]> git.donarmstrong.com Git - roundcube.git/blob - program/js/tiny_mce/tiny_mce_src.js
Imported Upstream version 0.3
[roundcube.git] / program / js / tiny_mce / tiny_mce_src.js
1 var tinymce = {\r
2         majorVersion : '3',\r
3         minorVersion : '2.3',\r
4         releaseDate : '2009-04-23',\r
5 \r
6         _init : function() {\r
7                 var t = this, d = document, w = window, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;\r
8 \r
9                 // Browser checks\r
10                 t.isOpera = w.opera && opera.buildNumber;\r
11                 t.isWebKit = /WebKit/.test(ua);\r
12                 t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName);\r
13                 t.isIE6 = t.isIE && /MSIE [56]/.test(ua);\r
14                 t.isGecko = !t.isWebKit && /Gecko/.test(ua);\r
15                 t.isMac = ua.indexOf('Mac') != -1;\r
16                 t.isAir = /adobeair/i.test(ua);\r
17 \r
18                 // TinyMCE .NET webcontrol might be setting the values for TinyMCE\r
19                 if (w.tinyMCEPreInit) {\r
20                         t.suffix = tinyMCEPreInit.suffix;\r
21                         t.baseURL = tinyMCEPreInit.base;\r
22                         t.query = tinyMCEPreInit.query;\r
23                         return;\r
24                 }\r
25 \r
26                 // Get suffix and base\r
27                 t.suffix = '';\r
28 \r
29                 // If base element found, add that infront of baseURL\r
30                 nl = d.getElementsByTagName('base');\r
31                 for (i=0; i<nl.length; i++) {\r
32                         if (v = nl[i].href) {\r
33                                 // Host only value like http://site.com or http://site.com:8008\r
34                                 if (/^https?:\/\/[^\/]+$/.test(v))\r
35                                         v += '/';\r
36 \r
37                                 base = v ? v.match(/.*\//)[0] : ''; // Get only directory\r
38                         }\r
39                 }\r
40 \r
41                 function getBase(n) {\r
42                         if (n.src && /tiny_mce(|_dev|_src|_gzip|_jquery|_prototype).js/.test(n.src)) {\r
43                                 if (/_(src|dev)\.js/g.test(n.src))\r
44                                         t.suffix = '_src';\r
45 \r
46                                 if ((p = n.src.indexOf('?')) != -1)\r
47                                         t.query = n.src.substring(p + 1);\r
48 \r
49                                 t.baseURL = n.src.substring(0, n.src.lastIndexOf('/'));\r
50 \r
51                                 // If path to script is relative and a base href was found add that one infront\r
52                                 if (base && t.baseURL.indexOf('://') == -1)\r
53                                         t.baseURL = base + t.baseURL;\r
54 \r
55                                 return t.baseURL;\r
56                         }\r
57 \r
58                         return null;\r
59                 };\r
60 \r
61                 // Check document\r
62                 nl = d.getElementsByTagName('script');\r
63                 for (i=0; i<nl.length; i++) {\r
64                         if (getBase(nl[i]))\r
65                                 return;\r
66                 }\r
67 \r
68                 // Check head\r
69                 n = d.getElementsByTagName('head')[0];\r
70                 if (n) {\r
71                         nl = n.getElementsByTagName('script');\r
72                         for (i=0; i<nl.length; i++) {\r
73                                 if (getBase(nl[i]))\r
74                                         return;\r
75                         }\r
76                 }\r
77 \r
78                 return;\r
79         },\r
80 \r
81         is : function(o, t) {\r
82                 var n = typeof(o);\r
83 \r
84                 if (!t)\r
85                         return n != 'undefined';\r
86 \r
87                 if (t == 'array' && (o.hasOwnProperty && o instanceof Array))\r
88                         return true;\r
89 \r
90                 return n == t;\r
91         },\r
92 \r
93 \r
94         each : function(o, cb, s) {\r
95                 var n, l;\r
96 \r
97                 if (!o)\r
98                         return 0;\r
99 \r
100                 s = s || o;\r
101 \r
102                 if (typeof(o.length) != 'undefined') {\r
103                         // Indexed arrays, needed for Safari\r
104                         for (n=0, l = o.length; n<l; n++) {\r
105                                 if (cb.call(s, o[n], n, o) === false)\r
106                                         return 0;\r
107                         }\r
108                 } else {\r
109                         // Hashtables\r
110                         for (n in o) {\r
111                                 if (o.hasOwnProperty(n)) {\r
112                                         if (cb.call(s, o[n], n, o) === false)\r
113                                                 return 0;\r
114                                 }\r
115                         }\r
116                 }\r
117 \r
118                 return 1;\r
119         },\r
120 \r
121         map : function(a, f) {\r
122                 var o = [];\r
123 \r
124                 tinymce.each(a, function(v) {\r
125                         o.push(f(v));\r
126                 });\r
127 \r
128                 return o;\r
129         },\r
130 \r
131         grep : function(a, f) {\r
132                 var o = [];\r
133 \r
134                 tinymce.each(a, function(v) {\r
135                         if (!f || f(v))\r
136                                 o.push(v);\r
137                 });\r
138 \r
139                 return o;\r
140         },\r
141 \r
142         inArray : function(a, v) {\r
143                 var i, l;\r
144 \r
145                 if (a) {\r
146                         for (i = 0, l = a.length; i < l; i++) {\r
147                                 if (a[i] === v)\r
148                                         return i;\r
149                         }\r
150                 }\r
151 \r
152                 return -1;\r
153         },\r
154 \r
155         extend : function(o, e) {\r
156                 var i, a = arguments;\r
157 \r
158                 for (i=1; i<a.length; i++) {\r
159                         e = a[i];\r
160 \r
161                         tinymce.each(e, function(v, n) {\r
162                                 if (typeof(v) !== 'undefined')\r
163                                         o[n] = v;\r
164                         });\r
165                 }\r
166 \r
167                 return o;\r
168         },\r
169 \r
170         trim : function(s) {\r
171                 return (s ? '' + s : '').replace(/^\s*|\s*$/g, '');\r
172         },\r
173 \r
174 \r
175         create : function(s, p) {\r
176                 var t = this, sp, ns, cn, scn, c, de = 0;\r
177 \r
178                 // Parse : <prefix> <class>:<super class>\r
179                 s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);\r
180                 cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name\r
181 \r
182                 // Create namespace for new class\r
183                 ns = t.createNS(s[3].replace(/\.\w+$/, ''));\r
184 \r
185                 // Class already exists\r
186                 if (ns[cn])\r
187                         return;\r
188 \r
189                 // Make pure static class\r
190                 if (s[2] == 'static') {\r
191                         ns[cn] = p;\r
192 \r
193                         if (this.onCreate)\r
194                                 this.onCreate(s[2], s[3], ns[cn]);\r
195 \r
196                         return;\r
197                 }\r
198 \r
199                 // Create default constructor\r
200                 if (!p[cn]) {\r
201                         p[cn] = function() {};\r
202                         de = 1;\r
203                 }\r
204 \r
205                 // Add constructor and methods\r
206                 ns[cn] = p[cn];\r
207                 t.extend(ns[cn].prototype, p);\r
208 \r
209                 // Extend\r
210                 if (s[5]) {\r
211                         sp = t.resolve(s[5]).prototype;\r
212                         scn = s[5].match(/\.(\w+)$/i)[1]; // Class name\r
213 \r
214                         // Extend constructor\r
215                         c = ns[cn];\r
216                         if (de) {\r
217                                 // Add passthrough constructor\r
218                                 ns[cn] = function() {\r
219                                         return sp[scn].apply(this, arguments);\r
220                                 };\r
221                         } else {\r
222                                 // Add inherit constructor\r
223                                 ns[cn] = function() {\r
224                                         this.parent = sp[scn];\r
225                                         return c.apply(this, arguments);\r
226                                 };\r
227                         }\r
228                         ns[cn].prototype[cn] = ns[cn];\r
229 \r
230                         // Add super methods\r
231                         t.each(sp, function(f, n) {\r
232                                 ns[cn].prototype[n] = sp[n];\r
233                         });\r
234 \r
235                         // Add overridden methods\r
236                         t.each(p, function(f, n) {\r
237                                 // Extend methods if needed\r
238                                 if (sp[n]) {\r
239                                         ns[cn].prototype[n] = function() {\r
240                                                 this.parent = sp[n];\r
241                                                 return f.apply(this, arguments);\r
242                                         };\r
243                                 } else {\r
244                                         if (n != cn)\r
245                                                 ns[cn].prototype[n] = f;\r
246                                 }\r
247                         });\r
248                 }\r
249 \r
250                 // Add static methods\r
251                 t.each(p['static'], function(f, n) {\r
252                         ns[cn][n] = f;\r
253                 });\r
254 \r
255                 if (this.onCreate)\r
256                         this.onCreate(s[2], s[3], ns[cn].prototype);\r
257         },\r
258 \r
259         walk : function(o, f, n, s) {\r
260                 s = s || this;\r
261 \r
262                 if (o) {\r
263                         if (n)\r
264                                 o = o[n];\r
265 \r
266                         tinymce.each(o, function(o, i) {\r
267                                 if (f.call(s, o, i, n) === false)\r
268                                         return false;\r
269 \r
270                                 tinymce.walk(o, f, n, s);\r
271                         });\r
272                 }\r
273         },\r
274 \r
275         createNS : function(n, o) {\r
276                 var i, v;\r
277 \r
278                 o = o || window;\r
279 \r
280                 n = n.split('.');\r
281                 for (i=0; i<n.length; i++) {\r
282                         v = n[i];\r
283 \r
284                         if (!o[v])\r
285                                 o[v] = {};\r
286 \r
287                         o = o[v];\r
288                 }\r
289 \r
290                 return o;\r
291         },\r
292 \r
293         resolve : function(n, o) {\r
294                 var i, l;\r
295 \r
296                 o = o || window;\r
297 \r
298                 n = n.split('.');\r
299                 for (i=0, l = n.length; i<l; i++) {\r
300                         o = o[n[i]];\r
301 \r
302                         if (!o)\r
303                                 break;\r
304                 }\r
305 \r
306                 return o;\r
307         },\r
308 \r
309         addUnload : function(f, s) {\r
310                 var t = this, w = window;\r
311 \r
312                 f = {func : f, scope : s || this};\r
313 \r
314                 if (!t.unloads) {\r
315                         function unload() {\r
316                                 var li = t.unloads, o, n;\r
317 \r
318                                 if (li) {\r
319                                         // Call unload handlers\r
320                                         for (n in li) {\r
321                                                 o = li[n];\r
322 \r
323                                                 if (o && o.func)\r
324                                                         o.func.call(o.scope, 1); // Send in one arg to distinct unload and user destroy\r
325                                         }\r
326 \r
327                                         // Detach unload function\r
328                                         if (w.detachEvent) {\r
329                                                 w.detachEvent('onbeforeunload', fakeUnload);\r
330                                                 w.detachEvent('onunload', unload);\r
331                                         } else if (w.removeEventListener)\r
332                                                 w.removeEventListener('unload', unload, false);\r
333 \r
334                                         // Destroy references\r
335                                         t.unloads = o = li = w = unload = 0;\r
336 \r
337                                         // Run garbarge collector on IE\r
338                                         if (window.CollectGarbage)\r
339                                                 window.CollectGarbage();\r
340                                 }\r
341                         };\r
342 \r
343                         function fakeUnload() {\r
344                                 var d = document;\r
345 \r
346                                 // Is there things still loading, then do some magic\r
347                                 if (d.readyState == 'interactive') {\r
348                                         function stop() {\r
349                                                 // Prevent memory leak\r
350                                                 d.detachEvent('onstop', stop);\r
351 \r
352                                                 // Call unload handler\r
353                                                 if (unload)\r
354                                                         unload();\r
355 \r
356                                                 d = 0;\r
357                                         };\r
358 \r
359                                         // Fire unload when the currently loading page is stopped\r
360                                         if (d)\r
361                                                 d.attachEvent('onstop', stop);\r
362 \r
363                                         // Remove onstop listener after a while to prevent the unload function\r
364                                         // to execute if the user presses cancel in an onbeforeunload\r
365                                         // confirm dialog and then presses the browser stop button\r
366                                         window.setTimeout(function() {\r
367                                                 if (d)\r
368                                                         d.detachEvent('onstop', stop);\r
369                                         }, 0);\r
370                                 }\r
371                         };\r
372 \r
373                         // Attach unload handler\r
374                         if (w.attachEvent) {\r
375                                 w.attachEvent('onunload', unload);\r
376                                 w.attachEvent('onbeforeunload', fakeUnload);\r
377                         } else if (w.addEventListener)\r
378                                 w.addEventListener('unload', unload, false);\r
379 \r
380                         // Setup initial unload handler array\r
381                         t.unloads = [f];\r
382                 } else\r
383                         t.unloads.push(f);\r
384 \r
385                 return f;\r
386         },\r
387 \r
388         removeUnload : function(f) {\r
389                 var u = this.unloads, r = null;\r
390 \r
391                 tinymce.each(u, function(o, i) {\r
392                         if (o && o.func == f) {\r
393                                 u.splice(i, 1);\r
394                                 r = f;\r
395                                 return false;\r
396                         }\r
397                 });\r
398 \r
399                 return r;\r
400         },\r
401 \r
402         explode : function(s, d) {\r
403                 return s ? tinymce.map(s.split(d || ','), tinymce.trim) : s;\r
404         },\r
405 \r
406         _addVer : function(u) {\r
407                 var v;\r
408 \r
409                 if (!this.query)\r
410                         return u;\r
411 \r
412                 v = (u.indexOf('?') == -1 ? '?' : '&') + this.query;\r
413 \r
414                 if (u.indexOf('#') == -1)\r
415                         return u + v;\r
416 \r
417                 return u.replace('#', v + '#');\r
418         }\r
419 \r
420         };\r
421 \r
422 // Required for GZip AJAX loading\r
423 window.tinymce = tinymce;\r
424 \r
425 // Initialize the API\r
426 tinymce._init();\r
427 tinymce.create('tinymce.util.Dispatcher', {\r
428         scope : null,\r
429         listeners : null,\r
430 \r
431         Dispatcher : function(s) {\r
432                 this.scope = s || this;\r
433                 this.listeners = [];\r
434         },\r
435 \r
436         add : function(cb, s) {\r
437                 this.listeners.push({cb : cb, scope : s || this.scope});\r
438 \r
439                 return cb;\r
440         },\r
441 \r
442         addToTop : function(cb, s) {\r
443                 this.listeners.unshift({cb : cb, scope : s || this.scope});\r
444 \r
445                 return cb;\r
446         },\r
447 \r
448         remove : function(cb) {\r
449                 var l = this.listeners, o = null;\r
450 \r
451                 tinymce.each(l, function(c, i) {\r
452                         if (cb == c.cb) {\r
453                                 o = cb;\r
454                                 l.splice(i, 1);\r
455                                 return false;\r
456                         }\r
457                 });\r
458 \r
459                 return o;\r
460         },\r
461 \r
462         dispatch : function() {\r
463                 var s, a = arguments, i, li = this.listeners, c;\r
464 \r
465                 // Needs to be a real loop since the listener count might change while looping\r
466                 // And this is also more efficient\r
467                 for (i = 0; i<li.length; i++) {\r
468                         c = li[i];\r
469                         s = c.cb.apply(c.scope, a);\r
470 \r
471                         if (s === false)\r
472                                 break;\r
473                 }\r
474 \r
475                 return s;\r
476         }\r
477 \r
478         });\r
479 (function() {\r
480         var each = tinymce.each;\r
481 \r
482         tinymce.create('tinymce.util.URI', {\r
483                 URI : function(u, s) {\r
484                         var t = this, o, a, b;\r
485 \r
486                         // Default settings\r
487                         s = t.settings = s || {};\r
488 \r
489                         // Strange app protocol or local anchor\r
490                         if (/^(mailto|tel|news|javascript|about):/i.test(u) || /^\s*#/.test(u)) {\r
491                                 t.source = u;\r
492                                 return;\r
493                         }\r
494 \r
495                         // Absolute path with no host, fake host and protocol\r
496                         if (u.indexOf('/') === 0 && u.indexOf('//') !== 0)\r
497                                 u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u;\r
498 \r
499                         // Relative path\r
500                         if (u.indexOf(':/') === -1 && u.indexOf('//') !== 0)\r
501                                 u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u);\r
502 \r
503                         // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)\r
504                         u = u.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something\r
505                         u = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(u);\r
506                         each(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], function(v, i) {\r
507                                 var s = u[i];\r
508 \r
509                                 // Zope 3 workaround, they use @@something\r
510                                 if (s)\r
511                                         s = s.replace(/\(mce_at\)/g, '@@');\r
512 \r
513                                 t[v] = s;\r
514                         });\r
515 \r
516                         if (b = s.base_uri) {\r
517                                 if (!t.protocol)\r
518                                         t.protocol = b.protocol;\r
519 \r
520                                 if (!t.userInfo)\r
521                                         t.userInfo = b.userInfo;\r
522 \r
523                                 if (!t.port && t.host == 'mce_host')\r
524                                         t.port = b.port;\r
525 \r
526                                 if (!t.host || t.host == 'mce_host')\r
527                                         t.host = b.host;\r
528 \r
529                                 t.source = '';\r
530                         }\r
531 \r
532                         //t.path = t.path || '/';\r
533                 },\r
534 \r
535                 setPath : function(p) {\r
536                         var t = this;\r
537 \r
538                         p = /^(.*?)\/?(\w+)?$/.exec(p);\r
539 \r
540                         // Update path parts\r
541                         t.path = p[0];\r
542                         t.directory = p[1];\r
543                         t.file = p[2];\r
544 \r
545                         // Rebuild source\r
546                         t.source = '';\r
547                         t.getURI();\r
548                 },\r
549 \r
550                 toRelative : function(u) {\r
551                         var t = this, o;\r
552 \r
553                         if (u === "./")\r
554                                 return u;\r
555 \r
556                         u = new tinymce.util.URI(u, {base_uri : t});\r
557 \r
558                         // Not on same domain/port or protocol\r
559                         if ((u.host != 'mce_host' && t.host != u.host && u.host) || t.port != u.port || t.protocol != u.protocol)\r
560                                 return u.getURI();\r
561 \r
562                         o = t.toRelPath(t.path, u.path);\r
563 \r
564                         // Add query\r
565                         if (u.query)\r
566                                 o += '?' + u.query;\r
567 \r
568                         // Add anchor\r
569                         if (u.anchor)\r
570                                 o += '#' + u.anchor;\r
571 \r
572                         return o;\r
573                 },\r
574         \r
575                 toAbsolute : function(u, nh) {\r
576                         var u = new tinymce.util.URI(u, {base_uri : this});\r
577 \r
578                         return u.getURI(this.host == u.host ? nh : 0);\r
579                 },\r
580 \r
581                 toRelPath : function(base, path) {\r
582                         var items, bp = 0, out = '', i, l;\r
583 \r
584                         // Split the paths\r
585                         base = base.substring(0, base.lastIndexOf('/'));\r
586                         base = base.split('/');\r
587                         items = path.split('/');\r
588 \r
589                         if (base.length >= items.length) {\r
590                                 for (i = 0, l = base.length; i < l; i++) {\r
591                                         if (i >= items.length || base[i] != items[i]) {\r
592                                                 bp = i + 1;\r
593                                                 break;\r
594                                         }\r
595                                 }\r
596                         }\r
597 \r
598                         if (base.length < items.length) {\r
599                                 for (i = 0, l = items.length; i < l; i++) {\r
600                                         if (i >= base.length || base[i] != items[i]) {\r
601                                                 bp = i + 1;\r
602                                                 break;\r
603                                         }\r
604                                 }\r
605                         }\r
606 \r
607                         if (bp == 1)\r
608                                 return path;\r
609 \r
610                         for (i = 0, l = base.length - (bp - 1); i < l; i++)\r
611                                 out += "../";\r
612 \r
613                         for (i = bp - 1, l = items.length; i < l; i++) {\r
614                                 if (i != bp - 1)\r
615                                         out += "/" + items[i];\r
616                                 else\r
617                                         out += items[i];\r
618                         }\r
619 \r
620                         return out;\r
621                 },\r
622 \r
623                 toAbsPath : function(base, path) {\r
624                         var i, nb = 0, o = [], tr;\r
625 \r
626                         // Split paths\r
627                         tr = /\/$/.test(path) ? '/' : '';\r
628                         base = base.split('/');\r
629                         path = path.split('/');\r
630 \r
631                         // Remove empty chunks\r
632                         each(base, function(k) {\r
633                                 if (k)\r
634                                         o.push(k);\r
635                         });\r
636 \r
637                         base = o;\r
638 \r
639                         // Merge relURLParts chunks\r
640                         for (i = path.length - 1, o = []; i >= 0; i--) {\r
641                                 // Ignore empty or .\r
642                                 if (path[i].length == 0 || path[i] == ".")\r
643                                         continue;\r
644 \r
645                                 // Is parent\r
646                                 if (path[i] == '..') {\r
647                                         nb++;\r
648                                         continue;\r
649                                 }\r
650 \r
651                                 // Move up\r
652                                 if (nb > 0) {\r
653                                         nb--;\r
654                                         continue;\r
655                                 }\r
656 \r
657                                 o.push(path[i]);\r
658                         }\r
659 \r
660                         i = base.length - nb;\r
661 \r
662                         // If /a/b/c or /\r
663                         if (i <= 0)\r
664                                 return '/' + o.reverse().join('/') + tr;\r
665 \r
666                         return '/' + base.slice(0, i).join('/') + '/' + o.reverse().join('/') + tr;\r
667                 },\r
668 \r
669                 getURI : function(nh) {\r
670                         var s, t = this;\r
671 \r
672                         // Rebuild source\r
673                         if (!t.source || nh) {\r
674                                 s = '';\r
675 \r
676                                 if (!nh) {\r
677                                         if (t.protocol)\r
678                                                 s += t.protocol + '://';\r
679 \r
680                                         if (t.userInfo)\r
681                                                 s += t.userInfo + '@';\r
682 \r
683                                         if (t.host)\r
684                                                 s += t.host;\r
685 \r
686                                         if (t.port)\r
687                                                 s += ':' + t.port;\r
688                                 }\r
689 \r
690                                 if (t.path)\r
691                                         s += t.path;\r
692 \r
693                                 if (t.query)\r
694                                         s += '?' + t.query;\r
695 \r
696                                 if (t.anchor)\r
697                                         s += '#' + t.anchor;\r
698 \r
699                                 t.source = s;\r
700                         }\r
701 \r
702                         return t.source;\r
703                 }\r
704 \r
705                 });\r
706 })();\r
707 (function() {\r
708         var each = tinymce.each;\r
709 \r
710         tinymce.create('static tinymce.util.Cookie', {\r
711                 getHash : function(n) {\r
712                         var v = this.get(n), h;\r
713 \r
714                         if (v) {\r
715                                 each(v.split('&'), function(v) {\r
716                                         v = v.split('=');\r
717                                         h = h || {};\r
718                                         h[unescape(v[0])] = unescape(v[1]);\r
719                                 });\r
720                         }\r
721 \r
722                         return h;\r
723                 },\r
724 \r
725                 setHash : function(n, v, e, p, d, s) {\r
726                         var o = '';\r
727 \r
728                         each(v, function(v, k) {\r
729                                 o += (!o ? '' : '&') + escape(k) + '=' + escape(v);\r
730                         });\r
731 \r
732                         this.set(n, o, e, p, d, s);\r
733                 },\r
734 \r
735                 get : function(n) {\r
736                         var c = document.cookie, e, p = n + "=", b;\r
737 \r
738                         // Strict mode\r
739                         if (!c)\r
740                                 return;\r
741 \r
742                         b = c.indexOf("; " + p);\r
743 \r
744                         if (b == -1) {\r
745                                 b = c.indexOf(p);\r
746 \r
747                                 if (b != 0)\r
748                                         return null;\r
749                         } else\r
750                                 b += 2;\r
751 \r
752                         e = c.indexOf(";", b);\r
753 \r
754                         if (e == -1)\r
755                                 e = c.length;\r
756 \r
757                         return unescape(c.substring(b + p.length, e));\r
758                 },\r
759 \r
760                 set : function(n, v, e, p, d, s) {\r
761                         document.cookie = n + "=" + escape(v) +\r
762                                 ((e) ? "; expires=" + e.toGMTString() : "") +\r
763                                 ((p) ? "; path=" + escape(p) : "") +\r
764                                 ((d) ? "; domain=" + d : "") +\r
765                                 ((s) ? "; secure" : "");\r
766                 },\r
767 \r
768                 remove : function(n, p) {\r
769                         var d = new Date();\r
770 \r
771                         d.setTime(d.getTime() - 1000);\r
772 \r
773                         this.set(n, '', d, p, d);\r
774                 }\r
775 \r
776                 });\r
777 })();\r
778 tinymce.create('static tinymce.util.JSON', {\r
779         serialize : function(o) {\r
780                 var i, v, s = tinymce.util.JSON.serialize, t;\r
781 \r
782                 if (o == null)\r
783                         return 'null';\r
784 \r
785                 t = typeof o;\r
786 \r
787                 if (t == 'string') {\r
788                         v = '\bb\tt\nn\ff\rr\""\'\'\\\\';\r
789 \r
790                         return '"' + o.replace(/([\u0080-\uFFFF\x00-\x1f\"])/g, function(a, b) {\r
791                                 i = v.indexOf(b);\r
792 \r
793                                 if (i + 1)\r
794                                         return '\\' + v.charAt(i + 1);\r
795 \r
796                                 a = b.charCodeAt().toString(16);\r
797 \r
798                                 return '\\u' + '0000'.substring(a.length) + a;\r
799                         }) + '"';\r
800                 }\r
801 \r
802                 if (t == 'object') {\r
803                         if (o.hasOwnProperty && o instanceof Array) {\r
804                                         for (i=0, v = '['; i<o.length; i++)\r
805                                                 v += (i > 0 ? ',' : '') + s(o[i]);\r
806 \r
807                                         return v + ']';\r
808                                 }\r
809 \r
810                                 v = '{';\r
811 \r
812                                 for (i in o)\r
813                                         v += typeof o[i] != 'function' ? (v.length > 1 ? ',"' : '"') + i + '":' + s(o[i]) : '';\r
814 \r
815                                 return v + '}';\r
816                 }\r
817 \r
818                 return '' + o;\r
819         },\r
820 \r
821         parse : function(s) {\r
822                 try {\r
823                         return eval('(' + s + ')');\r
824                 } catch (ex) {\r
825                         // Ignore\r
826                 }\r
827         }\r
828 \r
829         });\r
830 tinymce.create('static tinymce.util.XHR', {\r
831         send : function(o) {\r
832                 var x, t, w = window, c = 0;\r
833 \r
834                 // Default settings\r
835                 o.scope = o.scope || this;\r
836                 o.success_scope = o.success_scope || o.scope;\r
837                 o.error_scope = o.error_scope || o.scope;\r
838                 o.async = o.async === false ? false : true;\r
839                 o.data = o.data || '';\r
840 \r
841                 function get(s) {\r
842                         x = 0;\r
843 \r
844                         try {\r
845                                 x = new ActiveXObject(s);\r
846                         } catch (ex) {\r
847                         }\r
848 \r
849                         return x;\r
850                 };\r
851 \r
852                 x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP');\r
853 \r
854                 if (x) {\r
855                         if (x.overrideMimeType)\r
856                                 x.overrideMimeType(o.content_type);\r
857 \r
858                         x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async);\r
859 \r
860                         if (o.content_type)\r
861                                 x.setRequestHeader('Content-Type', o.content_type);\r
862 \r
863                         x.send(o.data);\r
864 \r
865                         function ready() {\r
866                                 if (!o.async || x.readyState == 4 || c++ > 10000) {\r
867                                         if (o.success && c < 10000 && x.status == 200)\r
868                                                 o.success.call(o.success_scope, '' + x.responseText, x, o);\r
869                                         else if (o.error)\r
870                                                 o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o);\r
871 \r
872                                         x = null;\r
873                                 } else\r
874                                         w.setTimeout(ready, 10);\r
875                         };\r
876 \r
877                         // Syncronous request\r
878                         if (!o.async)\r
879                                 return ready();\r
880 \r
881                         // Wait for response, onReadyStateChange can not be used since it leaks memory in IE\r
882                         t = w.setTimeout(ready, 10);\r
883                 }\r
884 \r
885                 }\r
886 });\r
887 (function() {\r
888         var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR;\r
889 \r
890         tinymce.create('tinymce.util.JSONRequest', {\r
891                 JSONRequest : function(s) {\r
892                         this.settings = extend({\r
893                         }, s);\r
894                         this.count = 0;\r
895                 },\r
896 \r
897                 send : function(o) {\r
898                         var ecb = o.error, scb = o.success;\r
899 \r
900                         o = extend(this.settings, o);\r
901 \r
902                         o.success = function(c, x) {\r
903                                 c = JSON.parse(c);\r
904 \r
905                                 if (typeof(c) == 'undefined') {\r
906                                         c = {\r
907                                                 error : 'JSON Parse error.'\r
908                                         };\r
909                                 }\r
910 \r
911                                 if (c.error)\r
912                                         ecb.call(o.error_scope || o.scope, c.error, x);\r
913                                 else\r
914                                         scb.call(o.success_scope || o.scope, c.result);\r
915                         };\r
916 \r
917                         o.error = function(ty, x) {\r
918                                 ecb.call(o.error_scope || o.scope, ty, x);\r
919                         };\r
920 \r
921                         o.data = JSON.serialize({\r
922                                 id : o.id || 'c' + (this.count++),\r
923                                 method : o.method,\r
924                                 params : o.params\r
925                         });\r
926 \r
927                         // JSON content type for Ruby on rails. Bug: #1883287\r
928                         o.content_type = 'application/json';\r
929 \r
930                         XHR.send(o);\r
931                 },\r
932 \r
933                 'static' : {\r
934                         sendRPC : function(o) {\r
935                                 return new tinymce.util.JSONRequest().send(o);\r
936                         }\r
937                 }\r
938 \r
939                 });\r
940 }());(function(tinymce) {\r
941         // Shorten names\r
942         var each = tinymce.each, is = tinymce.is;\r
943         var isWebKit = tinymce.isWebKit, isIE = tinymce.isIE;\r
944 \r
945         tinymce.create('tinymce.dom.DOMUtils', {\r
946                 doc : null,\r
947                 root : null,\r
948                 files : null,\r
949                 pixelStyles : /^(top|left|bottom|right|width|height|borderWidth)$/,\r
950                 props : {\r
951                         "for" : "htmlFor",\r
952                         "class" : "className",\r
953                         className : "className",\r
954                         checked : "checked",\r
955                         disabled : "disabled",\r
956                         maxlength : "maxLength",\r
957                         readonly : "readOnly",\r
958                         selected : "selected",\r
959                         value : "value",\r
960                         id : "id",\r
961                         name : "name",\r
962                         type : "type"\r
963                 },\r
964 \r
965                 DOMUtils : function(d, s) {\r
966                         var t = this;\r
967 \r
968                         t.doc = d;\r
969                         t.win = window;\r
970                         t.files = {};\r
971                         t.cssFlicker = false;\r
972                         t.counter = 0;\r
973                         t.boxModel = !tinymce.isIE || d.compatMode == "CSS1Compat"; \r
974                         t.stdMode = d.documentMode === 8;\r
975 \r
976                         this.settings = s = tinymce.extend({\r
977                                 keep_values : false,\r
978                                 hex_colors : 1,\r
979                                 process_html : 1\r
980                         }, s);\r
981 \r
982                         // Fix IE6SP2 flicker and check it failed for pre SP2\r
983                         if (tinymce.isIE6) {\r
984                                 try {\r
985                                         d.execCommand('BackgroundImageCache', false, true);\r
986                                 } catch (e) {\r
987                                         t.cssFlicker = true;\r
988                                 }\r
989                         }\r
990 \r
991                         tinymce.addUnload(t.destroy, t);\r
992                 },\r
993 \r
994                 getRoot : function() {\r
995                         var t = this, s = t.settings;\r
996 \r
997                         return (s && t.get(s.root_element)) || t.doc.body;\r
998                 },\r
999 \r
1000                 getViewPort : function(w) {\r
1001                         var d, b;\r
1002 \r
1003                         w = !w ? this.win : w;\r
1004                         d = w.document;\r
1005                         b = this.boxModel ? d.documentElement : d.body;\r
1006 \r
1007                         // Returns viewport size excluding scrollbars\r
1008                         return {\r
1009                                 x : w.pageXOffset || b.scrollLeft,\r
1010                                 y : w.pageYOffset || b.scrollTop,\r
1011                                 w : w.innerWidth || b.clientWidth,\r
1012                                 h : w.innerHeight || b.clientHeight\r
1013                         };\r
1014                 },\r
1015 \r
1016                 getRect : function(e) {\r
1017                         var p, t = this, sr;\r
1018 \r
1019                         e = t.get(e);\r
1020                         p = t.getPos(e);\r
1021                         sr = t.getSize(e);\r
1022 \r
1023                         return {\r
1024                                 x : p.x,\r
1025                                 y : p.y,\r
1026                                 w : sr.w,\r
1027                                 h : sr.h\r
1028                         };\r
1029                 },\r
1030 \r
1031                 getSize : function(e) {\r
1032                         var t = this, w, h;\r
1033 \r
1034                         e = t.get(e);\r
1035                         w = t.getStyle(e, 'width');\r
1036                         h = t.getStyle(e, 'height');\r
1037 \r
1038                         // Non pixel value, then force offset/clientWidth\r
1039                         if (w.indexOf('px') === -1)\r
1040                                 w = 0;\r
1041 \r
1042                         // Non pixel value, then force offset/clientWidth\r
1043                         if (h.indexOf('px') === -1)\r
1044                                 h = 0;\r
1045 \r
1046                         return {\r
1047                                 w : parseInt(w) || e.offsetWidth || e.clientWidth,\r
1048                                 h : parseInt(h) || e.offsetHeight || e.clientHeight\r
1049                         };\r
1050                 },\r
1051 \r
1052                 is : function(n, patt) {\r
1053                         return tinymce.dom.Sizzle.matches(patt, n.nodeType ? [n] : n).length > 0;\r
1054                 },\r
1055 \r
1056                 getParent : function(n, f, r) {\r
1057                         return this.getParents(n, f, r, false);\r
1058                 },\r
1059 \r
1060                 getParents : function(n, f, r, c) {\r
1061                         var t = this, na, se = t.settings, o = [];\r
1062 \r
1063                         n = t.get(n);\r
1064                         c = c === undefined;\r
1065 \r
1066                         if (se.strict_root)\r
1067                                 r = r || t.getRoot();\r
1068 \r
1069                         // Wrap node name as func\r
1070                         if (is(f, 'string')) {\r
1071                                 na = f;\r
1072 \r
1073                                 if (f === '*') {\r
1074                                         f = function(n) {return n.nodeType == 1;};\r
1075                                 } else {\r
1076                                         f = function(n) {\r
1077                                                 return t.is(n, na);\r
1078                                         };\r
1079                                 }\r
1080                         }\r
1081 \r
1082                         while (n) {\r
1083                                 if (n == r || !n.nodeType || n.nodeType === 9)\r
1084                                         break;\r
1085 \r
1086                                 if (!f || f(n)) {\r
1087                                         if (c)\r
1088                                                 o.push(n);\r
1089                                         else\r
1090                                                 return n;\r
1091                                 }\r
1092 \r
1093                                 n = n.parentNode;\r
1094                         }\r
1095 \r
1096                         return c ? o : null;\r
1097                 },\r
1098 \r
1099                 get : function(e) {\r
1100                         var n;\r
1101 \r
1102                         if (e && this.doc && typeof(e) == 'string') {\r
1103                                 n = e;\r
1104                                 e = this.doc.getElementById(e);\r
1105 \r
1106                                 // IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick\r
1107                                 if (e && e.id !== n)\r
1108                                         return this.doc.getElementsByName(n)[1];\r
1109                         }\r
1110 \r
1111                         return e;\r
1112                 },\r
1113 \r
1114 \r
1115                 select : function(pa, s) {\r
1116                         var t = this;\r
1117 \r
1118                         return tinymce.dom.Sizzle(pa, t.get(s) || t.get(t.settings.root_element) || t.doc, []);\r
1119                 },\r
1120 \r
1121 \r
1122                 add : function(p, n, a, h, c) {\r
1123                         var t = this;\r
1124 \r
1125                         return this.run(p, function(p) {\r
1126                                 var e, k;\r
1127 \r
1128                                 e = is(n, 'string') ? t.doc.createElement(n) : n;\r
1129                                 t.setAttribs(e, a);\r
1130 \r
1131                                 if (h) {\r
1132                                         if (h.nodeType)\r
1133                                                 e.appendChild(h);\r
1134                                         else\r
1135                                                 t.setHTML(e, h);\r
1136                                 }\r
1137 \r
1138                                 return !c ? p.appendChild(e) : e;\r
1139                         });\r
1140                 },\r
1141 \r
1142                 create : function(n, a, h) {\r
1143                         return this.add(this.doc.createElement(n), n, a, h, 1);\r
1144                 },\r
1145 \r
1146                 createHTML : function(n, a, h) {\r
1147                         var o = '', t = this, k;\r
1148 \r
1149                         o += '<' + n;\r
1150 \r
1151                         for (k in a) {\r
1152                                 if (a.hasOwnProperty(k))\r
1153                                         o += ' ' + k + '="' + t.encode(a[k]) + '"';\r
1154                         }\r
1155 \r
1156                         if (tinymce.is(h))\r
1157                                 return o + '>' + h + '</' + n + '>';\r
1158 \r
1159                         return o + ' />';\r
1160                 },\r
1161 \r
1162                 remove : function(n, k) {\r
1163                         var t = this;\r
1164 \r
1165                         return this.run(n, function(n) {\r
1166                                 var p, g, i;\r
1167 \r
1168                                 p = n.parentNode;\r
1169 \r
1170                                 if (!p)\r
1171                                         return null;\r
1172 \r
1173                                 if (k) {\r
1174                                         for (i = n.childNodes.length - 1; i >= 0; i--)\r
1175                                                 t.insertAfter(n.childNodes[i], n);\r
1176 \r
1177                                         //each(n.childNodes, function(c) {\r
1178                                         //      p.insertBefore(c.cloneNode(true), n);\r
1179                                         //});\r
1180                                 }\r
1181 \r
1182                                 // Fix IE psuedo leak\r
1183                                 if (t.fixPsuedoLeaks) {\r
1184                                         p = n.cloneNode(true);\r
1185                                         k = 'IELeakGarbageBin';\r
1186                                         g = t.get(k) || t.add(t.doc.body, 'div', {id : k, style : 'display:none'});\r
1187                                         g.appendChild(n);\r
1188                                         g.innerHTML = '';\r
1189 \r
1190                                         return p;\r
1191                                 }\r
1192 \r
1193                                 return p.removeChild(n);\r
1194                         });\r
1195                 },\r
1196 \r
1197 \r
1198                 setStyle : function(n, na, v) {\r
1199                         var t = this;\r
1200 \r
1201                         return t.run(n, function(e) {\r
1202                                 var s, i;\r
1203 \r
1204                                 s = e.style;\r
1205 \r
1206                                 // Camelcase it, if needed\r
1207                                 na = na.replace(/-(\D)/g, function(a, b){\r
1208                                         return b.toUpperCase();\r
1209                                 });\r
1210 \r
1211                                 // Default px suffix on these\r
1212                                 if (t.pixelStyles.test(na) && (tinymce.is(v, 'number') || /^[\-0-9\.]+$/.test(v)))\r
1213                                         v += 'px';\r
1214 \r
1215                                 switch (na) {\r
1216                                         case 'opacity':\r
1217                                                 // IE specific opacity\r
1218                                                 if (isIE) {\r
1219                                                         s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")";\r
1220 \r
1221                                                         if (!n.currentStyle || !n.currentStyle.hasLayout)\r
1222                                                                 s.display = 'inline-block';\r
1223                                                 }\r
1224 \r
1225                                                 // Fix for older browsers\r
1226                                                 s[na] = s['-moz-opacity'] = s['-khtml-opacity'] = v || '';\r
1227                                                 break;\r
1228 \r
1229                                         case 'float':\r
1230                                                 isIE ? s.styleFloat = v : s.cssFloat = v;\r
1231                                                 break;\r
1232                                         \r
1233                                         default:\r
1234                                                 s[na] = v || '';\r
1235                                 }\r
1236 \r
1237                                 // Force update of the style data\r
1238                                 if (t.settings.update_styles)\r
1239                                         t.setAttrib(e, 'mce_style');\r
1240                         });\r
1241                 },\r
1242 \r
1243                 getStyle : function(n, na, c) {\r
1244                         n = this.get(n);\r
1245 \r
1246                         if (!n)\r
1247                                 return false;\r
1248 \r
1249                         // Gecko\r
1250                         if (this.doc.defaultView && c) {\r
1251                                 // Remove camelcase\r
1252                                 na = na.replace(/[A-Z]/g, function(a){\r
1253                                         return '-' + a;\r
1254                                 });\r
1255 \r
1256                                 try {\r
1257                                         return this.doc.defaultView.getComputedStyle(n, null).getPropertyValue(na);\r
1258                                 } catch (ex) {\r
1259                                         // Old safari might fail\r
1260                                         return null;\r
1261                                 }\r
1262                         }\r
1263 \r
1264                         // Camelcase it, if needed\r
1265                         na = na.replace(/-(\D)/g, function(a, b){\r
1266                                 return b.toUpperCase();\r
1267                         });\r
1268 \r
1269                         if (na == 'float')\r
1270                                 na = isIE ? 'styleFloat' : 'cssFloat';\r
1271 \r
1272                         // IE & Opera\r
1273                         if (n.currentStyle && c)\r
1274                                 return n.currentStyle[na];\r
1275 \r
1276                         return n.style[na];\r
1277                 },\r
1278 \r
1279                 setStyles : function(e, o) {\r
1280                         var t = this, s = t.settings, ol;\r
1281 \r
1282                         ol = s.update_styles;\r
1283                         s.update_styles = 0;\r
1284 \r
1285                         each(o, function(v, n) {\r
1286                                 t.setStyle(e, n, v);\r
1287                         });\r
1288 \r
1289                         // Update style info\r
1290                         s.update_styles = ol;\r
1291                         if (s.update_styles)\r
1292                                 t.setAttrib(e, s.cssText);\r
1293                 },\r
1294 \r
1295                 setAttrib : function(e, n, v) {\r
1296                         var t = this;\r
1297 \r
1298                         // Whats the point\r
1299                         if (!e || !n)\r
1300                                 return;\r
1301 \r
1302                         // Strict XML mode\r
1303                         if (t.settings.strict)\r
1304                                 n = n.toLowerCase();\r
1305 \r
1306                         return this.run(e, function(e) {\r
1307                                 var s = t.settings;\r
1308 \r
1309                                 switch (n) {\r
1310                                         case "style":\r
1311                                                 if (!is(v, 'string')) {\r
1312                                                         each(v, function(v, n) {\r
1313                                                                 t.setStyle(e, n, v);\r
1314                                                         });\r
1315 \r
1316                                                         return;\r
1317                                                 }\r
1318 \r
1319                                                 // No mce_style for elements with these since they might get resized by the user\r
1320                                                 if (s.keep_values) {\r
1321                                                         if (v && !t._isRes(v))\r
1322                                                                 e.setAttribute('mce_style', v, 2);\r
1323                                                         else\r
1324                                                                 e.removeAttribute('mce_style', 2);\r
1325                                                 }\r
1326 \r
1327                                                 e.style.cssText = v;\r
1328                                                 break;\r
1329 \r
1330                                         case "class":\r
1331                                                 e.className = v || ''; // Fix IE null bug\r
1332                                                 break;\r
1333 \r
1334                                         case "src":\r
1335                                         case "href":\r
1336                                                 if (s.keep_values) {\r
1337                                                         if (s.url_converter)\r
1338                                                                 v = s.url_converter.call(s.url_converter_scope || t, v, n, e);\r
1339 \r
1340                                                         t.setAttrib(e, 'mce_' + n, v, 2);\r
1341                                                 }\r
1342 \r
1343                                                 break;\r
1344                                         \r
1345                                         case "shape":\r
1346                                                 e.setAttribute('mce_style', v);\r
1347                                                 break;\r
1348                                 }\r
1349 \r
1350                                 if (is(v) && v !== null && v.length !== 0)\r
1351                                         e.setAttribute(n, '' + v, 2);\r
1352                                 else\r
1353                                         e.removeAttribute(n, 2);\r
1354                         });\r
1355                 },\r
1356 \r
1357                 setAttribs : function(e, o) {\r
1358                         var t = this;\r
1359 \r
1360                         return this.run(e, function(e) {\r
1361                                 each(o, function(v, n) {\r
1362                                         t.setAttrib(e, n, v);\r
1363                                 });\r
1364                         });\r
1365                 },\r
1366 \r
1367 \r
1368                 getAttrib : function(e, n, dv) {\r
1369                         var v, t = this;\r
1370 \r
1371                         e = t.get(e);\r
1372 \r
1373                         if (!e || e.nodeType !== 1)\r
1374                                 return false;\r
1375 \r
1376                         if (!is(dv))\r
1377                                 dv = '';\r
1378 \r
1379                         // Try the mce variant for these\r
1380                         if (/^(src|href|style|coords|shape)$/.test(n)) {\r
1381                                 v = e.getAttribute("mce_" + n);\r
1382 \r
1383                                 if (v)\r
1384                                         return v;\r
1385                         }\r
1386 \r
1387                         if (isIE && t.props[n]) {\r
1388                                 v = e[t.props[n]];\r
1389                                 v = v && v.nodeValue ? v.nodeValue : v;\r
1390                         }\r
1391 \r
1392                         if (!v)\r
1393                                 v = e.getAttribute(n, 2);\r
1394 \r
1395                         if (n === 'style') {\r
1396                                 v = v || e.style.cssText;\r
1397 \r
1398                                 if (v) {\r
1399                                         v = t.serializeStyle(t.parseStyle(v));\r
1400 \r
1401                                         if (t.settings.keep_values && !t._isRes(v))\r
1402                                                 e.setAttribute('mce_style', v);\r
1403                                 }\r
1404                         }\r
1405 \r
1406                         // Remove Apple and WebKit stuff\r
1407                         if (isWebKit && n === "class" && v)\r
1408                                 v = v.replace(/(apple|webkit)\-[a-z\-]+/gi, '');\r
1409 \r
1410                         // Handle IE issues\r
1411                         if (isIE) {\r
1412                                 switch (n) {\r
1413                                         case 'rowspan':\r
1414                                         case 'colspan':\r
1415                                                 // IE returns 1 as default value\r
1416                                                 if (v === 1)\r
1417                                                         v = '';\r
1418 \r
1419                                                 break;\r
1420 \r
1421                                         case 'size':\r
1422                                                 // IE returns +0 as default value for size\r
1423                                                 if (v === '+0' || v === 20 || v === 0)\r
1424                                                         v = '';\r
1425 \r
1426                                                 break;\r
1427 \r
1428                                         case 'width':\r
1429                                         case 'height':\r
1430                                         case 'vspace':\r
1431                                         case 'checked':\r
1432                                         case 'disabled':\r
1433                                         case 'readonly':\r
1434                                                 if (v === 0)\r
1435                                                         v = '';\r
1436 \r
1437                                                 break;\r
1438 \r
1439                                         case 'hspace':\r
1440                                                 // IE returns -1 as default value\r
1441                                                 if (v === -1)\r
1442                                                         v = '';\r
1443 \r
1444                                                 break;\r
1445 \r
1446                                         case 'maxlength':\r
1447                                         case 'tabindex':\r
1448                                                 // IE returns default value\r
1449                                                 if (v === 32768 || v === 2147483647 || v === '32768')\r
1450                                                         v = '';\r
1451 \r
1452                                                 break;\r
1453 \r
1454                                         case 'multiple':\r
1455                                         case 'compact':\r
1456                                         case 'noshade':\r
1457                                         case 'nowrap':\r
1458                                                 if (v === 65535)\r
1459                                                         return n;\r
1460 \r
1461                                                 return dv;\r
1462 \r
1463                                         case 'shape':\r
1464                                                 v = v.toLowerCase();\r
1465                                                 break;\r
1466 \r
1467                                         default:\r
1468                                                 // IE has odd anonymous function for event attributes\r
1469                                                 if (n.indexOf('on') === 0 && v)\r
1470                                                         v = ('' + v).replace(/^function\s+anonymous\(\)\s+\{\s+(.*)\s+\}$/, '$1');\r
1471                                 }\r
1472                         }\r
1473 \r
1474                         return (v !== undefined && v !== null && v !== '') ? '' + v : dv;\r
1475                 },\r
1476 \r
1477                 getPos : function(n, ro) {\r
1478                         var t = this, x = 0, y = 0, e, d = t.doc, r;\r
1479 \r
1480                         n = t.get(n);\r
1481                         ro = ro || d.body;\r
1482 \r
1483                         if (n) {\r
1484                                 // Use getBoundingClientRect on IE, Opera has it but it's not perfect\r
1485                                 if (isIE && !t.stdMode) {\r
1486                                         n = n.getBoundingClientRect();\r
1487                                         e = t.boxModel ? d.documentElement : d.body;\r
1488                                         x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border\r
1489                                         x = (x == 'medium' || t.boxModel && !t.isIE6) && 2 || x;\r
1490                                         n.top += t.win.self != t.win.top ? 2 : 0; // IE adds some strange extra cord if used in a frameset\r
1491 \r
1492                                         return {x : n.left + e.scrollLeft - x, y : n.top + e.scrollTop - x};\r
1493                                 }\r
1494 \r
1495                                 r = n;\r
1496                                 while (r && r != ro && r.nodeType) {\r
1497                                         x += r.offsetLeft || 0;\r
1498                                         y += r.offsetTop || 0;\r
1499                                         r = r.offsetParent;\r
1500                                 }\r
1501 \r
1502                                 r = n.parentNode;\r
1503                                 while (r && r != ro && r.nodeType) {\r
1504                                         x -= r.scrollLeft || 0;\r
1505                                         y -= r.scrollTop || 0;\r
1506                                         r = r.parentNode;\r
1507                                 }\r
1508                         }\r
1509 \r
1510                         return {x : x, y : y};\r
1511                 },\r
1512 \r
1513                 parseStyle : function(st) {\r
1514                         var t = this, s = t.settings, o = {};\r
1515 \r
1516                         if (!st)\r
1517                                 return o;\r
1518 \r
1519                         function compress(p, s, ot) {\r
1520                                 var t, r, b, l;\r
1521 \r
1522                                 // Get values and check it it needs compressing\r
1523                                 t = o[p + '-top' + s];\r
1524                                 if (!t)\r
1525                                         return;\r
1526 \r
1527                                 r = o[p + '-right' + s];\r
1528                                 if (t != r)\r
1529                                         return;\r
1530 \r
1531                                 b = o[p + '-bottom' + s];\r
1532                                 if (r != b)\r
1533                                         return;\r
1534 \r
1535                                 l = o[p + '-left' + s];\r
1536                                 if (b != l)\r
1537                                         return;\r
1538 \r
1539                                 // Compress\r
1540                                 o[ot] = l;\r
1541                                 delete o[p + '-top' + s];\r
1542                                 delete o[p + '-right' + s];\r
1543                                 delete o[p + '-bottom' + s];\r
1544                                 delete o[p + '-left' + s];\r
1545                         };\r
1546 \r
1547                         function compress2(ta, a, b, c) {\r
1548                                 var t;\r
1549 \r
1550                                 t = o[a];\r
1551                                 if (!t)\r
1552                                         return;\r
1553 \r
1554                                 t = o[b];\r
1555                                 if (!t)\r
1556                                         return;\r
1557 \r
1558                                 t = o[c];\r
1559                                 if (!t)\r
1560                                         return;\r
1561 \r
1562                                 // Compress\r
1563                                 o[ta] = o[a] + ' ' + o[b] + ' ' + o[c];\r
1564                                 delete o[a];\r
1565                                 delete o[b];\r
1566                                 delete o[c];\r
1567                         };\r
1568 \r
1569                         st = st.replace(/&(#?[a-z0-9]+);/g, '&$1_MCE_SEMI_'); // Protect entities\r
1570 \r
1571                         each(st.split(';'), function(v) {\r
1572                                 var sv, ur = [];\r
1573 \r
1574                                 if (v) {\r
1575                                         v = v.replace(/_MCE_SEMI_/g, ';'); // Restore entities\r
1576                                         v = v.replace(/url\([^\)]+\)/g, function(v) {ur.push(v);return 'url(' + ur.length + ')';});\r
1577                                         v = v.split(':');\r
1578                                         sv = tinymce.trim(v[1]);\r
1579                                         sv = sv.replace(/url\(([^\)]+)\)/g, function(a, b) {return ur[parseInt(b) - 1];});\r
1580 \r
1581                                         sv = sv.replace(/rgb\([^\)]+\)/g, function(v) {\r
1582                                                 return t.toHex(v);\r
1583                                         });\r
1584 \r
1585                                         if (s.url_converter) {\r
1586                                                 sv = sv.replace(/url\([\'\"]?([^\)\'\"]+)[\'\"]?\)/g, function(x, c) {\r
1587                                                         return 'url(' + s.url_converter.call(s.url_converter_scope || t, t.decode(c), 'style', null) + ')';\r
1588                                                 });\r
1589                                         }\r
1590 \r
1591                                         o[tinymce.trim(v[0]).toLowerCase()] = sv;\r
1592                                 }\r
1593                         });\r
1594 \r
1595                         compress("border", "", "border");\r
1596                         compress("border", "-width", "border-width");\r
1597                         compress("border", "-color", "border-color");\r
1598                         compress("border", "-style", "border-style");\r
1599                         compress("padding", "", "padding");\r
1600                         compress("margin", "", "margin");\r
1601                         compress2('border', 'border-width', 'border-style', 'border-color');\r
1602 \r
1603                         if (isIE) {\r
1604                                 // Remove pointless border\r
1605                                 if (o.border == 'medium none')\r
1606                                         o.border = '';\r
1607                         }\r
1608 \r
1609                         return o;\r
1610                 },\r
1611 \r
1612                 serializeStyle : function(o) {\r
1613                         var s = '';\r
1614 \r
1615                         each(o, function(v, k) {\r
1616                                 if (k && v) {\r
1617                                         if (tinymce.isGecko && k.indexOf('-moz-') === 0)\r
1618                                                 return;\r
1619 \r
1620                                         switch (k) {\r
1621                                                 case 'color':\r
1622                                                 case 'background-color':\r
1623                                                         v = v.toLowerCase();\r
1624                                                         break;\r
1625                                         }\r
1626 \r
1627                                         s += (s ? ' ' : '') + k + ': ' + v + ';';\r
1628                                 }\r
1629                         });\r
1630 \r
1631                         return s;\r
1632                 },\r
1633 \r
1634                 loadCSS : function(u) {\r
1635                         var t = this, d = t.doc;\r
1636 \r
1637                         if (!u)\r
1638                                 u = '';\r
1639 \r
1640                         each(u.split(','), function(u) {\r
1641                                 if (t.files[u])\r
1642                                         return;\r
1643 \r
1644                                 t.files[u] = true;\r
1645                                 t.add(t.select('head')[0], 'link', {rel : 'stylesheet', href : tinymce._addVer(u)});\r
1646                         });\r
1647                 },\r
1648 \r
1649 \r
1650                 addClass : function(e, c) {\r
1651                         return this.run(e, function(e) {\r
1652                                 var o;\r
1653 \r
1654                                 if (!c)\r
1655                                         return 0;\r
1656 \r
1657                                 if (this.hasClass(e, c))\r
1658                                         return e.className;\r
1659 \r
1660                                 o = this.removeClass(e, c);\r
1661 \r
1662                                 return e.className = (o != '' ? (o + ' ') : '') + c;\r
1663                         });\r
1664                 },\r
1665 \r
1666                 removeClass : function(e, c) {\r
1667                         var t = this, re;\r
1668 \r
1669                         return t.run(e, function(e) {\r
1670                                 var v;\r
1671 \r
1672                                 if (t.hasClass(e, c)) {\r
1673                                         if (!re)\r
1674                                                 re = new RegExp("(^|\\s+)" + c + "(\\s+|$)", "g");\r
1675 \r
1676                                         v = e.className.replace(re, ' ');\r
1677 \r
1678                                         return e.className = tinymce.trim(v != ' ' ? v : '');\r
1679                                 }\r
1680 \r
1681                                 return e.className;\r
1682                         });\r
1683                 },\r
1684 \r
1685                 hasClass : function(n, c) {\r
1686                         n = this.get(n);\r
1687 \r
1688                         if (!n || !c)\r
1689                                 return false;\r
1690 \r
1691                         return (' ' + n.className + ' ').indexOf(' ' + c + ' ') !== -1;\r
1692                 },\r
1693 \r
1694                 show : function(e) {\r
1695                         return this.setStyle(e, 'display', 'block');\r
1696                 },\r
1697 \r
1698                 hide : function(e) {\r
1699                         return this.setStyle(e, 'display', 'none');\r
1700                 },\r
1701 \r
1702                 isHidden : function(e) {\r
1703                         e = this.get(e);\r
1704 \r
1705                         return !e || e.style.display == 'none' || this.getStyle(e, 'display') == 'none';\r
1706                 },\r
1707 \r
1708 \r
1709                 uniqueId : function(p) {\r
1710                         return (!p ? 'mce_' : p) + (this.counter++);\r
1711                 },\r
1712 \r
1713                 setHTML : function(e, h) {\r
1714                         var t = this;\r
1715 \r
1716                         return this.run(e, function(e) {\r
1717                                 var x, i, nl, n, p, x;\r
1718 \r
1719                                 h = t.processHTML(h);\r
1720 \r
1721                                 if (isIE) {\r
1722                                         function set() {\r
1723                                                 try {\r
1724                                                         // IE will remove comments from the beginning\r
1725                                                         // unless you padd the contents with something\r
1726                                                         e.innerHTML = '<br />' + h;\r
1727                                                         e.removeChild(e.firstChild);\r
1728                                                 } catch (ex) {\r
1729                                                         // 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\r
1730                                                         // This seems to fix this problem\r
1731 \r
1732                                                         // Remove all child nodes\r
1733                                                         while (e.firstChild)\r
1734                                                                 e.firstChild.removeNode();\r
1735 \r
1736                                                         // Create new div with HTML contents and a BR infront to keep comments\r
1737                                                         x = t.create('div');\r
1738                                                         x.innerHTML = '<br />' + h;\r
1739 \r
1740                                                         // Add all children from div to target\r
1741                                                         each (x.childNodes, function(n, i) {\r
1742                                                                 // Skip br element\r
1743                                                                 if (i)\r
1744                                                                         e.appendChild(n);\r
1745                                                         });\r
1746                                                 }\r
1747                                         };\r
1748 \r
1749                                         // IE has a serious bug when it comes to paragraphs it can produce an invalid\r
1750                                         // DOM tree if contents like this <p><ul><li>Item 1</li></ul></p> is inserted\r
1751                                         // It seems to be that IE doesn't like a root block element placed inside another root block element\r
1752                                         if (t.settings.fix_ie_paragraphs)\r
1753                                                 h = h.replace(/<p><\/p>|<p([^>]+)><\/p>|<p[^\/+]\/>/gi, '<p$1 mce_keep="true">&nbsp;</p>');\r
1754 \r
1755                                         set();\r
1756 \r
1757                                         if (t.settings.fix_ie_paragraphs) {\r
1758                                                 // Check for odd paragraphs this is a sign of a broken DOM\r
1759                                                 nl = e.getElementsByTagName("p");\r
1760                                                 for (i = nl.length - 1, x = 0; i >= 0; i--) {\r
1761                                                         n = nl[i];\r
1762 \r
1763                                                         if (!n.hasChildNodes()) {\r
1764                                                                 if (!n.mce_keep) {\r
1765                                                                         x = 1; // Is broken\r
1766                                                                         break;\r
1767                                                                 }\r
1768 \r
1769                                                                 n.removeAttribute('mce_keep');\r
1770                                                         }\r
1771                                                 }\r
1772                                         }\r
1773 \r
1774                                         // Time to fix the madness IE left us\r
1775                                         if (x) {\r
1776                                                 // So if we replace the p elements with divs and mark them and then replace them back to paragraphs\r
1777                                                 // after we use innerHTML we can fix the DOM tree\r
1778                                                 h = h.replace(/<p ([^>]+)>|<p>/g, '<div $1 mce_tmp="1">');\r
1779                                                 h = h.replace(/<\/p>/g, '</div>');\r
1780 \r
1781                                                 // Set the new HTML with DIVs\r
1782                                                 set();\r
1783 \r
1784                                                 // Replace all DIV elements with he mce_tmp attibute back to paragraphs\r
1785                                                 // This is needed since IE has a annoying bug see above for details\r
1786                                                 // This is a slow process but it has to be done. :(\r
1787                                                 if (t.settings.fix_ie_paragraphs) {\r
1788                                                         nl = e.getElementsByTagName("DIV");\r
1789                                                         for (i = nl.length - 1; i >= 0; i--) {\r
1790                                                                 n = nl[i];\r
1791 \r
1792                                                                 // Is it a temp div\r
1793                                                                 if (n.mce_tmp) {\r
1794                                                                         // Create new paragraph\r
1795                                                                         p = t.doc.createElement('p');\r
1796 \r
1797                                                                         // Copy all attributes\r
1798                                                                         n.cloneNode(false).outerHTML.replace(/([a-z0-9\-_]+)=/gi, function(a, b) {\r
1799                                                                                 var v;\r
1800 \r
1801                                                                                 if (b !== 'mce_tmp') {\r
1802                                                                                         v = n.getAttribute(b);\r
1803 \r
1804                                                                                         if (!v && b === 'class')\r
1805                                                                                                 v = n.className;\r
1806 \r
1807                                                                                         p.setAttribute(b, v);\r
1808                                                                                 }\r
1809                                                                         });\r
1810 \r
1811                                                                         // Append all children to new paragraph\r
1812                                                                         for (x = 0; x<n.childNodes.length; x++)\r
1813                                                                                 p.appendChild(n.childNodes[x].cloneNode(true));\r
1814 \r
1815                                                                         // Replace div with new paragraph\r
1816                                                                         n.swapNode(p);\r
1817                                                                 }\r
1818                                                         }\r
1819                                                 }\r
1820                                         }\r
1821                                 } else\r
1822                                         e.innerHTML = h;\r
1823 \r
1824                                 return h;\r
1825                         });\r
1826                 },\r
1827 \r
1828                 processHTML : function(h) {\r
1829                         var t = this, s = t.settings;\r
1830 \r
1831                         if (!s.process_html)\r
1832                                 return h;\r
1833 \r
1834                         // Convert strong and em to b and i in FF since it can't handle them\r
1835                         if (tinymce.isGecko) {\r
1836                                 h = h.replace(/<(\/?)strong>|<strong( [^>]+)>/gi, '<$1b$2>');\r
1837                                 h = h.replace(/<(\/?)em>|<em( [^>]+)>/gi, '<$1i$2>');\r
1838                         } else if (isIE) {\r
1839                                 h = h.replace(/&apos;/g, '&#39;'); // IE can't handle apos\r
1840                                 h = h.replace(/\s+(disabled|checked|readonly|selected)\s*=\s*[\"\']?(false|0)[\"\']?/gi, ''); // IE doesn't handle default values correct\r
1841                         }\r
1842 \r
1843                         // Fix some issues\r
1844                         h = h.replace(/<a( )([^>]+)\/>|<a\/>/gi, '<a$1$2></a>'); // Force open\r
1845 \r
1846                         // Store away src and href in mce_src and mce_href since browsers mess them up\r
1847                         if (s.keep_values) {\r
1848                                 // Wrap scripts and styles in comments for serialization purposes\r
1849                                 if (/<script|style/.test(h)) {\r
1850                                         function trim(s) {\r
1851                                                 // Remove prefix and suffix code for element\r
1852                                                 s = s.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n');\r
1853                                                 s = s.replace(/^[\r\n]*|[\r\n]*$/g, '');\r
1854                                                 s = s.replace(/^\s*(\/\/\s*<!--|\/\/\s*<!\[CDATA\[|<!--|<!\[CDATA\[)[\r\n]*/g, '');\r
1855                                                 s = s.replace(/\s*(\/\/\s*\]\]>|\/\/\s*-->|\]\]>|-->|\]\]-->)\s*$/g, '');\r
1856 \r
1857                                                 return s;\r
1858                                         };\r
1859 \r
1860                                         // Preserve script elements\r
1861                                         h = h.replace(/<script([^>]+|)>([\s\S]*?)<\/script>/g, function(v, a, b) {\r
1862                                                 // Remove prefix and suffix code for script element\r
1863                                                 b = trim(b);\r
1864 \r
1865                                                 // Force type attribute\r
1866                                                 if (!a)\r
1867                                                         a = ' type="text/javascript"';\r
1868 \r
1869                                                 // Wrap contents in a comment\r
1870                                                 if (b)\r
1871                                                         b = '<!--\n' + b + '\n// -->';\r
1872 \r
1873                                                 // Output fake element\r
1874                                                 return '<mce:script' + a + '>' + b + '</mce:script>';\r
1875                                         });\r
1876 \r
1877                                         // Preserve style elements\r
1878                                         h = h.replace(/<style([^>]+|)>([\s\S]*?)<\/style>/g, function(v, a, b) {\r
1879                                                 b = trim(b);\r
1880                                                 return '<mce:style' + a + '><!--\n' + b + '\n--></mce:style><style' + a + ' mce_bogus="1">' + b + '</style>';\r
1881                                         });\r
1882                                 }\r
1883 \r
1884                                 h = h.replace(/<!\[CDATA\[([\s\S]+)\]\]>/g, '<!--[CDATA[$1]]-->');\r
1885 \r
1886                                 // Process all tags with src, href or style\r
1887                                 h = h.replace(/<([\w:]+) [^>]*(src|href|style|shape|coords)[^>]*>/gi, function(a, n) {\r
1888                                         function handle(m, b, c) {\r
1889                                                 var u = c;\r
1890 \r
1891                                                 // Tag already got a mce_ version\r
1892                                                 if (a.indexOf('mce_' + b) != -1)\r
1893                                                         return m;\r
1894 \r
1895                                                 if (b == 'style') {\r
1896                                                         // No mce_style for elements with these since they might get resized by the user\r
1897                                                         if (t._isRes(c))\r
1898                                                                 return m;\r
1899 \r
1900                                                         if (s.hex_colors) {\r
1901                                                                 u = u.replace(/rgb\([^\)]+\)/g, function(v) {\r
1902                                                                         return t.toHex(v);\r
1903                                                                 });\r
1904                                                         }\r
1905 \r
1906                                                         if (s.url_converter) {\r
1907                                                                 u = u.replace(/url\([\'\"]?([^\)\'\"]+)\)/g, function(x, c) {\r
1908                                                                         return 'url(' + t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(c), b, n)) + ')';\r
1909                                                                 });\r
1910                                                         }\r
1911                                                 } else if (b != 'coords' && b != 'shape') {\r
1912                                                         if (s.url_converter)\r
1913                                                                 u = t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(c), b, n));\r
1914                                                 }\r
1915 \r
1916                                                 return ' ' + b + '="' + c + '" mce_' + b + '="' + u + '"';\r
1917                                         };\r
1918 \r
1919                                         a = a.replace(/ (src|href|style|coords|shape)=[\"]([^\"]+)[\"]/gi, handle); // W3C\r
1920                                         a = a.replace(/ (src|href|style|coords|shape)=[\']([^\']+)[\']/gi, handle); // W3C\r
1921 \r
1922                                         return a.replace(/ (src|href|style|coords|shape)=([^\s\"\'>]+)/gi, handle); // IE\r
1923                                 });\r
1924                         }\r
1925 \r
1926                         return h;\r
1927                 },\r
1928 \r
1929                 getOuterHTML : function(e) {\r
1930                         var d;\r
1931 \r
1932                         e = this.get(e);\r
1933 \r
1934                         if (!e)\r
1935                                 return null;\r
1936 \r
1937                         if (e.outerHTML !== undefined)\r
1938                                 return e.outerHTML;\r
1939 \r
1940                         d = (e.ownerDocument || this.doc).createElement("body");\r
1941                         d.appendChild(e.cloneNode(true));\r
1942 \r
1943                         return d.innerHTML;\r
1944                 },\r
1945 \r
1946                 setOuterHTML : function(e, h, d) {\r
1947                         var t = this;\r
1948 \r
1949                         return this.run(e, function(e) {\r
1950                                 var n, tp;\r
1951 \r
1952                                 e = t.get(e);\r
1953                                 d = d || e.ownerDocument || t.doc;\r
1954 \r
1955                                 if (isIE && e.nodeType == 1)\r
1956                                         e.outerHTML = h;\r
1957                                 else {\r
1958                                         tp = d.createElement("body");\r
1959                                         tp.innerHTML = h;\r
1960 \r
1961                                         n = tp.lastChild;\r
1962                                         while (n) {\r
1963                                                 t.insertAfter(n.cloneNode(true), e);\r
1964                                                 n = n.previousSibling;\r
1965                                         }\r
1966 \r
1967                                         t.remove(e);\r
1968                                 }\r
1969                         });\r
1970                 },\r
1971 \r
1972                 decode : function(s) {\r
1973                         var e, n, v;\r
1974 \r
1975                         // Look for entities to decode\r
1976                         if (/&[^;]+;/.test(s)) {\r
1977                                 // Decode the entities using a div element not super efficient but less code\r
1978                                 e = this.doc.createElement("div");\r
1979                                 e.innerHTML = s;\r
1980                                 n = e.firstChild;\r
1981                                 v = '';\r
1982 \r
1983                                 if (n) {\r
1984                                         do {\r
1985                                                 v += n.nodeValue;\r
1986                                         } while (n.nextSibling);\r
1987                                 }\r
1988 \r
1989                                 return v || s;\r
1990                         }\r
1991 \r
1992                         return s;\r
1993                 },\r
1994 \r
1995                 encode : function(s) {\r
1996                         return s ? ('' + s).replace(/[<>&\"]/g, function (c, b) {\r
1997                                 switch (c) {\r
1998                                         case '&':\r
1999                                                 return '&amp;';\r
2000 \r
2001                                         case '"':\r
2002                                                 return '&quot;';\r
2003 \r
2004                                         case '<':\r
2005                                                 return '&lt;';\r
2006 \r
2007                                         case '>':\r
2008                                                 return '&gt;';\r
2009                                 }\r
2010 \r
2011                                 return c;\r
2012                         }) : s;\r
2013                 },\r
2014 \r
2015 \r
2016                 insertAfter : function(n, r) {\r
2017                         var t = this;\r
2018 \r
2019                         r = t.get(r);\r
2020 \r
2021                         return this.run(n, function(n) {\r
2022                                 var p, ns;\r
2023 \r
2024                                 p = r.parentNode;\r
2025                                 ns = r.nextSibling;\r
2026 \r
2027                                 if (ns)\r
2028                                         p.insertBefore(n, ns);\r
2029                                 else\r
2030                                         p.appendChild(n);\r
2031 \r
2032                                 return n;\r
2033                         });\r
2034                 },\r
2035 \r
2036 \r
2037                 isBlock : function(n) {\r
2038                         if (n.nodeType && n.nodeType !== 1)\r
2039                                 return false;\r
2040 \r
2041                         n = n.nodeName || n;\r
2042 \r
2043                         return /^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TR|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n);\r
2044                 },\r
2045 \r
2046 \r
2047                 replace : function(n, o, k) {\r
2048                         var t = this;\r
2049 \r
2050                         if (is(o, 'array'))\r
2051                                 n = n.cloneNode(true);\r
2052 \r
2053                         return t.run(o, function(o) {\r
2054                                 if (k) {\r
2055                                         each(o.childNodes, function(c) {\r
2056                                                 n.appendChild(c.cloneNode(true));\r
2057                                         });\r
2058                                 }\r
2059 \r
2060                                 // Fix IE psuedo leak for elements since replacing elements if fairly common\r
2061                                 // Will break parentNode for some unknown reason\r
2062                                 if (t.fixPsuedoLeaks && o.nodeType === 1) {\r
2063                                         o.parentNode.insertBefore(n, o);\r
2064                                         t.remove(o);\r
2065                                         return n;\r
2066                                 }\r
2067 \r
2068                                 return o.parentNode.replaceChild(n, o);\r
2069                         });\r
2070                 },\r
2071 \r
2072 \r
2073                 findCommonAncestor : function(a, b) {\r
2074                         var ps = a, pe;\r
2075 \r
2076                         while (ps) {\r
2077                                 pe = b;\r
2078 \r
2079                                 while (pe && ps != pe)\r
2080                                         pe = pe.parentNode;\r
2081 \r
2082                                 if (ps == pe)\r
2083                                         break;\r
2084 \r
2085                                 ps = ps.parentNode;\r
2086                         }\r
2087 \r
2088                         if (!ps && a.ownerDocument)\r
2089                                 return a.ownerDocument.documentElement;\r
2090 \r
2091                         return ps;\r
2092                 },\r
2093 \r
2094                 toHex : function(s) {\r
2095                         var c = /^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(s);\r
2096 \r
2097                         function hex(s) {\r
2098                                 s = parseInt(s).toString(16);\r
2099 \r
2100                                 return s.length > 1 ? s : '0' + s; // 0 -> 00\r
2101                         };\r
2102 \r
2103                         if (c) {\r
2104                                 s = '#' + hex(c[1]) + hex(c[2]) + hex(c[3]);\r
2105 \r
2106                                 return s;\r
2107                         }\r
2108 \r
2109                         return s;\r
2110                 },\r
2111 \r
2112                 getClasses : function() {\r
2113                         var t = this, cl = [], i, lo = {}, f = t.settings.class_filter, ov;\r
2114 \r
2115                         if (t.classes)\r
2116                                 return t.classes;\r
2117 \r
2118                         function addClasses(s) {\r
2119                                 // IE style imports\r
2120                                 each(s.imports, function(r) {\r
2121                                         addClasses(r);\r
2122                                 });\r
2123 \r
2124                                 each(s.cssRules || s.rules, function(r) {\r
2125                                         // Real type or fake it on IE\r
2126                                         switch (r.type || 1) {\r
2127                                                 // Rule\r
2128                                                 case 1:\r
2129                                                         if (r.selectorText) {\r
2130                                                                 each(r.selectorText.split(','), function(v) {\r
2131                                                                         v = v.replace(/^\s*|\s*$|^\s\./g, "");\r
2132 \r
2133                                                                         // Is internal or it doesn't contain a class\r
2134                                                                         if (/\.mce/.test(v) || !/\.[\w\-]+$/.test(v))\r
2135                                                                                 return;\r
2136 \r
2137                                                                         // Remove everything but class name\r
2138                                                                         ov = v;\r
2139                                                                         v = v.replace(/.*\.([a-z0-9_\-]+).*/i, '$1');\r
2140 \r
2141                                                                         // Filter classes\r
2142                                                                         if (f && !(v = f(v, ov)))\r
2143                                                                                 return;\r
2144 \r
2145                                                                         if (!lo[v]) {\r
2146                                                                                 cl.push({'class' : v});\r
2147                                                                                 lo[v] = 1;\r
2148                                                                         }\r
2149                                                                 });\r
2150                                                         }\r
2151                                                         break;\r
2152 \r
2153                                                 // Import\r
2154                                                 case 3:\r
2155                                                         addClasses(r.styleSheet);\r
2156                                                         break;\r
2157                                         }\r
2158                                 });\r
2159                         };\r
2160 \r
2161                         try {\r
2162                                 each(t.doc.styleSheets, addClasses);\r
2163                         } catch (ex) {\r
2164                                 // Ignore\r
2165                         }\r
2166 \r
2167                         if (cl.length > 0)\r
2168                                 t.classes = cl;\r
2169 \r
2170                         return cl;\r
2171                 },\r
2172 \r
2173                 run : function(e, f, s) {\r
2174                         var t = this, o;\r
2175 \r
2176                         if (t.doc && typeof(e) === 'string')\r
2177                                 e = t.get(e);\r
2178 \r
2179                         if (!e)\r
2180                                 return false;\r
2181 \r
2182                         s = s || this;\r
2183                         if (!e.nodeType && (e.length || e.length === 0)) {\r
2184                                 o = [];\r
2185 \r
2186                                 each(e, function(e, i) {\r
2187                                         if (e) {\r
2188                                                 if (typeof(e) == 'string')\r
2189                                                         e = t.doc.getElementById(e);\r
2190 \r
2191                                                 o.push(f.call(s, e, i));\r
2192                                         }\r
2193                                 });\r
2194 \r
2195                                 return o;\r
2196                         }\r
2197 \r
2198                         return f.call(s, e);\r
2199                 },\r
2200 \r
2201                 getAttribs : function(n) {\r
2202                         var o;\r
2203 \r
2204                         n = this.get(n);\r
2205 \r
2206                         if (!n)\r
2207                                 return [];\r
2208 \r
2209                         if (isIE) {\r
2210                                 o = [];\r
2211 \r
2212                                 // Object will throw exception in IE\r
2213                                 if (n.nodeName == 'OBJECT')\r
2214                                         return n.attributes;\r
2215 \r
2216                                 // It's crazy that this is faster in IE but it's because it returns all attributes all the time\r
2217                                 n.cloneNode(false).outerHTML.replace(/([a-z0-9\:\-_]+)=/gi, function(a, b) {\r
2218                                         o.push({specified : 1, nodeName : b});\r
2219                                 });\r
2220 \r
2221                                 return o;\r
2222                         }\r
2223 \r
2224                         return n.attributes;\r
2225                 },\r
2226 \r
2227                 destroy : function(s) {\r
2228                         var t = this;\r
2229 \r
2230                         t.win = t.doc = t.root = null;\r
2231 \r
2232                         // Manual destroy then remove unload handler\r
2233                         if (!s)\r
2234                                 tinymce.removeUnload(t.destroy);\r
2235                 },\r
2236 \r
2237                 createRng : function() {\r
2238                         var d = this.doc;\r
2239 \r
2240                         return d.createRange ? d.createRange() : new tinymce.dom.Range(this);\r
2241                 },\r
2242 \r
2243                 split : function(pe, e, re) {\r
2244                         var t = this, r = t.createRng(), bef, aft, pa;\r
2245 \r
2246                         // W3C valid browsers tend to leave empty nodes to the left/right side of the contents, this makes sence\r
2247                         // but we don't want that in our code since it serves no purpose\r
2248                         // For example if this is chopped:\r
2249                         //   <p>text 1<span><b>CHOP</b></span>text 2</p>\r
2250                         // would produce:\r
2251                         //   <p>text 1<span></span></p><b>CHOP</b><p><span></span>text 2</p>\r
2252                         // this function will then trim of empty edges and produce:\r
2253                         //   <p>text 1</p><b>CHOP</b><p>text 2</p>\r
2254                         function trimEdge(n, na) {\r
2255                                 n = n[na];\r
2256 \r
2257                                 if (n && n[na] && n[na].nodeType == 1 && isEmpty(n[na]))\r
2258                                         t.remove(n[na]);\r
2259                         };\r
2260 \r
2261                         function isEmpty(n) {\r
2262                                 n = t.getOuterHTML(n);\r
2263                                 n = n.replace(/<(img|hr|table)/gi, '-'); // Keep these convert them to - chars\r
2264                                 n = n.replace(/<[^>]+>/g, ''); // Remove all tags\r
2265 \r
2266                                 return n.replace(/[ \t\r\n]+|&nbsp;|&#160;/g, '') == '';\r
2267                         };\r
2268 \r
2269                         if (pe && e) {\r
2270                                 // Get before chunk\r
2271                                 r.setStartBefore(pe);\r
2272                                 r.setEndBefore(e);\r
2273                                 bef = r.extractContents();\r
2274 \r
2275                                 // Get after chunk\r
2276                                 r = t.createRng();\r
2277                                 r.setStartAfter(e);\r
2278                                 r.setEndAfter(pe);\r
2279                                 aft = r.extractContents();\r
2280 \r
2281                                 // Insert chunks and remove parent\r
2282                                 pa = pe.parentNode;\r
2283 \r
2284                                 // Remove right side edge of the before contents\r
2285                                 trimEdge(bef, 'lastChild');\r
2286 \r
2287                                 if (!isEmpty(bef))\r
2288                                         pa.insertBefore(bef, pe);\r
2289 \r
2290                                 if (re)\r
2291                                         pa.replaceChild(re, e);\r
2292                                 else\r
2293                                         pa.insertBefore(e, pe);\r
2294 \r
2295                                 // Remove left site edge of the after contents\r
2296                                 trimEdge(aft, 'firstChild');\r
2297 \r
2298                                 if (!isEmpty(aft))\r
2299                                         pa.insertBefore(aft, pe);\r
2300 \r
2301                                 t.remove(pe);\r
2302 \r
2303                                 return re || e;\r
2304                         }\r
2305                 },\r
2306 \r
2307 \r
2308                 _isRes : function(c) {\r
2309                         // Is live resizble element\r
2310                         return /^(top|left|bottom|right|width|height)/i.test(c) || /;\s*(top|left|bottom|right|width|height)/i.test(c);\r
2311                 }\r
2312 \r
2313                 /*\r
2314                 walk : function(n, f, s) {\r
2315                         var d = this.doc, w;\r
2316 \r
2317                         if (d.createTreeWalker) {\r
2318                                 w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);\r
2319 \r
2320                                 while ((n = w.nextNode()) != null)\r
2321                                         f.call(s || this, n);\r
2322                         } else\r
2323                                 tinymce.walk(n, f, 'childNodes', s);\r
2324                 }\r
2325                 */\r
2326 \r
2327                 /*\r
2328                 toRGB : function(s) {\r
2329                         var c = /^\s*?#([0-9A-F]{2})([0-9A-F]{1,2})([0-9A-F]{2})?\s*?$/.exec(s);\r
2330 \r
2331                         if (c) {\r
2332                                 // #FFF -> #FFFFFF\r
2333                                 if (!is(c[3]))\r
2334                                         c[3] = c[2] = c[1];\r
2335 \r
2336                                 return "rgb(" + parseInt(c[1], 16) + "," + parseInt(c[2], 16) + "," + parseInt(c[3], 16) + ")";\r
2337                         }\r
2338 \r
2339                         return s;\r
2340                 }\r
2341                 */\r
2342 \r
2343                 });\r
2344 \r
2345         // Setup page DOM\r
2346         tinymce.DOM = new tinymce.dom.DOMUtils(document, {process_html : 0});\r
2347 })(tinymce);\r
2348 (function(ns) {\r
2349         // Traverse constants\r
2350         var EXTRACT = 0, CLONE = 1, DELETE = 2, extend = tinymce.extend;\r
2351 \r
2352         function indexOf(child, parent) {\r
2353                 var i, node;\r
2354 \r
2355                 if (child.parentNode != parent)\r
2356                         return -1;\r
2357 \r
2358                 for (node = parent.firstChild, i = 0; node != child; node = node.nextSibling)\r
2359                         i++;\r
2360 \r
2361                 return i;\r
2362         };\r
2363 \r
2364         function nodeIndex(n) {\r
2365                 var i = 0;\r
2366 \r
2367                 while (n.previousSibling) {\r
2368                         i++;\r
2369                         n = n.previousSibling;\r
2370                 }\r
2371 \r
2372                 return i;\r
2373         };\r
2374 \r
2375         function getSelectedNode(container, offset) {\r
2376                 var child;\r
2377 \r
2378                 if (container.nodeType == 3 /* TEXT_NODE */)\r
2379                         return container;\r
2380 \r
2381                 if (offset < 0)\r
2382                         return container;\r
2383 \r
2384                 child = container.firstChild;\r
2385                 while (child != null && offset > 0) {\r
2386                         --offset;\r
2387                         child = child.nextSibling;\r
2388                 }\r
2389 \r
2390                 if (child != null)\r
2391                         return child;\r
2392 \r
2393                 return container;\r
2394         };\r
2395 \r
2396         // Range constructor\r
2397         function Range(dom) {\r
2398                 var d = dom.doc;\r
2399 \r
2400                 extend(this, {\r
2401                         dom : dom,\r
2402 \r
2403                         // Inital states\r
2404                         startContainer : d,\r
2405                         startOffset : 0,\r
2406                         endContainer : d,\r
2407                         endOffset : 0,\r
2408                         collapsed : true,\r
2409                         commonAncestorContainer : d,\r
2410 \r
2411                         // Range constants\r
2412                         START_TO_START : 0,\r
2413                         START_TO_END : 1,\r
2414                         END_TO_END : 2,\r
2415                         END_TO_START : 3\r
2416                 });\r
2417         };\r
2418 \r
2419         // Add range methods\r
2420         extend(Range.prototype, {\r
2421                 setStart : function(n, o) {\r
2422                         this._setEndPoint(true, n, o);\r
2423                 },\r
2424 \r
2425                 setEnd : function(n, o) {\r
2426                         this._setEndPoint(false, n, o);\r
2427                 },\r
2428 \r
2429                 setStartBefore : function(n) {\r
2430                         this.setStart(n.parentNode, nodeIndex(n));\r
2431                 },\r
2432 \r
2433                 setStartAfter : function(n) {\r
2434                         this.setStart(n.parentNode, nodeIndex(n) + 1);\r
2435                 },\r
2436 \r
2437                 setEndBefore : function(n) {\r
2438                         this.setEnd(n.parentNode, nodeIndex(n));\r
2439                 },\r
2440 \r
2441                 setEndAfter : function(n) {\r
2442                         this.setEnd(n.parentNode, nodeIndex(n) + 1);\r
2443                 },\r
2444 \r
2445                 collapse : function(ts) {\r
2446                         var t = this;\r
2447 \r
2448                         if (ts) {\r
2449                                 t.endContainer = t.startContainer;\r
2450                                 t.endOffset = t.startOffset;\r
2451                         } else {\r
2452                                 t.startContainer = t.endContainer;\r
2453                                 t.startOffset = t.endOffset;\r
2454                         }\r
2455 \r
2456                         t.collapsed = true;\r
2457                 },\r
2458 \r
2459                 selectNode : function(n) {\r
2460                         this.setStartBefore(n);\r
2461                         this.setEndAfter(n);\r
2462                 },\r
2463 \r
2464                 selectNodeContents : function(n) {\r
2465                         this.setStart(n, 0);\r
2466                         this.setEnd(n, n.nodeType === 1 ? n.childNodes.length : n.nodeValue.length);\r
2467                 },\r
2468 \r
2469                 compareBoundaryPoints : function(h, r) {\r
2470                         var t = this, sc = t.startContainer, so = t.startOffset, ec = t.endContainer, eo = t.endOffset;\r
2471 \r
2472                         // Check START_TO_START\r
2473                         if (h === 0)\r
2474                                 return t._compareBoundaryPoints(sc, so, sc, so);\r
2475 \r
2476                         // Check START_TO_END\r
2477                         if (h === 1)\r
2478                                 return t._compareBoundaryPoints(sc, so, ec, eo);\r
2479 \r
2480                         // Check END_TO_END\r
2481                         if (h === 2)\r
2482                                 return t._compareBoundaryPoints(ec, eo, ec, eo);\r
2483 \r
2484                         // Check END_TO_START\r
2485                         if (h === 3)\r
2486                                 return t._compareBoundaryPoints(ec, eo, sc, so);\r
2487                 },\r
2488 \r
2489                 deleteContents : function() {\r
2490                         this._traverse(DELETE);\r
2491                 },\r
2492 \r
2493                 extractContents : function() {\r
2494                         return this._traverse(EXTRACT);\r
2495                 },\r
2496 \r
2497                 cloneContents : function() {\r
2498                         return this._traverse(CLONE);\r
2499                 },\r
2500 \r
2501                 insertNode : function(n) {\r
2502                         var t = this, nn, o;\r
2503 \r
2504                         // Node is TEXT_NODE or CDATA\r
2505                         if (n.nodeType === 3 || n.nodeType === 4) {\r
2506                                 nn = t.startContainer.splitText(t.startOffset);\r
2507                                 t.startContainer.parentNode.insertBefore(n, nn);\r
2508                         } else {\r
2509                                 // Insert element node\r
2510                                 if (t.startContainer.childNodes.length > 0)\r
2511                                         o = t.startContainer.childNodes[t.startOffset];\r
2512 \r
2513                                 t.startContainer.insertBefore(n, o);\r
2514                         }\r
2515                 },\r
2516 \r
2517                 surroundContents : function(n) {\r
2518                         var t = this, f = t.extractContents();\r
2519 \r
2520                         t.insertNode(n);\r
2521                         n.appendChild(f);\r
2522                         t.selectNode(n);\r
2523                 },\r
2524 \r
2525                 cloneRange : function() {\r
2526                         var t = this;\r
2527 \r
2528                         return extend(new Range(t.dom), {\r
2529                                 startContainer : t.startContainer,\r
2530                                 startOffset : t.startOffset,\r
2531                                 endContainer : t.endContainer,\r
2532                                 endOffset : t.endOffset,\r
2533                                 collapsed : t.collapsed,\r
2534                                 commonAncestorContainer : t.commonAncestorContainer\r
2535                         });\r
2536                 },\r
2537 \r
2538 /*\r
2539                 detach : function() {\r
2540                         // Not implemented\r
2541                 },\r
2542 */\r
2543                 // Internal methods\r
2544 \r
2545                 _isCollapsed : function() {\r
2546                         return (this.startContainer == this.endContainer && this.startOffset == this.endOffset);\r
2547                 },\r
2548 \r
2549                 _compareBoundaryPoints : function (containerA, offsetA, containerB, offsetB) {\r
2550                         var c, offsetC, n, cmnRoot, childA, childB;\r
2551 \r
2552                         // In the first case the boundary-points have the same container. A is before B \r
2553                         // if its offset is less than the offset of B, A is equal to B if its offset is \r
2554                         // equal to the offset of B, and A is after B if its offset is greater than the \r
2555                         // offset of B.\r
2556                         if (containerA == containerB) {\r
2557                                 if (offsetA == offsetB) {\r
2558                                         return 0; // equal\r
2559                                 } else if (offsetA < offsetB) {\r
2560                                         return -1; // before\r
2561                                 } else {\r
2562                                         return 1; // after\r
2563                                 }\r
2564                         }\r
2565 \r
2566                         // In the second case a child node C of the container of A is an ancestor \r
2567                         // container of B. In this case, A is before B if the offset of A is less than or \r
2568                         // equal to the index of the child node C and A is after B otherwise.\r
2569                         c = containerB;\r
2570                         while (c && c.parentNode != containerA) {\r
2571                                 c = c.parentNode;\r
2572                         }\r
2573                         if (c) {\r
2574                                 offsetC = 0;\r
2575                                 n = containerA.firstChild;\r
2576 \r
2577                                 while (n != c && offsetC < offsetA) {\r
2578                                         offsetC++;\r
2579                                         n = n.nextSibling;\r
2580                                 }\r
2581 \r
2582                                 if (offsetA <= offsetC) {\r
2583                                         return -1; // before\r
2584                                 } else {\r
2585                                         return 1; // after\r
2586                                 }\r
2587                         }\r
2588 \r
2589                         // In the third case a child node C of the container of B is an ancestor container \r
2590                         // of A. In this case, A is before B if the index of the child node C is less than \r
2591                         // the offset of B and A is after B otherwise.\r
2592                         c = containerA;\r
2593                         while (c && c.parentNode != containerB) {\r
2594                                 c = c.parentNode;\r
2595                         }\r
2596 \r
2597                         if (c) {\r
2598                                 offsetC = 0;\r
2599                                 n = containerB.firstChild;\r
2600 \r
2601                                 while (n != c && offsetC < offsetB) {\r
2602                                         offsetC++;\r
2603                                         n = n.nextSibling;\r
2604                                 }\r
2605 \r
2606                                 if (offsetC < offsetB) {\r
2607                                         return -1; // before\r
2608                                 } else {\r
2609                                         return 1; // after\r
2610                                 }\r
2611                         }\r
2612 \r
2613                         // In the fourth case, none of three other cases hold: the containers of A and B \r
2614                         // are siblings or descendants of sibling nodes. In this case, A is before B if \r
2615                         // the container of A is before the container of B in a pre-order traversal of the\r
2616                         // Ranges' context tree and A is after B otherwise.\r
2617                         cmnRoot = this.dom.findCommonAncestor(containerA, containerB);\r
2618                         childA = containerA;\r
2619 \r
2620                         while (childA && childA.parentNode != cmnRoot) {\r
2621                                 childA = childA.parentNode;  \r
2622                         }\r
2623 \r
2624                         if (!childA) {\r
2625                                 childA = cmnRoot;\r
2626                         }\r
2627 \r
2628                         childB = containerB;\r
2629                         while (childB && childB.parentNode != cmnRoot) {\r
2630                                 childB = childB.parentNode;\r
2631                         }\r
2632 \r
2633                         if (!childB) {\r
2634                                 childB = cmnRoot;\r
2635                         }\r
2636 \r
2637                         if (childA == childB) {\r
2638                                 return 0; // equal\r
2639                         }\r
2640 \r
2641                         n = cmnRoot.firstChild;\r
2642                         while (n) {\r
2643                                 if (n == childA) {\r
2644                                         return -1; // before\r
2645                                 }\r
2646 \r
2647                                 if (n == childB) {\r
2648                                         return 1; // after\r
2649                                 }\r
2650 \r
2651                                 n = n.nextSibling;\r
2652                         }\r
2653                 },\r
2654 \r
2655                 _setEndPoint : function(st, n, o) {\r
2656                         var t = this, ec, sc;\r
2657 \r
2658                         if (st) {\r
2659                                 t.startContainer = n;\r
2660                                 t.startOffset = o;\r
2661                         } else {\r
2662                                 t.endContainer = n;\r
2663                                 t.endOffset = o;\r
2664                         }\r
2665 \r
2666                         // If one boundary-point of a Range is set to have a root container \r
2667                         // other than the current one for the Range, the Range is collapsed to \r
2668                         // the new position. This enforces the restriction that both boundary-\r
2669                         // points of a Range must have the same root container.\r
2670                         ec = t.endContainer;\r
2671                         while (ec.parentNode)\r
2672                                 ec = ec.parentNode;\r
2673 \r
2674                         sc = t.startContainer;\r
2675                         while (sc.parentNode)\r
2676                                 sc = sc.parentNode;\r
2677 \r
2678                         if (sc != ec) {\r
2679                                 t.collapse(st);\r
2680                         } else {\r
2681                                 // The start position of a Range is guaranteed to never be after the \r
2682                                 // end position. To enforce this restriction, if the start is set to \r
2683                                 // be at a position after the end, the Range is collapsed to that \r
2684                                 // position.\r
2685                                 if (t._compareBoundaryPoints(t.startContainer, t.startOffset, t.endContainer, t.endOffset) > 0)\r
2686                                         t.collapse(st);\r
2687                         }\r
2688 \r
2689                         t.collapsed = t._isCollapsed();\r
2690                         t.commonAncestorContainer = t.dom.findCommonAncestor(t.startContainer, t.endContainer);\r
2691                 },\r
2692 \r
2693                 // This code is heavily "inspired" by the Apache Xerces implementation. I hope they don't mind. :)\r
2694 \r
2695                 _traverse : function(how) {\r
2696                         var t = this, c, endContainerDepth = 0, startContainerDepth = 0, p, depthDiff, startNode, endNode, sp, ep;\r
2697 \r
2698                         if (t.startContainer == t.endContainer)\r
2699                                 return t._traverseSameContainer(how);\r
2700 \r
2701                         for (c = t.endContainer, p = c.parentNode; p != null; c = p, p = p.parentNode) {\r
2702                                 if (p == t.startContainer)\r
2703                                         return t._traverseCommonStartContainer(c, how);\r
2704 \r
2705                                 ++endContainerDepth;\r
2706                         }\r
2707 \r
2708                         for (c = t.startContainer, p = c.parentNode; p != null; c = p, p = p.parentNode) {\r
2709                                 if (p == t.endContainer)\r
2710                                         return t._traverseCommonEndContainer(c, how);\r
2711 \r
2712                                 ++startContainerDepth;\r
2713                         }\r
2714 \r
2715                         depthDiff = startContainerDepth - endContainerDepth;\r
2716 \r
2717                         startNode = t.startContainer;\r
2718                         while (depthDiff > 0) {\r
2719                                 startNode = startNode.parentNode;\r
2720                                 depthDiff--;\r
2721                         }\r
2722 \r
2723                         endNode = t.endContainer;\r
2724                         while (depthDiff < 0) {\r
2725                                 endNode = endNode.parentNode;\r
2726                                 depthDiff++;\r
2727                         }\r
2728 \r
2729                         // ascend the ancestor hierarchy until we have a common parent.\r
2730                         for (sp = startNode.parentNode, ep = endNode.parentNode; sp != ep; sp = sp.parentNode, ep = ep.parentNode) {\r
2731                                 startNode = sp;\r
2732                                 endNode = ep;\r
2733                         }\r
2734 \r
2735                         return t._traverseCommonAncestors(startNode, endNode, how);\r
2736                 },\r
2737 \r
2738                 _traverseSameContainer : function(how) {\r
2739                         var t = this, frag, s, sub, n, cnt, sibling, xferNode;\r
2740 \r
2741                         if (how != DELETE)\r
2742                                 frag = t.dom.doc.createDocumentFragment();\r
2743 \r
2744                         // If selection is empty, just return the fragment\r
2745                         if (t.startOffset == t.endOffset)\r
2746                                 return frag;\r
2747 \r
2748                         // Text node needs special case handling\r
2749                         if (t.startContainer.nodeType == 3 /* TEXT_NODE */) {\r
2750                                 // get the substring\r
2751                                 s = t.startContainer.nodeValue;\r
2752                                 sub = s.substring(t.startOffset, t.endOffset);\r
2753 \r
2754                                 // set the original text node to its new value\r
2755                                 if (how != CLONE) {\r
2756                                         t.startContainer.deleteData(t.startOffset, t.endOffset - t.startOffset);\r
2757 \r
2758                                         // Nothing is partially selected, so collapse to start point\r
2759                                         t.collapse(true);\r
2760                                 }\r
2761 \r
2762                                 if (how == DELETE)\r
2763                                         return null;\r
2764 \r
2765                                 frag.appendChild(t.dom.doc.createTextNode(sub));\r
2766                                 return frag;\r
2767                         }\r
2768 \r
2769                         // Copy nodes between the start/end offsets.\r
2770                         n = getSelectedNode(t.startContainer, t.startOffset);\r
2771                         cnt = t.endOffset - t.startOffset;\r
2772 \r
2773                         while (cnt > 0) {\r
2774                                 sibling = n.nextSibling;\r
2775                                 xferNode = t._traverseFullySelected(n, how);\r
2776 \r
2777                                 if (frag)\r
2778                                         frag.appendChild( xferNode );\r
2779 \r
2780                                 --cnt;\r
2781                                 n = sibling;\r
2782                         }\r
2783 \r
2784                         // Nothing is partially selected, so collapse to start point\r
2785                         if (how != CLONE)\r
2786                                 t.collapse(true);\r
2787 \r
2788                         return frag;\r
2789                 },\r
2790 \r
2791                 _traverseCommonStartContainer : function(endAncestor, how) {\r
2792                         var t = this, frag, n, endIdx, cnt, sibling, xferNode;\r
2793 \r
2794                         if (how != DELETE)\r
2795                                 frag = t.dom.doc.createDocumentFragment();\r
2796 \r
2797                         n = t._traverseRightBoundary(endAncestor, how);\r
2798 \r
2799                         if (frag)\r
2800                                 frag.appendChild(n);\r
2801 \r
2802                         endIdx = indexOf(endAncestor, t.startContainer);\r
2803                         cnt = endIdx - t.startOffset;\r
2804 \r
2805                         if (cnt <= 0) {\r
2806                                 // Collapse to just before the endAncestor, which \r
2807                                 // is partially selected.\r
2808                                 if (how != CLONE) {\r
2809                                         t.setEndBefore(endAncestor);\r
2810                                         t.collapse(false);\r
2811                                 }\r
2812 \r
2813                                 return frag;\r
2814                         }\r
2815 \r
2816                         n = endAncestor.previousSibling;\r
2817                         while (cnt > 0) {\r
2818                                 sibling = n.previousSibling;\r
2819                                 xferNode = t._traverseFullySelected(n, how);\r
2820 \r
2821                                 if (frag)\r
2822                                         frag.insertBefore(xferNode, frag.firstChild);\r
2823 \r
2824                                 --cnt;\r
2825                                 n = sibling;\r
2826                         }\r
2827 \r
2828                         // Collapse to just before the endAncestor, which \r
2829                         // is partially selected.\r
2830                         if (how != CLONE) {\r
2831                                 t.setEndBefore(endAncestor);\r
2832                                 t.collapse(false);\r
2833                         }\r
2834 \r
2835                         return frag;\r
2836                 },\r
2837 \r
2838                 _traverseCommonEndContainer : function(startAncestor, how) {\r
2839                         var t = this, frag, startIdx, n, cnt, sibling, xferNode;\r
2840 \r
2841                         if (how != DELETE)\r
2842                                 frag = t.dom.doc.createDocumentFragment();\r
2843 \r
2844                         n = t._traverseLeftBoundary(startAncestor, how);\r
2845                         if (frag)\r
2846                                 frag.appendChild(n);\r
2847 \r
2848                         startIdx = indexOf(startAncestor, t.endContainer);\r
2849                         ++startIdx;  // Because we already traversed it....\r
2850 \r
2851                         cnt = t.endOffset - startIdx;\r
2852                         n = startAncestor.nextSibling;\r
2853                         while (cnt > 0) {\r
2854                                 sibling = n.nextSibling;\r
2855                                 xferNode = t._traverseFullySelected(n, how);\r
2856 \r
2857                                 if (frag)\r
2858                                         frag.appendChild(xferNode);\r
2859 \r
2860                                 --cnt;\r
2861                                 n = sibling;\r
2862                         }\r
2863 \r
2864                         if (how != CLONE) {\r
2865                                 t.setStartAfter(startAncestor);\r
2866                                 t.collapse(true);\r
2867                         }\r
2868 \r
2869                         return frag;\r
2870                 },\r
2871 \r
2872                 _traverseCommonAncestors : function(startAncestor, endAncestor, how) {\r
2873                         var t = this, n, frag, commonParent, startOffset, endOffset, cnt, sibling, nextSibling;\r
2874 \r
2875                         if (how != DELETE)\r
2876                                 frag = t.dom.doc.createDocumentFragment();\r
2877 \r
2878                         n = t._traverseLeftBoundary(startAncestor, how);\r
2879                         if (frag)\r
2880                                 frag.appendChild(n);\r
2881 \r
2882                         commonParent = startAncestor.parentNode;\r
2883                         startOffset = indexOf(startAncestor, commonParent);\r
2884                         endOffset = indexOf(endAncestor, commonParent);\r
2885                         ++startOffset;\r
2886 \r
2887                         cnt = endOffset - startOffset;\r
2888                         sibling = startAncestor.nextSibling;\r
2889 \r
2890                         while (cnt > 0) {\r
2891                                 nextSibling = sibling.nextSibling;\r
2892                                 n = t._traverseFullySelected(sibling, how);\r
2893 \r
2894                                 if (frag)\r
2895                                         frag.appendChild(n);\r
2896 \r
2897                                 sibling = nextSibling;\r
2898                                 --cnt;\r
2899                         }\r
2900 \r
2901                         n = t._traverseRightBoundary(endAncestor, how);\r
2902 \r
2903                         if (frag)\r
2904                                 frag.appendChild(n);\r
2905 \r
2906                         if (how != CLONE) {\r
2907                                 t.setStartAfter(startAncestor);\r
2908                                 t.collapse(true);\r
2909                         }\r
2910 \r
2911                         return frag;\r
2912                 },\r
2913 \r
2914                 _traverseRightBoundary : function(root, how) {\r
2915                         var t = this, next = getSelectedNode(t.endContainer, t.endOffset - 1), parent, clonedParent, prevSibling, clonedChild, clonedGrandParent;\r
2916                         var isFullySelected = next != t.endContainer;\r
2917 \r
2918                         if (next == root)\r
2919                                 return t._traverseNode(next, isFullySelected, false, how);\r
2920 \r
2921                         parent = next.parentNode;\r
2922                         clonedParent = t._traverseNode(parent, false, false, how);\r
2923 \r
2924                         while (parent != null) {\r
2925                                 while (next != null) {\r
2926                                         prevSibling = next.previousSibling;\r
2927                                         clonedChild = t._traverseNode(next, isFullySelected, false, how);\r
2928 \r
2929                                         if (how != DELETE)\r
2930                                                 clonedParent.insertBefore(clonedChild, clonedParent.firstChild);\r
2931 \r
2932                                         isFullySelected = true;\r
2933                                         next = prevSibling;\r
2934                                 }\r
2935 \r
2936                                 if (parent == root)\r
2937                                         return clonedParent;\r
2938 \r
2939                                 next = parent.previousSibling;\r
2940                                 parent = parent.parentNode;\r
2941 \r
2942                                 clonedGrandParent = t._traverseNode(parent, false, false, how);\r
2943 \r
2944                                 if (how != DELETE)\r
2945                                         clonedGrandParent.appendChild(clonedParent);\r
2946 \r
2947                                 clonedParent = clonedGrandParent;\r
2948                         }\r
2949 \r
2950                         // should never occur\r
2951                         return null;\r
2952                 },\r
2953 \r
2954                 _traverseLeftBoundary : function(root, how) {\r
2955                         var t = this, next = getSelectedNode(t.startContainer, t.startOffset);\r
2956                         var isFullySelected = next != t.startContainer, parent, clonedParent, nextSibling, clonedChild, clonedGrandParent;\r
2957 \r
2958                         if (next == root)\r
2959                                 return t._traverseNode(next, isFullySelected, true, how);\r
2960 \r
2961                         parent = next.parentNode;\r
2962                         clonedParent = t._traverseNode(parent, false, true, how);\r
2963 \r
2964                         while (parent != null) {\r
2965                                 while (next != null) {\r
2966                                         nextSibling = next.nextSibling;\r
2967                                         clonedChild = t._traverseNode(next, isFullySelected, true, how);\r
2968 \r
2969                                         if (how != DELETE)\r
2970                                                 clonedParent.appendChild(clonedChild);\r
2971 \r
2972                                         isFullySelected = true;\r
2973                                         next = nextSibling;\r
2974                                 }\r
2975 \r
2976                                 if (parent == root)\r
2977                                         return clonedParent;\r
2978 \r
2979                                 next = parent.nextSibling;\r
2980                                 parent = parent.parentNode;\r
2981 \r
2982                                 clonedGrandParent = t._traverseNode(parent, false, true, how);\r
2983 \r
2984                                 if (how != DELETE)\r
2985                                         clonedGrandParent.appendChild(clonedParent);\r
2986 \r
2987                                 clonedParent = clonedGrandParent;\r
2988                         }\r
2989 \r
2990                         // should never occur\r
2991                         return null;\r
2992                 },\r
2993 \r
2994                 _traverseNode : function(n, isFullySelected, isLeft, how) {\r
2995                         var t = this, txtValue, newNodeValue, oldNodeValue, offset, newNode;\r
2996 \r
2997                         if (isFullySelected)\r
2998                                 return t._traverseFullySelected(n, how);\r
2999 \r
3000                         if (n.nodeType == 3 /* TEXT_NODE */) {\r
3001                                 txtValue = n.nodeValue;\r
3002 \r
3003                                 if (isLeft) {\r
3004                                         offset = t.startOffset;\r
3005                                         newNodeValue = txtValue.substring(offset);\r
3006                                         oldNodeValue = txtValue.substring(0, offset);\r
3007                                 } else {\r
3008                                         offset = t.endOffset;\r
3009                                         newNodeValue = txtValue.substring(0, offset);\r
3010                                         oldNodeValue = txtValue.substring(offset);\r
3011                                 }\r
3012 \r
3013                                 if (how != CLONE)\r
3014                                         n.nodeValue = oldNodeValue;\r
3015 \r
3016                                 if (how == DELETE)\r
3017                                         return null;\r
3018 \r
3019                                 newNode = n.cloneNode(false);\r
3020                                 newNode.nodeValue = newNodeValue;\r
3021 \r
3022                                 return newNode;\r
3023                         }\r
3024 \r
3025                         if (how == DELETE)\r
3026                                 return null;\r
3027 \r
3028                         return n.cloneNode(false);\r
3029                 },\r
3030 \r
3031                 _traverseFullySelected : function(n, how) {\r
3032                         var t = this;\r
3033 \r
3034                         if (how != DELETE)\r
3035                                 return how == CLONE ? n.cloneNode(true) : n;\r
3036 \r
3037                         n.parentNode.removeChild(n);\r
3038                         return null;\r
3039                 }\r
3040         });\r
3041 \r
3042         ns.Range = Range;\r
3043 })(tinymce.dom);\r
3044 (function() {\r
3045         function Selection(selection) {\r
3046                 var t = this, invisibleChar = '\uFEFF', range, lastIERng;\r
3047 \r
3048                 function compareRanges(rng1, rng2) {\r
3049                         if (rng1 && rng2) {\r
3050                                 // Both are control ranges and the selected element matches\r
3051                                 if (rng1.item && rng2.item && rng1.item(0) === rng2.item(0))\r
3052                                         return 1;\r
3053 \r
3054                                 // Both are text ranges and the range matches\r
3055                                 if (rng1.isEqual && rng2.isEqual && rng2.isEqual(rng1))\r
3056                                         return 1;\r
3057                         }\r
3058 \r
3059                         return 0;\r
3060                 };\r
3061 \r
3062                 function getRange() {\r
3063                         var dom = selection.dom, ieRange = selection.getRng(), domRange = dom.createRng(), startPos, endPos, element, sc, ec, collapsed;\r
3064 \r
3065                         function findIndex(element) {\r
3066                                 var nl = element.parentNode.childNodes, i;\r
3067 \r
3068                                 for (i = nl.length - 1; i >= 0; i--) {\r
3069                                         if (nl[i] == element)\r
3070                                                 return i;\r
3071                                 }\r
3072 \r
3073                                 return -1;\r
3074                         };\r
3075 \r
3076                         function findEndPoint(start) {\r
3077                                 var rng = ieRange.duplicate(), parent, i, nl, n, offset = 0, index = 0, pos, tmpRng;\r
3078 \r
3079                                 // Insert marker character\r
3080                                 rng.collapse(start);\r
3081                                 parent = rng.parentElement();\r
3082                                 rng.pasteHTML(invisibleChar); // Needs to be a pasteHTML instead of .text = since IE has a bug with nodeValue\r
3083 \r
3084                                 // Find marker character\r
3085                                 nl = parent.childNodes;\r
3086                                 for (i = 0; i < nl.length; i++) {\r
3087                                         n = nl[i];\r
3088 \r
3089                                         // Calculate node index excluding text node fragmentation\r
3090                                         if (i > 0 && (n.nodeType !== 3 || nl[i - 1].nodeType !== 3))\r
3091                                                 index++;\r
3092 \r
3093                                         // If text node then calculate offset\r
3094                                         if (n.nodeType === 3) {\r
3095                                                 // Look for marker\r
3096                                                 pos = n.nodeValue.indexOf(invisibleChar);\r
3097                                                 if (pos !== -1) {\r
3098                                                         offset += pos;\r
3099                                                         break;\r
3100                                                 }\r
3101 \r
3102                                                 offset += n.nodeValue.length;\r
3103                                         } else\r
3104                                                 offset = 0;\r
3105                                 }\r
3106 \r
3107                                 // Remove marker character\r
3108                                 rng.moveStart('character', -1);\r
3109                                 rng.text = '';\r
3110 \r
3111                                 return {index : index, offset : offset, parent : parent};\r
3112                         };\r
3113 \r
3114                         // If selection is outside the current document just return an empty range\r
3115                         element = ieRange.item ? ieRange.item(0) : ieRange.parentElement();\r
3116                         if (element.ownerDocument != dom.doc)\r
3117                                 return domRange;\r
3118 \r
3119                         // Handle control selection or text selection of a image\r
3120                         if (ieRange.item || !element.hasChildNodes()) {\r
3121                                 domRange.setStart(element.parentNode, findIndex(element));\r
3122                                 domRange.setEnd(domRange.startContainer, domRange.startOffset + 1);\r
3123 \r
3124                                 return domRange;\r
3125                         }\r
3126 \r
3127                         // Check collapsed state\r
3128                         collapsed = selection.isCollapsed();\r
3129 \r
3130                         // Find start and end pos index and offset\r
3131                         startPos = findEndPoint(true);\r
3132                         endPos = findEndPoint(false);\r
3133 \r
3134                         // Normalize the elements to avoid fragmented dom\r
3135                         startPos.parent.normalize();\r
3136                         endPos.parent.normalize();\r
3137 \r
3138                         // Set start container and offset\r
3139                         sc = startPos.parent.childNodes[Math.min(startPos.index, startPos.parent.childNodes.length - 1)];\r
3140 \r
3141                         if (sc.nodeType != 3)\r
3142                                 domRange.setStart(startPos.parent, startPos.index);\r
3143                         else\r
3144                                 domRange.setStart(startPos.parent.childNodes[startPos.index], startPos.offset);\r
3145 \r
3146                         // Set end container and offset\r
3147                         ec = endPos.parent.childNodes[Math.min(endPos.index, endPos.parent.childNodes.length - 1)];\r
3148 \r
3149                         if (ec.nodeType != 3) {\r
3150                                 if (!collapsed)\r
3151                                         endPos.index++;\r
3152 \r
3153                                 domRange.setEnd(endPos.parent, endPos.index);\r
3154                         } else\r
3155                                 domRange.setEnd(endPos.parent.childNodes[endPos.index], endPos.offset);\r
3156 \r
3157                         // If not collapsed then make sure offsets are valid\r
3158                         if (!collapsed) {\r
3159                                 sc = domRange.startContainer;\r
3160                                 if (sc.nodeType == 1)\r
3161                                         domRange.setStart(sc, Math.min(domRange.startOffset, sc.childNodes.length));\r
3162 \r
3163                                 ec = domRange.endContainer;\r
3164                                 if (ec.nodeType == 1)\r
3165                                         domRange.setEnd(ec, Math.min(domRange.endOffset, ec.childNodes.length));\r
3166                         }\r
3167 \r
3168                         // Restore selection to new range\r
3169                         t.addRange(domRange);\r
3170 \r
3171                         return domRange;\r
3172                 };\r
3173 \r
3174                 this.addRange = function(rng) {\r
3175                         var ieRng, body = selection.dom.doc.body, startPos, endPos, sc, so, ec, eo;\r
3176 \r
3177                         // Setup some shorter versions\r
3178                         sc = rng.startContainer;\r
3179                         so = rng.startOffset;\r
3180                         ec = rng.endContainer;\r
3181                         eo = rng.endOffset;\r
3182                         ieRng = body.createTextRange();\r
3183 \r
3184                         // Find element\r
3185                         sc = sc.nodeType == 1 ? sc.childNodes[Math.min(so, sc.childNodes.length - 1)] : sc;\r
3186                         ec = ec.nodeType == 1 ? ec.childNodes[Math.min(so == eo ? eo : eo - 1, ec.childNodes.length - 1)] : ec;\r
3187 \r
3188                         // Single element selection\r
3189                         if (sc == ec && sc.nodeType == 1) {\r
3190                                 // Make control selection for some elements\r
3191                                 if (/^(IMG|TABLE)$/.test(sc.nodeName) && so != eo) {\r
3192                                         ieRng = body.createControlRange();\r
3193                                         ieRng.addElement(sc);\r
3194                                 } else {\r
3195                                         ieRng = body.createTextRange();\r
3196 \r
3197                                         // Padd empty elements with invisible character\r
3198                                         if (!sc.hasChildNodes() && sc.canHaveHTML)\r
3199                                                 sc.innerHTML = invisibleChar;\r
3200 \r
3201                                         // Select element contents\r
3202                                         ieRng.moveToElementText(sc);\r
3203 \r
3204                                         // If it's only containing a padding remove it so the caret remains\r
3205                                         if (sc.innerHTML == invisibleChar) {\r
3206                                                 ieRng.collapse(true);\r
3207                                                 sc.removeChild(sc.firstChild);\r
3208                                         }\r
3209                                 }\r
3210 \r
3211                                 if (so == eo)\r
3212                                         ieRng.collapse(eo <= rng.endContainer.childNodes.length - 1);\r
3213 \r
3214                                 ieRng.select();\r
3215 \r
3216                                 return;\r
3217                         }\r
3218 \r
3219                         function getCharPos(container, offset) {\r
3220                                 var nodeVal, rng, pos;\r
3221 \r
3222                                 if (container.nodeType != 3)\r
3223                                         return -1;\r
3224 \r
3225                                 nodeVal = container.nodeValue;\r
3226                                 rng = body.createTextRange();\r
3227 \r
3228                                 // Insert marker at offset position\r
3229                                 container.nodeValue = nodeVal.substring(0, offset) + invisibleChar + nodeVal.substring(offset);\r
3230 \r
3231                                 // Find char pos of marker and remove it\r
3232                                 rng.moveToElementText(container.parentNode);\r
3233                                 rng.findText(invisibleChar);\r
3234                                 pos = Math.abs(rng.moveStart('character', -0xFFFFF));\r
3235                                 container.nodeValue = nodeVal;\r
3236 \r
3237                                 return pos;\r
3238                         };\r
3239 \r
3240                         // Collapsed range\r
3241                         if (rng.collapsed) {\r
3242                                 pos = getCharPos(sc, so);\r
3243 \r
3244                                 ieRng = body.createTextRange();\r
3245                                 ieRng.move('character', pos);\r
3246                                 ieRng.select();\r
3247 \r
3248                                 return;\r
3249                         } else {\r
3250                                 // If same text container\r
3251                                 if (sc == ec && sc.nodeType == 3) {\r
3252                                         startPos = getCharPos(sc, so);\r
3253 \r
3254                                         ieRng.move('character', startPos);\r
3255                                         ieRng.moveEnd('character', eo - so);\r
3256                                         ieRng.select();\r
3257 \r
3258                                         return;\r
3259                                 }\r
3260 \r
3261                                 // Get caret positions\r
3262                                 startPos = getCharPos(sc, so);\r
3263                                 endPos = getCharPos(ec, eo);\r
3264                                 ieRng = body.createTextRange();\r
3265 \r
3266                                 // Move start of range to start character position or start element\r
3267                                 if (startPos == -1) {\r
3268                                         ieRng.moveToElementText(sc);\r
3269                                         startPos = 0;\r
3270                                 } else\r
3271                                         ieRng.move('character', startPos);\r
3272 \r
3273                                 // Move end of range to end character position or end element\r
3274                                 tmpRng = body.createTextRange();\r
3275 \r
3276                                 if (endPos == -1)\r
3277                                         tmpRng.moveToElementText(ec);\r
3278                                 else\r
3279                                         tmpRng.move('character', endPos);\r
3280 \r
3281                                 ieRng.setEndPoint('EndToEnd', tmpRng);\r
3282                                 ieRng.select();\r
3283 \r
3284                                 return;\r
3285                         }\r
3286                 };\r
3287 \r
3288                 this.getRangeAt = function() {\r
3289                         // Setup new range if the cache is empty\r
3290                         if (!range || !compareRanges(lastIERng, selection.getRng())) {\r
3291                                 range = getRange();\r
3292 \r
3293                                 // Store away text range for next call\r
3294                                 lastIERng = selection.getRng();\r
3295                         }\r
3296 \r
3297                         // Return cached range\r
3298                         return range;\r
3299                 };\r
3300 \r
3301                 this.destroy = function() {\r
3302                         // Destroy cached range and last IE range to avoid memory leaks\r
3303                         lastIERng = range = null;\r
3304                 };\r
3305         };\r
3306 \r
3307         // Expose the selection object\r
3308         tinymce.dom.TridentSelection = Selection;\r
3309 })();\r
3310 \r
3311 /*\r
3312  * Sizzle CSS Selector Engine - v1.0\r
3313  *  Copyright 2009, The Dojo Foundation\r
3314  *  Released under the MIT, BSD, and GPL Licenses.\r
3315  *  More information: http://sizzlejs.com/\r
3316  */\r
3317 (function(){\r
3318 \r
3319 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,\r
3320         done = 0,\r
3321         toString = Object.prototype.toString,\r
3322         hasDuplicate = false;\r
3323 \r
3324 var Sizzle = function(selector, context, results, seed) {\r
3325         results = results || [];\r
3326         var origContext = context = context || document;\r
3327 \r
3328         if ( context.nodeType !== 1 && context.nodeType !== 9 ) {\r
3329                 return [];\r
3330         }\r
3331         \r
3332         if ( !selector || typeof selector !== "string" ) {\r
3333                 return results;\r
3334         }\r
3335 \r
3336         var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context);\r
3337         \r
3338         // Reset the position of the chunker regexp (start from head)\r
3339         chunker.lastIndex = 0;\r
3340         \r
3341         while ( (m = chunker.exec(selector)) !== null ) {\r
3342                 parts.push( m[1] );\r
3343                 \r
3344                 if ( m[2] ) {\r
3345                         extra = RegExp.rightContext;\r
3346                         break;\r
3347                 }\r
3348         }\r
3349 \r
3350         if ( parts.length > 1 && origPOS.exec( selector ) ) {\r
3351                 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {\r
3352                         set = posProcess( parts[0] + parts[1], context );\r
3353                 } else {\r
3354                         set = Expr.relative[ parts[0] ] ?\r
3355                                 [ context ] :\r
3356                                 Sizzle( parts.shift(), context );\r
3357 \r
3358                         while ( parts.length ) {\r
3359                                 selector = parts.shift();\r
3360 \r
3361                                 if ( Expr.relative[ selector ] )\r
3362                                         selector += parts.shift();\r
3363 \r
3364                                 set = posProcess( selector, set );\r
3365                         }\r
3366                 }\r
3367         } else {\r
3368                 // Take a shortcut and set the context if the root selector is an ID\r
3369                 // (but not if it'll be faster if the inner selector is an ID)\r
3370                 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&\r
3371                                 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {\r
3372                         var ret = Sizzle.find( parts.shift(), context, contextXML );\r
3373                         context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];\r
3374                 }\r
3375 \r
3376                 if ( context ) {\r
3377                         var ret = seed ?\r
3378                                 { expr: parts.pop(), set: makeArray(seed) } :\r
3379                                 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );\r
3380                         set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;\r
3381 \r
3382                         if ( parts.length > 0 ) {\r
3383                                 checkSet = makeArray(set);\r
3384                         } else {\r
3385                                 prune = false;\r
3386                         }\r
3387 \r
3388                         while ( parts.length ) {\r
3389                                 var cur = parts.pop(), pop = cur;\r
3390 \r
3391                                 if ( !Expr.relative[ cur ] ) {\r
3392                                         cur = "";\r
3393                                 } else {\r
3394                                         pop = parts.pop();\r
3395                                 }\r
3396 \r
3397                                 if ( pop == null ) {\r
3398                                         pop = context;\r
3399                                 }\r
3400 \r
3401                                 Expr.relative[ cur ]( checkSet, pop, contextXML );\r
3402                         }\r
3403                 } else {\r
3404                         checkSet = parts = [];\r
3405                 }\r
3406         }\r
3407 \r
3408         if ( !checkSet ) {\r
3409                 checkSet = set;\r
3410         }\r
3411 \r
3412         if ( !checkSet ) {\r
3413                 throw "Syntax error, unrecognized expression: " + (cur || selector);\r
3414         }\r
3415 \r
3416         if ( toString.call(checkSet) === "[object Array]" ) {\r
3417                 if ( !prune ) {\r
3418                         results.push.apply( results, checkSet );\r
3419                 } else if ( context && context.nodeType === 1 ) {\r
3420                         for ( var i = 0; checkSet[i] != null; i++ ) {\r
3421                                 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {\r
3422                                         results.push( set[i] );\r
3423                                 }\r
3424                         }\r
3425                 } else {\r
3426                         for ( var i = 0; checkSet[i] != null; i++ ) {\r
3427                                 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {\r
3428                                         results.push( set[i] );\r
3429                                 }\r
3430                         }\r
3431                 }\r
3432         } else {\r
3433                 makeArray( checkSet, results );\r
3434         }\r
3435 \r
3436         if ( extra ) {\r
3437                 Sizzle( extra, origContext, results, seed );\r
3438                 Sizzle.uniqueSort( results );\r
3439         }\r
3440 \r
3441         return results;\r
3442 };\r
3443 \r
3444 Sizzle.uniqueSort = function(results){\r
3445         if ( sortOrder ) {\r
3446                 hasDuplicate = false;\r
3447                 results.sort(sortOrder);\r
3448 \r
3449                 if ( hasDuplicate ) {\r
3450                         for ( var i = 1; i < results.length; i++ ) {\r
3451                                 if ( results[i] === results[i-1] ) {\r
3452                                         results.splice(i--, 1);\r
3453                                 }\r
3454                         }\r
3455                 }\r
3456         }\r
3457 };\r
3458 \r
3459 Sizzle.matches = function(expr, set){\r
3460         return Sizzle(expr, null, null, set);\r
3461 };\r
3462 \r
3463 Sizzle.find = function(expr, context, isXML){\r
3464         var set, match;\r
3465 \r
3466         if ( !expr ) {\r
3467                 return [];\r
3468         }\r
3469 \r
3470         for ( var i = 0, l = Expr.order.length; i < l; i++ ) {\r
3471                 var type = Expr.order[i], match;\r
3472                 \r
3473                 if ( (match = Expr.match[ type ].exec( expr )) ) {\r
3474                         var left = RegExp.leftContext;\r
3475 \r
3476                         if ( left.substr( left.length - 1 ) !== "\\" ) {\r
3477                                 match[1] = (match[1] || "").replace(/\\/g, "");\r
3478                                 set = Expr.find[ type ]( match, context, isXML );\r
3479                                 if ( set != null ) {\r
3480                                         expr = expr.replace( Expr.match[ type ], "" );\r
3481                                         break;\r
3482                                 }\r
3483                         }\r
3484                 }\r
3485         }\r
3486 \r
3487         if ( !set ) {\r
3488                 set = context.getElementsByTagName("*");\r
3489         }\r
3490 \r
3491         return {set: set, expr: expr};\r
3492 };\r
3493 \r
3494 Sizzle.filter = function(expr, set, inplace, not){\r
3495         var old = expr, result = [], curLoop = set, match, anyFound,\r
3496                 isXMLFilter = set && set[0] && isXML(set[0]);\r
3497 \r
3498         while ( expr && set.length ) {\r
3499                 for ( var type in Expr.filter ) {\r
3500                         if ( (match = Expr.match[ type ].exec( expr )) != null ) {\r
3501                                 var filter = Expr.filter[ type ], found, item;\r
3502                                 anyFound = false;\r
3503 \r
3504                                 if ( curLoop == result ) {\r
3505                                         result = [];\r
3506                                 }\r
3507 \r
3508                                 if ( Expr.preFilter[ type ] ) {\r
3509                                         match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );\r
3510 \r
3511                                         if ( !match ) {\r
3512                                                 anyFound = found = true;\r
3513                                         } else if ( match === true ) {\r
3514                                                 continue;\r
3515                                         }\r
3516                                 }\r
3517 \r
3518                                 if ( match ) {\r
3519                                         for ( var i = 0; (item = curLoop[i]) != null; i++ ) {\r
3520                                                 if ( item ) {\r
3521                                                         found = filter( item, match, i, curLoop );\r
3522                                                         var pass = not ^ !!found;\r
3523 \r
3524                                                         if ( inplace && found != null ) {\r
3525                                                                 if ( pass ) {\r
3526                                                                         anyFound = true;\r
3527                                                                 } else {\r
3528                                                                         curLoop[i] = false;\r
3529                                                                 }\r
3530                                                         } else if ( pass ) {\r
3531                                                                 result.push( item );\r
3532                                                                 anyFound = true;\r
3533                                                         }\r
3534                                                 }\r
3535                                         }\r
3536                                 }\r
3537 \r
3538                                 if ( found !== undefined ) {\r
3539                                         if ( !inplace ) {\r
3540                                                 curLoop = result;\r
3541                                         }\r
3542 \r
3543                                         expr = expr.replace( Expr.match[ type ], "" );\r
3544 \r
3545                                         if ( !anyFound ) {\r
3546                                                 return [];\r
3547                                         }\r
3548 \r
3549                                         break;\r
3550                                 }\r
3551                         }\r
3552                 }\r
3553 \r
3554                 // Improper expression\r
3555                 if ( expr == old ) {\r
3556                         if ( anyFound == null ) {\r
3557                                 throw "Syntax error, unrecognized expression: " + expr;\r
3558                         } else {\r
3559                                 break;\r
3560                         }\r
3561                 }\r
3562 \r
3563                 old = expr;\r
3564         }\r
3565 \r
3566         return curLoop;\r
3567 };\r
3568 \r
3569 var Expr = Sizzle.selectors = {\r
3570         order: [ "ID", "NAME", "TAG" ],\r
3571         match: {\r
3572                 ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,\r
3573                 CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,\r
3574                 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,\r
3575                 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,\r
3576                 TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,\r
3577                 CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,\r
3578                 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,\r
3579                 PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/\r
3580         },\r
3581         attrMap: {\r
3582                 "class": "className",\r
3583                 "for": "htmlFor"\r
3584         },\r
3585         attrHandle: {\r
3586                 href: function(elem){\r
3587                         return elem.getAttribute("href");\r
3588                 }\r
3589         },\r
3590         relative: {\r
3591                 "+": function(checkSet, part, isXML){\r
3592                         var isPartStr = typeof part === "string",\r
3593                                 isTag = isPartStr && !/\W/.test(part),\r
3594                                 isPartStrNotTag = isPartStr && !isTag;\r
3595 \r
3596                         if ( isTag && !isXML ) {\r
3597                                 part = part.toUpperCase();\r
3598                         }\r
3599 \r
3600                         for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {\r
3601                                 if ( (elem = checkSet[i]) ) {\r
3602                                         while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}\r
3603 \r
3604                                         checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?\r
3605                                                 elem || false :\r
3606                                                 elem === part;\r
3607                                 }\r
3608                         }\r
3609 \r
3610                         if ( isPartStrNotTag ) {\r
3611                                 Sizzle.filter( part, checkSet, true );\r
3612                         }\r
3613                 },\r
3614                 ">": function(checkSet, part, isXML){\r
3615                         var isPartStr = typeof part === "string";\r
3616 \r
3617                         if ( isPartStr && !/\W/.test(part) ) {\r
3618                                 part = isXML ? part : part.toUpperCase();\r
3619 \r
3620                                 for ( var i = 0, l = checkSet.length; i < l; i++ ) {\r
3621                                         var elem = checkSet[i];\r
3622                                         if ( elem ) {\r
3623                                                 var parent = elem.parentNode;\r
3624                                                 checkSet[i] = parent.nodeName === part ? parent : false;\r
3625                                         }\r
3626                                 }\r
3627                         } else {\r
3628                                 for ( var i = 0, l = checkSet.length; i < l; i++ ) {\r
3629                                         var elem = checkSet[i];\r
3630                                         if ( elem ) {\r
3631                                                 checkSet[i] = isPartStr ?\r
3632                                                         elem.parentNode :\r
3633                                                         elem.parentNode === part;\r
3634                                         }\r
3635                                 }\r
3636 \r
3637                                 if ( isPartStr ) {\r
3638                                         Sizzle.filter( part, checkSet, true );\r
3639                                 }\r
3640                         }\r
3641                 },\r
3642                 "": function(checkSet, part, isXML){\r
3643                         var doneName = done++, checkFn = dirCheck;\r
3644 \r
3645                         if ( !part.match(/\W/) ) {\r
3646                                 var nodeCheck = part = isXML ? part : part.toUpperCase();\r
3647                                 checkFn = dirNodeCheck;\r
3648                         }\r
3649 \r
3650                         checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);\r
3651                 },\r
3652                 "~": function(checkSet, part, isXML){\r
3653                         var doneName = done++, checkFn = dirCheck;\r
3654 \r
3655                         if ( typeof part === "string" && !part.match(/\W/) ) {\r
3656                                 var nodeCheck = part = isXML ? part : part.toUpperCase();\r
3657                                 checkFn = dirNodeCheck;\r
3658                         }\r
3659 \r
3660                         checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);\r
3661                 }\r
3662         },\r
3663         find: {\r
3664                 ID: function(match, context, isXML){\r
3665                         if ( typeof context.getElementById !== "undefined" && !isXML ) {\r
3666                                 var m = context.getElementById(match[1]);\r
3667                                 return m ? [m] : [];\r
3668                         }\r
3669                 },\r
3670                 NAME: function(match, context, isXML){\r
3671                         if ( typeof context.getElementsByName !== "undefined" ) {\r
3672                                 var ret = [], results = context.getElementsByName(match[1]);\r
3673 \r
3674                                 for ( var i = 0, l = results.length; i < l; i++ ) {\r
3675                                         if ( results[i].getAttribute("name") === match[1] ) {\r
3676                                                 ret.push( results[i] );\r
3677                                         }\r
3678                                 }\r
3679 \r
3680                                 return ret.length === 0 ? null : ret;\r
3681                         }\r
3682                 },\r
3683                 TAG: function(match, context){\r
3684                         return context.getElementsByTagName(match[1]);\r
3685                 }\r
3686         },\r
3687         preFilter: {\r
3688                 CLASS: function(match, curLoop, inplace, result, not, isXML){\r
3689                         match = " " + match[1].replace(/\\/g, "") + " ";\r
3690 \r
3691                         if ( isXML ) {\r
3692                                 return match;\r
3693                         }\r
3694 \r
3695                         for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {\r
3696                                 if ( elem ) {\r
3697                                         if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {\r
3698                                                 if ( !inplace )\r
3699                                                         result.push( elem );\r
3700                                         } else if ( inplace ) {\r
3701                                                 curLoop[i] = false;\r
3702                                         }\r
3703                                 }\r
3704                         }\r
3705 \r
3706                         return false;\r
3707                 },\r
3708                 ID: function(match){\r
3709                         return match[1].replace(/\\/g, "");\r
3710                 },\r
3711                 TAG: function(match, curLoop){\r
3712                         for ( var i = 0; curLoop[i] === false; i++ ){}\r
3713                         return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();\r
3714                 },\r
3715                 CHILD: function(match){\r
3716                         if ( match[1] == "nth" ) {\r
3717                                 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'\r
3718                                 var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(\r
3719                                         match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||\r
3720                                         !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);\r
3721 \r
3722                                 // calculate the numbers (first)n+(last) including if they are negative\r
3723                                 match[2] = (test[1] + (test[2] || 1)) - 0;\r
3724                                 match[3] = test[3] - 0;\r
3725                         }\r
3726 \r
3727                         // TODO: Move to normal caching system\r
3728                         match[0] = done++;\r
3729 \r
3730                         return match;\r
3731                 },\r
3732                 ATTR: function(match, curLoop, inplace, result, not, isXML){\r
3733                         var name = match[1].replace(/\\/g, "");\r
3734                         \r
3735                         if ( !isXML && Expr.attrMap[name] ) {\r
3736                                 match[1] = Expr.attrMap[name];\r
3737                         }\r
3738 \r
3739                         if ( match[2] === "~=" ) {\r
3740                                 match[4] = " " + match[4] + " ";\r
3741                         }\r
3742 \r
3743                         return match;\r
3744                 },\r
3745                 PSEUDO: function(match, curLoop, inplace, result, not){\r
3746                         if ( match[1] === "not" ) {\r
3747                                 // If we're dealing with a complex expression, or a simple one\r
3748                                 if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) {\r
3749                                         match[3] = Sizzle(match[3], null, null, curLoop);\r
3750                                 } else {\r
3751                                         var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);\r
3752                                         if ( !inplace ) {\r
3753                                                 result.push.apply( result, ret );\r
3754                                         }\r
3755                                         return false;\r
3756                                 }\r
3757                         } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {\r
3758                                 return true;\r
3759                         }\r
3760                         \r
3761                         return match;\r
3762                 },\r
3763                 POS: function(match){\r
3764                         match.unshift( true );\r
3765                         return match;\r
3766                 }\r
3767         },\r
3768         filters: {\r
3769                 enabled: function(elem){\r
3770                         return elem.disabled === false && elem.type !== "hidden";\r
3771                 },\r
3772                 disabled: function(elem){\r
3773                         return elem.disabled === true;\r
3774                 },\r
3775                 checked: function(elem){\r
3776                         return elem.checked === true;\r
3777                 },\r
3778                 selected: function(elem){\r
3779                         // Accessing this property makes selected-by-default\r
3780                         // options in Safari work properly\r
3781                         elem.parentNode.selectedIndex;\r
3782                         return elem.selected === true;\r
3783                 },\r
3784                 parent: function(elem){\r
3785                         return !!elem.firstChild;\r
3786                 },\r
3787                 empty: function(elem){\r
3788                         return !elem.firstChild;\r
3789                 },\r
3790                 has: function(elem, i, match){\r
3791                         return !!Sizzle( match[3], elem ).length;\r
3792                 },\r
3793                 header: function(elem){\r
3794                         return /h\d/i.test( elem.nodeName );\r
3795                 },\r
3796                 text: function(elem){\r
3797                         return "text" === elem.type;\r
3798                 },\r
3799                 radio: function(elem){\r
3800                         return "radio" === elem.type;\r
3801                 },\r
3802                 checkbox: function(elem){\r
3803                         return "checkbox" === elem.type;\r
3804                 },\r
3805                 file: function(elem){\r
3806                         return "file" === elem.type;\r
3807                 },\r
3808                 password: function(elem){\r
3809                         return "password" === elem.type;\r
3810                 },\r
3811                 submit: function(elem){\r
3812                         return "submit" === elem.type;\r
3813                 },\r
3814                 image: function(elem){\r
3815                         return "image" === elem.type;\r
3816                 },\r
3817                 reset: function(elem){\r
3818                         return "reset" === elem.type;\r
3819                 },\r
3820                 button: function(elem){\r
3821                         return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";\r
3822                 },\r
3823                 input: function(elem){\r
3824                         return /input|select|textarea|button/i.test(elem.nodeName);\r
3825                 }\r
3826         },\r
3827         setFilters: {\r
3828                 first: function(elem, i){\r
3829                         return i === 0;\r
3830                 },\r
3831                 last: function(elem, i, match, array){\r
3832                         return i === array.length - 1;\r
3833                 },\r
3834                 even: function(elem, i){\r
3835                         return i % 2 === 0;\r
3836                 },\r
3837                 odd: function(elem, i){\r
3838                         return i % 2 === 1;\r
3839                 },\r
3840                 lt: function(elem, i, match){\r
3841                         return i < match[3] - 0;\r
3842                 },\r
3843                 gt: function(elem, i, match){\r
3844                         return i > match[3] - 0;\r
3845                 },\r
3846                 nth: function(elem, i, match){\r
3847                         return match[3] - 0 == i;\r
3848                 },\r
3849                 eq: function(elem, i, match){\r
3850                         return match[3] - 0 == i;\r
3851                 }\r
3852         },\r
3853         filter: {\r
3854                 PSEUDO: function(elem, match, i, array){\r
3855                         var name = match[1], filter = Expr.filters[ name ];\r
3856 \r
3857                         if ( filter ) {\r
3858                                 return filter( elem, i, match, array );\r
3859                         } else if ( name === "contains" ) {\r
3860                                 return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;\r
3861                         } else if ( name === "not" ) {\r
3862                                 var not = match[3];\r
3863 \r
3864                                 for ( var i = 0, l = not.length; i < l; i++ ) {\r
3865                                         if ( not[i] === elem ) {\r
3866                                                 return false;\r
3867                                         }\r
3868                                 }\r
3869 \r
3870                                 return true;\r
3871                         }\r
3872                 },\r
3873                 CHILD: function(elem, match){\r
3874                         var type = match[1], node = elem;\r
3875                         switch (type) {\r
3876                                 case 'only':\r
3877                                 case 'first':\r
3878                                         while (node = node.previousSibling)  {\r
3879                                                 if ( node.nodeType === 1 ) return false;\r
3880                                         }\r
3881                                         if ( type == 'first') return true;\r
3882                                         node = elem;\r
3883                                 case 'last':\r
3884                                         while (node = node.nextSibling)  {\r
3885                                                 if ( node.nodeType === 1 ) return false;\r
3886                                         }\r
3887                                         return true;\r
3888                                 case 'nth':\r
3889                                         var first = match[2], last = match[3];\r
3890 \r
3891                                         if ( first == 1 && last == 0 ) {\r
3892                                                 return true;\r
3893                                         }\r
3894                                         \r
3895                                         var doneName = match[0],\r
3896                                                 parent = elem.parentNode;\r
3897         \r
3898                                         if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {\r
3899                                                 var count = 0;\r
3900                                                 for ( node = parent.firstChild; node; node = node.nextSibling ) {\r
3901                                                         if ( node.nodeType === 1 ) {\r
3902                                                                 node.nodeIndex = ++count;\r
3903                                                         }\r
3904                                                 } \r
3905                                                 parent.sizcache = doneName;\r
3906                                         }\r
3907                                         \r
3908                                         var diff = elem.nodeIndex - last;\r
3909                                         if ( first == 0 ) {\r
3910                                                 return diff == 0;\r
3911                                         } else {\r
3912                                                 return ( diff % first == 0 && diff / first >= 0 );\r
3913                                         }\r
3914                         }\r
3915                 },\r
3916                 ID: function(elem, match){\r
3917                         return elem.nodeType === 1 && elem.getAttribute("id") === match;\r
3918                 },\r
3919                 TAG: function(elem, match){\r
3920                         return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;\r
3921                 },\r
3922                 CLASS: function(elem, match){\r
3923                         return (" " + (elem.className || elem.getAttribute("class")) + " ")\r
3924                                 .indexOf( match ) > -1;\r
3925                 },\r
3926                 ATTR: function(elem, match){\r
3927                         var name = match[1],\r
3928                                 result = Expr.attrHandle[ name ] ?\r
3929                                         Expr.attrHandle[ name ]( elem ) :\r
3930                                         elem[ name ] != null ?\r
3931                                                 elem[ name ] :\r
3932                                                 elem.getAttribute( name ),\r
3933                                 value = result + "",\r
3934                                 type = match[2],\r
3935                                 check = match[4];\r
3936 \r
3937                         return result == null ?\r
3938                                 type === "!=" :\r
3939                                 type === "=" ?\r
3940                                 value === check :\r
3941                                 type === "*=" ?\r
3942                                 value.indexOf(check) >= 0 :\r
3943                                 type === "~=" ?\r
3944                                 (" " + value + " ").indexOf(check) >= 0 :\r
3945                                 !check ?\r
3946                                 value && result !== false :\r
3947                                 type === "!=" ?\r
3948                                 value != check :\r
3949                                 type === "^=" ?\r
3950                                 value.indexOf(check) === 0 :\r
3951                                 type === "$=" ?\r
3952                                 value.substr(value.length - check.length) === check :\r
3953                                 type === "|=" ?\r
3954                                 value === check || value.substr(0, check.length + 1) === check + "-" :\r
3955                                 false;\r
3956                 },\r
3957                 POS: function(elem, match, i, array){\r
3958                         var name = match[2], filter = Expr.setFilters[ name ];\r
3959 \r
3960                         if ( filter ) {\r
3961                                 return filter( elem, i, match, array );\r
3962                         }\r
3963                 }\r
3964         }\r
3965 };\r
3966 \r
3967 var origPOS = Expr.match.POS;\r
3968 \r
3969 for ( var type in Expr.match ) {\r
3970         Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );\r
3971 }\r
3972 \r
3973 var makeArray = function(array, results) {\r
3974         array = Array.prototype.slice.call( array );\r
3975 \r
3976         if ( results ) {\r
3977                 results.push.apply( results, array );\r
3978                 return results;\r
3979         }\r
3980         \r
3981         return array;\r
3982 };\r
3983 \r
3984 // Perform a simple check to determine if the browser is capable of\r
3985 // converting a NodeList to an array using builtin methods.\r
3986 try {\r
3987         Array.prototype.slice.call( document.documentElement.childNodes );\r
3988 \r
3989 // Provide a fallback method if it does not work\r
3990 } catch(e){\r
3991         makeArray = function(array, results) {\r
3992                 var ret = results || [];\r
3993 \r
3994                 if ( toString.call(array) === "[object Array]" ) {\r
3995                         Array.prototype.push.apply( ret, array );\r
3996                 } else {\r
3997                         if ( typeof array.length === "number" ) {\r
3998                                 for ( var i = 0, l = array.length; i < l; i++ ) {\r
3999                                         ret.push( array[i] );\r
4000                                 }\r
4001                         } else {\r
4002                                 for ( var i = 0; array[i]; i++ ) {\r
4003                                         ret.push( array[i] );\r
4004                                 }\r
4005                         }\r
4006                 }\r
4007 \r
4008                 return ret;\r
4009         };\r
4010 }\r
4011 \r
4012 var sortOrder;\r
4013 \r
4014 if ( document.documentElement.compareDocumentPosition ) {\r
4015         sortOrder = function( a, b ) {\r
4016                 var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;\r
4017                 if ( ret === 0 ) {\r
4018                         hasDuplicate = true;\r
4019                 }\r
4020                 return ret;\r
4021         };\r
4022 } else if ( "sourceIndex" in document.documentElement ) {\r
4023         sortOrder = function( a, b ) {\r
4024                 var ret = a.sourceIndex - b.sourceIndex;\r
4025                 if ( ret === 0 ) {\r
4026                         hasDuplicate = true;\r
4027                 }\r
4028                 return ret;\r
4029         };\r
4030 } else if ( document.createRange ) {\r
4031         sortOrder = function( a, b ) {\r
4032                 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();\r
4033                 aRange.setStart(a, 0);\r
4034                 aRange.setEnd(a, 0);\r
4035                 bRange.setStart(b, 0);\r
4036                 bRange.setEnd(b, 0);\r
4037                 var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);\r
4038                 if ( ret === 0 ) {\r
4039                         hasDuplicate = true;\r
4040                 }\r
4041                 return ret;\r
4042         };\r
4043 }\r
4044 \r
4045 // Check to see if the browser returns elements by name when\r
4046 // querying by getElementById (and provide a workaround)\r
4047 (function(){\r
4048         // We're going to inject a fake input element with a specified name\r
4049         var form = document.createElement("div"),\r
4050                 id = "script" + (new Date).getTime();\r
4051         form.innerHTML = "<a name='" + id + "'/>";\r
4052 \r
4053         // Inject it into the root element, check its status, and remove it quickly\r
4054         var root = document.documentElement;\r
4055         root.insertBefore( form, root.firstChild );\r
4056 \r
4057         // The workaround has to do additional checks after a getElementById\r
4058         // Which slows things down for other browsers (hence the branching)\r
4059         if ( !!document.getElementById( id ) ) {\r
4060                 Expr.find.ID = function(match, context, isXML){\r
4061                         if ( typeof context.getElementById !== "undefined" && !isXML ) {\r
4062                                 var m = context.getElementById(match[1]);\r
4063                                 return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];\r
4064                         }\r
4065                 };\r
4066 \r
4067                 Expr.filter.ID = function(elem, match){\r
4068                         var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");\r
4069                         return elem.nodeType === 1 && node && node.nodeValue === match;\r
4070                 };\r
4071         }\r
4072 \r
4073         root.removeChild( form );\r
4074 })();\r
4075 \r
4076 (function(){\r
4077         // Check to see if the browser returns only elements\r
4078         // when doing getElementsByTagName("*")\r
4079 \r
4080         // Create a fake element\r
4081         var div = document.createElement("div");\r
4082         div.appendChild( document.createComment("") );\r
4083 \r
4084         // Make sure no comments are found\r
4085         if ( div.getElementsByTagName("*").length > 0 ) {\r
4086                 Expr.find.TAG = function(match, context){\r
4087                         var results = context.getElementsByTagName(match[1]);\r
4088 \r
4089                         // Filter out possible comments\r
4090                         if ( match[1] === "*" ) {\r
4091                                 var tmp = [];\r
4092 \r
4093                                 for ( var i = 0; results[i]; i++ ) {\r
4094                                         if ( results[i].nodeType === 1 ) {\r
4095                                                 tmp.push( results[i] );\r
4096                                         }\r
4097                                 }\r
4098 \r
4099                                 results = tmp;\r
4100                         }\r
4101 \r
4102                         return results;\r
4103                 };\r
4104         }\r
4105 \r
4106         // Check to see if an attribute returns normalized href attributes\r
4107         div.innerHTML = "<a href='#'></a>";\r
4108         if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&\r
4109                         div.firstChild.getAttribute("href") !== "#" ) {\r
4110                 Expr.attrHandle.href = function(elem){\r
4111                         return elem.getAttribute("href", 2);\r
4112                 };\r
4113         }\r
4114 })();\r
4115 \r
4116 if ( document.querySelectorAll ) (function(){\r
4117         var oldSizzle = Sizzle, div = document.createElement("div");\r
4118         div.innerHTML = "<p class='TEST'></p>";\r
4119 \r
4120         // Safari can't handle uppercase or unicode characters when\r
4121         // in quirks mode.\r
4122         if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {\r
4123                 return;\r
4124         }\r
4125         \r
4126         Sizzle = function(query, context, extra, seed){\r
4127                 context = context || document;\r
4128 \r
4129                 // Only use querySelectorAll on non-XML documents\r
4130                 // (ID selectors don't work in non-HTML documents)\r
4131                 if ( !seed && context.nodeType === 9 && !isXML(context) ) {\r
4132                         try {\r
4133                                 return makeArray( context.querySelectorAll(query), extra );\r
4134                         } catch(e){}\r
4135                 }\r
4136                 \r
4137                 return oldSizzle(query, context, extra, seed);\r
4138         };\r
4139 \r
4140         for ( var prop in oldSizzle ) {\r
4141                 Sizzle[ prop ] = oldSizzle[ prop ];\r
4142         }\r
4143 })();\r
4144 \r
4145 if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){\r
4146         var div = document.createElement("div");\r
4147         div.innerHTML = "<div class='test e'></div><div class='test'></div>";\r
4148 \r
4149         // Opera can't find a second classname (in 9.6)\r
4150         if ( div.getElementsByClassName("e").length === 0 )\r
4151                 return;\r
4152 \r
4153         // Safari caches class attributes, doesn't catch changes (in 3.2)\r
4154         div.lastChild.className = "e";\r
4155 \r
4156         if ( div.getElementsByClassName("e").length === 1 )\r
4157                 return;\r
4158 \r
4159         Expr.order.splice(1, 0, "CLASS");\r
4160         Expr.find.CLASS = function(match, context, isXML) {\r
4161                 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {\r
4162                         return context.getElementsByClassName(match[1]);\r
4163                 }\r
4164         };\r
4165 })();\r
4166 \r
4167 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\r
4168         var sibDir = dir == "previousSibling" && !isXML;\r
4169         for ( var i = 0, l = checkSet.length; i < l; i++ ) {\r
4170                 var elem = checkSet[i];\r
4171                 if ( elem ) {\r
4172                         if ( sibDir && elem.nodeType === 1 ){\r
4173                                 elem.sizcache = doneName;\r
4174                                 elem.sizset = i;\r
4175                         }\r
4176                         elem = elem[dir];\r
4177                         var match = false;\r
4178 \r
4179                         while ( elem ) {\r
4180                                 if ( elem.sizcache === doneName ) {\r
4181                                         match = checkSet[elem.sizset];\r
4182                                         break;\r
4183                                 }\r
4184 \r
4185                                 if ( elem.nodeType === 1 && !isXML ){\r
4186                                         elem.sizcache = doneName;\r
4187                                         elem.sizset = i;\r
4188                                 }\r
4189 \r
4190                                 if ( elem.nodeName === cur ) {\r
4191                                         match = elem;\r
4192                                         break;\r
4193                                 }\r
4194 \r
4195                                 elem = elem[dir];\r
4196                         }\r
4197 \r
4198                         checkSet[i] = match;\r
4199                 }\r
4200         }\r
4201 }\r
4202 \r
4203 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\r
4204         var sibDir = dir == "previousSibling" && !isXML;\r
4205         for ( var i = 0, l = checkSet.length; i < l; i++ ) {\r
4206                 var elem = checkSet[i];\r
4207                 if ( elem ) {\r
4208                         if ( sibDir && elem.nodeType === 1 ) {\r
4209                                 elem.sizcache = doneName;\r
4210                                 elem.sizset = i;\r
4211                         }\r
4212                         elem = elem[dir];\r
4213                         var match = false;\r
4214 \r
4215                         while ( elem ) {\r
4216                                 if ( elem.sizcache === doneName ) {\r
4217                                         match = checkSet[elem.sizset];\r
4218                                         break;\r
4219                                 }\r
4220 \r
4221                                 if ( elem.nodeType === 1 ) {\r
4222                                         if ( !isXML ) {\r
4223                                                 elem.sizcache = doneName;\r
4224                                                 elem.sizset = i;\r
4225                                         }\r
4226                                         if ( typeof cur !== "string" ) {\r
4227                                                 if ( elem === cur ) {\r
4228                                                         match = true;\r
4229                                                         break;\r
4230                                                 }\r
4231 \r
4232                                         } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {\r
4233                                                 match = elem;\r
4234                                                 break;\r
4235                                         }\r
4236                                 }\r
4237 \r
4238                                 elem = elem[dir];\r
4239                         }\r
4240 \r
4241                         checkSet[i] = match;\r
4242                 }\r
4243         }\r
4244 }\r
4245 \r
4246 var contains = document.compareDocumentPosition ?  function(a, b){\r
4247         return a.compareDocumentPosition(b) & 16;\r
4248 } : function(a, b){\r
4249         return a !== b && (a.contains ? a.contains(b) : true);\r
4250 };\r
4251 \r
4252 var isXML = function(elem){\r
4253         return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||\r
4254                 !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";\r
4255 };\r
4256 \r
4257 var posProcess = function(selector, context){\r
4258         var tmpSet = [], later = "", match,\r
4259                 root = context.nodeType ? [context] : context;\r
4260 \r
4261         // Position selectors must be done after the filter\r
4262         // And so must :not(positional) so we move all PSEUDOs to the end\r
4263         while ( (match = Expr.match.PSEUDO.exec( selector )) ) {\r
4264                 later += match[0];\r
4265                 selector = selector.replace( Expr.match.PSEUDO, "" );\r
4266         }\r
4267 \r
4268         selector = Expr.relative[selector] ? selector + "*" : selector;\r
4269 \r
4270         for ( var i = 0, l = root.length; i < l; i++ ) {\r
4271                 Sizzle( selector, root[i], tmpSet );\r
4272         }\r
4273 \r
4274         return Sizzle.filter( later, tmpSet );\r
4275 };\r
4276 \r
4277 // EXPOSE\r
4278 \r
4279 window.tinymce.dom.Sizzle = Sizzle;\r
4280 \r
4281 })();\r
4282 \r
4283 (function(tinymce) {\r
4284         // Shorten names\r
4285         var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event;\r
4286 \r
4287         tinymce.create('static tinymce.dom.Event', {\r
4288                 inits : [],\r
4289                 events : [],\r
4290 \r
4291 \r
4292                 add : function(o, n, f, s) {\r
4293                         var cb, t = this, el = t.events, r;\r
4294 \r
4295                         // Handle array\r
4296                         if (o && o.hasOwnProperty && o instanceof Array) {\r
4297                                 r = [];\r
4298 \r
4299                                 each(o, function(o) {\r
4300                                         o = DOM.get(o);\r
4301                                         r.push(t.add(o, n, f, s));\r
4302                                 });\r
4303 \r
4304                                 return r;\r
4305                         }\r
4306 \r
4307                         o = DOM.get(o);\r
4308 \r
4309                         if (!o)\r
4310                                 return;\r
4311 \r
4312                         // Setup event callback\r
4313                         cb = function(e) {\r
4314                                 e = e || window.event;\r
4315 \r
4316                                 // Patch in target in IE it's W3C valid\r
4317                                 if (e && !e.target && isIE)\r
4318                                         e.target = e.srcElement;\r
4319 \r
4320                                 if (!s)\r
4321                                         return f(e);\r
4322 \r
4323                                 return f.call(s, e);\r
4324                         };\r
4325 \r
4326                         if (n == 'unload') {\r
4327                                 tinymce.unloads.unshift({func : cb});\r
4328                                 return cb;\r
4329                         }\r
4330 \r
4331                         if (n == 'init') {\r
4332                                 if (t.domLoaded)\r
4333                                         cb();\r
4334                                 else\r
4335                                         t.inits.push(cb);\r
4336 \r
4337                                 return cb;\r
4338                         }\r
4339 \r
4340                         // Store away listener reference\r
4341                         el.push({\r
4342                                 obj : o,\r
4343                                 name : n,\r
4344                                 func : f,\r
4345                                 cfunc : cb,\r
4346                                 scope : s\r
4347                         });\r
4348 \r
4349                         t._add(o, n, cb);\r
4350 \r
4351                         return f;\r
4352                 },\r
4353 \r
4354                 remove : function(o, n, f) {\r
4355                         var t = this, a = t.events, s = false, r;\r
4356 \r
4357                         // Handle array\r
4358                         if (o && o.hasOwnProperty && o instanceof Array) {\r
4359                                 r = [];\r
4360 \r
4361                                 each(o, function(o) {\r
4362                                         o = DOM.get(o);\r
4363                                         r.push(t.remove(o, n, f));\r
4364                                 });\r
4365 \r
4366                                 return r;\r
4367                         }\r
4368 \r
4369                         o = DOM.get(o);\r
4370 \r
4371                         each(a, function(e, i) {\r
4372                                 if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) {\r
4373                                         a.splice(i, 1);\r
4374                                         t._remove(o, n, e.cfunc);\r
4375                                         s = true;\r
4376                                         return false;\r
4377                                 }\r
4378                         });\r
4379 \r
4380                         return s;\r
4381                 },\r
4382 \r
4383                 clear : function(o) {\r
4384                         var t = this, a = t.events, i, e;\r
4385 \r
4386                         if (o) {\r
4387                                 o = DOM.get(o);\r
4388 \r
4389                                 for (i = a.length - 1; i >= 0; i--) {\r
4390                                         e = a[i];\r
4391 \r
4392                                         if (e.obj === o) {\r
4393                                                 t._remove(e.obj, e.name, e.cfunc);\r
4394                                                 e.obj = e.cfunc = null;\r
4395                                                 a.splice(i, 1);\r
4396                                         }\r
4397                                 }\r
4398                         }\r
4399                 },\r
4400 \r
4401 \r
4402                 cancel : function(e) {\r
4403                         if (!e)\r
4404                                 return false;\r
4405 \r
4406                         this.stop(e);\r
4407                         return this.prevent(e);\r
4408                 },\r
4409 \r
4410                 stop : function(e) {\r
4411                         if (e.stopPropagation)\r
4412                                 e.stopPropagation();\r
4413                         else\r
4414                                 e.cancelBubble = true;\r
4415 \r
4416                         return false;\r
4417                 },\r
4418 \r
4419                 prevent : function(e) {\r
4420                         if (e.preventDefault)\r
4421                                 e.preventDefault();\r
4422                         else\r
4423                                 e.returnValue = false;\r
4424 \r
4425                         return false;\r
4426                 },\r
4427 \r
4428                 _unload : function() {\r
4429                         var t = Event;\r
4430 \r
4431                         each(t.events, function(e, i) {\r
4432                                 t._remove(e.obj, e.name, e.cfunc);\r
4433                                 e.obj = e.cfunc = null;\r
4434                         });\r
4435 \r
4436                         t.events = [];\r
4437                         t = null;\r
4438                 },\r
4439 \r
4440                 _add : function(o, n, f) {\r
4441                         if (o.attachEvent)\r
4442                                 o.attachEvent('on' + n, f);\r
4443                         else if (o.addEventListener)\r
4444                                 o.addEventListener(n, f, false);\r
4445                         else\r
4446                                 o['on' + n] = f;\r
4447                 },\r
4448 \r
4449                 _remove : function(o, n, f) {\r
4450                         if (o) {\r
4451                                 try {\r
4452                                         if (o.detachEvent)\r
4453                                                 o.detachEvent('on' + n, f);\r
4454                                         else if (o.removeEventListener)\r
4455                                                 o.removeEventListener(n, f, false);\r
4456                                         else\r
4457                                                 o['on' + n] = null;\r
4458                                 } catch (ex) {\r
4459                                         // Might fail with permission denined on IE so we just ignore that\r
4460                                 }\r
4461                         }\r
4462                 },\r
4463 \r
4464                 _pageInit : function() {\r
4465                         var e = Event;\r
4466 \r
4467                         // Keep it from running more than once\r
4468                         if (e.domLoaded)\r
4469                                 return;\r
4470 \r
4471                         e._remove(window, 'DOMContentLoaded', e._pageInit);\r
4472                         e.domLoaded = true;\r
4473 \r
4474                         each(e.inits, function(c) {\r
4475                                 c();\r
4476                         });\r
4477 \r
4478                         e.inits = [];\r
4479                 },\r
4480 \r
4481                 _wait : function() {\r
4482                         // No need since the document is already loaded\r
4483                         if (window.tinyMCE_GZ && tinyMCE_GZ.loaded) {\r
4484                                 Event.domLoaded = 1;\r
4485                                 return;\r
4486                         }\r
4487 \r
4488                         // Use IE method\r
4489                         if (document.attachEvent) {\r
4490                                 document.attachEvent("onreadystatechange", function() {\r
4491                                         if (document.readyState === "complete") {\r
4492                                                 document.detachEvent("onreadystatechange", arguments.callee);\r
4493                                                 Event._pageInit();\r
4494                                         }\r
4495                                 });\r
4496 \r
4497                                 if (document.documentElement.doScroll && window == window.top) {\r
4498                                         (function() {\r
4499                                                 if (Event.domLoaded)\r
4500                                                         return;\r
4501 \r
4502                                                 try {\r
4503                                                         // If IE is used, use the trick by Diego Perini\r
4504                                                         // http://javascript.nwbox.com/IEContentLoaded/\r
4505                                                         document.documentElement.doScroll("left");\r
4506                                                 } catch (ex) {\r
4507                                                         setTimeout(arguments.callee, 0);\r
4508                                                         return;\r
4509                                                 }\r
4510 \r
4511                                                 Event._pageInit();\r
4512                                         })();\r
4513                                 }\r
4514                         } else if (document.addEventListener)\r
4515                                 Event._add(window, 'DOMContentLoaded', Event._pageInit, Event);\r
4516 \r
4517                         Event._add(window, 'load', Event._pageInit, Event);\r
4518                 }\r
4519 \r
4520                 });\r
4521 \r
4522         // Shorten name\r
4523         Event = tinymce.dom.Event;\r
4524 \r
4525         // Dispatch DOM content loaded event for IE and Safari\r
4526         Event._wait();\r
4527         tinymce.addUnload(Event._unload);\r
4528 })(tinymce);\r
4529 (function(tinymce) {\r
4530         var each = tinymce.each;\r
4531 \r
4532         tinymce.create('tinymce.dom.Element', {\r
4533                 Element : function(id, s) {\r
4534                         var t = this, dom, el;\r
4535 \r
4536                         s = s || {};\r
4537                         t.id = id;\r
4538                         t.dom = dom = s.dom || tinymce.DOM;\r
4539                         t.settings = s;\r
4540 \r
4541                         // Only IE leaks DOM references, this is a lot faster\r
4542                         if (!tinymce.isIE)\r
4543                                 el = t.dom.get(t.id);\r
4544 \r
4545                         each([\r
4546                                 'getPos',\r
4547                                 'getRect',\r
4548                                 'getParent',\r
4549                                 'add',\r
4550                                 'setStyle',\r
4551                                 'getStyle',\r
4552                                 'setStyles',\r
4553                                 'setAttrib',\r
4554                                 'setAttribs',\r
4555                                 'getAttrib',\r
4556                                 'addClass',\r
4557                                 'removeClass',\r
4558                                 'hasClass',\r
4559                                 'getOuterHTML',\r
4560                                 'setOuterHTML',\r
4561                                 'remove',\r
4562                                 'show',\r
4563                                 'hide',\r
4564                                 'isHidden',\r
4565                                 'setHTML',\r
4566                                 'get'\r
4567                         ], function(k) {\r
4568                                 t[k] = function() {\r
4569                                         var a = [id], i;\r
4570 \r
4571                                         for (i = 0; i < arguments.length; i++)\r
4572                                                 a.push(arguments[i]);\r
4573 \r
4574                                         a = dom[k].apply(dom, a);\r
4575                                         t.update(k);\r
4576 \r
4577                                         return a;\r
4578                                 };\r
4579                         });\r
4580                 },\r
4581 \r
4582                 on : function(n, f, s) {\r
4583                         return tinymce.dom.Event.add(this.id, n, f, s);\r
4584                 },\r
4585 \r
4586                 getXY : function() {\r
4587                         return {\r
4588                                 x : parseInt(this.getStyle('left')),\r
4589                                 y : parseInt(this.getStyle('top'))\r
4590                         };\r
4591                 },\r
4592 \r
4593                 getSize : function() {\r
4594                         var n = this.dom.get(this.id);\r
4595 \r
4596                         return {\r
4597                                 w : parseInt(this.getStyle('width') || n.clientWidth),\r
4598                                 h : parseInt(this.getStyle('height') || n.clientHeight)\r
4599                         };\r
4600                 },\r
4601 \r
4602                 moveTo : function(x, y) {\r
4603                         this.setStyles({left : x, top : y});\r
4604                 },\r
4605 \r
4606                 moveBy : function(x, y) {\r
4607                         var p = this.getXY();\r
4608 \r
4609                         this.moveTo(p.x + x, p.y + y);\r
4610                 },\r
4611 \r
4612                 resizeTo : function(w, h) {\r
4613                         this.setStyles({width : w, height : h});\r
4614                 },\r
4615 \r
4616                 resizeBy : function(w, h) {\r
4617                         var s = this.getSize();\r
4618 \r
4619                         this.resizeTo(s.w + w, s.h + h);\r
4620                 },\r
4621 \r
4622                 update : function(k) {\r
4623                         var t = this, b, dom = t.dom;\r
4624 \r
4625                         if (tinymce.isIE6 && t.settings.blocker) {\r
4626                                 k = k || '';\r
4627 \r
4628                                 // Ignore getters\r
4629                                 if (k.indexOf('get') === 0 || k.indexOf('has') === 0 || k.indexOf('is') === 0)\r
4630                                         return;\r
4631 \r
4632                                 // Remove blocker on remove\r
4633                                 if (k == 'remove') {\r
4634                                         dom.remove(t.blocker);\r
4635                                         return;\r
4636                                 }\r
4637 \r
4638                                 if (!t.blocker) {\r
4639                                         t.blocker = dom.uniqueId();\r
4640                                         b = dom.add(t.settings.container || dom.getRoot(), 'iframe', {id : t.blocker, style : 'position:absolute;', frameBorder : 0, src : 'javascript:""'});\r
4641                                         dom.setStyle(b, 'opacity', 0);\r
4642                                 } else\r
4643                                         b = dom.get(t.blocker);\r
4644 \r
4645                                 dom.setStyle(b, 'left', t.getStyle('left', 1));\r
4646                                 dom.setStyle(b, 'top', t.getStyle('top', 1));\r
4647                                 dom.setStyle(b, 'width', t.getStyle('width', 1));\r
4648                                 dom.setStyle(b, 'height', t.getStyle('height', 1));\r
4649                                 dom.setStyle(b, 'display', t.getStyle('display', 1));\r
4650                                 dom.setStyle(b, 'zIndex', parseInt(t.getStyle('zIndex', 1) || 0) - 1);\r
4651                         }\r
4652                 }\r
4653 \r
4654                 });\r
4655 })(tinymce);\r
4656 (function(tinymce) {\r
4657         function trimNl(s) {\r
4658                 return s.replace(/[\n\r]+/g, '');\r
4659         };\r
4660 \r
4661         // Shorten names\r
4662         var is = tinymce.is, isIE = tinymce.isIE, each = tinymce.each;\r
4663 \r
4664         tinymce.create('tinymce.dom.Selection', {\r
4665                 Selection : function(dom, win, serializer) {\r
4666                         var t = this;\r
4667 \r
4668                         t.dom = dom;\r
4669                         t.win = win;\r
4670                         t.serializer = serializer;\r
4671 \r
4672                         // Add events\r
4673                         each([\r
4674                                 'onBeforeSetContent',\r
4675                                 'onBeforeGetContent',\r
4676                                 'onSetContent',\r
4677                                 'onGetContent'\r
4678                         ], function(e) {\r
4679                                 t[e] = new tinymce.util.Dispatcher(t);\r
4680                         });\r
4681 \r
4682                         // No W3C Range support\r
4683                         if (!t.win.getSelection)\r
4684                                 t.tridentSel = new tinymce.dom.TridentSelection(t);\r
4685 \r
4686                         // Prevent leaks\r
4687                         tinymce.addUnload(t.destroy, t);\r
4688                 },\r
4689 \r
4690                 getContent : function(s) {\r
4691                         var t = this, r = t.getRng(), e = t.dom.create("body"), se = t.getSel(), wb, wa, n;\r
4692 \r
4693                         s = s || {};\r
4694                         wb = wa = '';\r
4695                         s.get = true;\r
4696                         s.format = s.format || 'html';\r
4697                         t.onBeforeGetContent.dispatch(t, s);\r
4698 \r
4699                         if (s.format == 'text')\r
4700                                 return t.isCollapsed() ? '' : (r.text || (se.toString ? se.toString() : ''));\r
4701 \r
4702                         if (r.cloneContents) {\r
4703                                 n = r.cloneContents();\r
4704 \r
4705                                 if (n)\r
4706                                         e.appendChild(n);\r
4707                         } else if (is(r.item) || is(r.htmlText))\r
4708                                 e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText;\r
4709                         else\r
4710                                 e.innerHTML = r.toString();\r
4711 \r
4712                         // Keep whitespace before and after\r
4713                         if (/^\s/.test(e.innerHTML))\r
4714                                 wb = ' ';\r
4715 \r
4716                         if (/\s+$/.test(e.innerHTML))\r
4717                                 wa = ' ';\r
4718 \r
4719                         s.getInner = true;\r
4720 \r
4721                         s.content = t.isCollapsed() ? '' : wb + t.serializer.serialize(e, s) + wa;\r
4722                         t.onGetContent.dispatch(t, s);\r
4723 \r
4724                         return s.content;\r
4725                 },\r
4726 \r
4727                 setContent : function(h, s) {\r
4728                         var t = this, r = t.getRng(), c, d = t.win.document;\r
4729 \r
4730                         s = s || {format : 'html'};\r
4731                         s.set = true;\r
4732                         h = s.content = t.dom.processHTML(h);\r
4733 \r
4734                         // Dispatch before set content event\r
4735                         t.onBeforeSetContent.dispatch(t, s);\r
4736                         h = s.content;\r
4737 \r
4738                         if (r.insertNode) {\r
4739                                 // Make caret marker since insertNode places the caret in the beginning of text after insert\r
4740                                 h += '<span id="__caret">_</span>';\r
4741 \r
4742                                 // Delete and insert new node\r
4743                                 r.deleteContents();\r
4744                                 r.insertNode(t.getRng().createContextualFragment(h));\r
4745 \r
4746                                 // Move to caret marker\r
4747                                 c = t.dom.get('__caret');\r
4748 \r
4749                                 // Make sure we wrap it compleatly, Opera fails with a simple select call\r
4750                                 r = d.createRange();\r
4751                                 r.setStartBefore(c);\r
4752                                 r.setEndAfter(c);\r
4753                                 t.setRng(r);\r
4754 \r
4755                                 // Delete the marker, and hopefully the caret gets placed in the right location\r
4756                                 // Removed this since it seems to remove &nbsp; in FF and simply deleting it\r
4757                                 // doesn't seem to affect the caret position in any browser\r
4758                                 //d.execCommand('Delete', false, null);\r
4759 \r
4760                                 // Remove the caret position\r
4761                                 t.dom.remove('__caret');\r
4762                         } else {\r
4763                                 if (r.item) {\r
4764                                         // Delete content and get caret text selection\r
4765                                         d.execCommand('Delete', false, null);\r
4766                                         r = t.getRng();\r
4767                                 }\r
4768 \r
4769                                 r.pasteHTML(h);\r
4770                         }\r
4771 \r
4772                         // Dispatch set content event\r
4773                         t.onSetContent.dispatch(t, s);\r
4774                 },\r
4775 \r
4776                 getStart : function() {\r
4777                         var t = this, r = t.getRng(), e;\r
4778 \r
4779                         if (isIE) {\r
4780                                 if (r.item)\r
4781                                         return r.item(0);\r
4782 \r
4783                                 r = r.duplicate();\r
4784                                 r.collapse(1);\r
4785                                 e = r.parentElement();\r
4786 \r
4787                                 if (e && e.nodeName == 'BODY')\r
4788                                         return e.firstChild;\r
4789 \r
4790                                 return e;\r
4791                         } else {\r
4792                                 e = r.startContainer;\r
4793 \r
4794                                 if (e.nodeName == 'BODY')\r
4795                                         return e.firstChild;\r
4796 \r
4797                                 return t.dom.getParent(e, '*');\r
4798                         }\r
4799                 },\r
4800 \r
4801                 getEnd : function() {\r
4802                         var t = this, r = t.getRng(), e;\r
4803 \r
4804                         if (isIE) {\r
4805                                 if (r.item)\r
4806                                         return r.item(0);\r
4807 \r
4808                                 r = r.duplicate();\r
4809                                 r.collapse(0);\r
4810                                 e = r.parentElement();\r
4811 \r
4812                                 if (e && e.nodeName == 'BODY')\r
4813                                         return e.lastChild;\r
4814 \r
4815                                 return e;\r
4816                         } else {\r
4817                                 e = r.endContainer;\r
4818 \r
4819                                 if (e.nodeName == 'BODY')\r
4820                                         return e.lastChild;\r
4821 \r
4822                                 return t.dom.getParent(e, '*');\r
4823                         }\r
4824                 },\r
4825 \r
4826                 getBookmark : function(si) {\r
4827                         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;\r
4828                         sx = vp.x;\r
4829                         sy = vp.y;\r
4830 \r
4831                         // Simple bookmark fast but not as persistent\r
4832                         if (si == 'simple')\r
4833                                 return {rng : r, scrollX : sx, scrollY : sy};\r
4834 \r
4835                         // Handle IE\r
4836                         if (isIE) {\r
4837                                 // Control selection\r
4838                                 if (r.item) {\r
4839                                         e = r.item(0);\r
4840 \r
4841                                         each(t.dom.select(e.nodeName), function(n, i) {\r
4842                                                 if (e == n) {\r
4843                                                         sp = i;\r
4844                                                         return false;\r
4845                                                 }\r
4846                                         });\r
4847 \r
4848                                         return {\r
4849                                                 tag : e.nodeName,\r
4850                                                 index : sp,\r
4851                                                 scrollX : sx,\r
4852                                                 scrollY : sy\r
4853                                         };\r
4854                                 }\r
4855 \r
4856                                 // Text selection\r
4857                                 tr = t.dom.doc.body.createTextRange();\r
4858                                 tr.moveToElementText(ro);\r
4859                                 tr.collapse(true);\r
4860                                 bp = Math.abs(tr.move('character', c));\r
4861 \r
4862                                 tr = r.duplicate();\r
4863                                 tr.collapse(true);\r
4864                                 sp = Math.abs(tr.move('character', c));\r
4865 \r
4866                                 tr = r.duplicate();\r
4867                                 tr.collapse(false);\r
4868                                 le = Math.abs(tr.move('character', c)) - sp;\r
4869 \r
4870                                 return {\r
4871                                         start : sp - bp,\r
4872                                         length : le,\r
4873                                         scrollX : sx,\r
4874                                         scrollY : sy\r
4875                                 };\r
4876                         }\r
4877 \r
4878                         // Handle W3C\r
4879                         e = t.getNode();\r
4880                         s = t.getSel();\r
4881 \r
4882                         if (!s)\r
4883                                 return null;\r
4884 \r
4885                         // Image selection\r
4886                         if (e && e.nodeName == 'IMG') {\r
4887                                 return {\r
4888                                         scrollX : sx,\r
4889                                         scrollY : sy\r
4890                                 };\r
4891                         }\r
4892 \r
4893                         // Text selection\r
4894 \r
4895                         function getPos(r, sn, en) {\r
4896                                 var w = t.dom.doc.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};\r
4897 \r
4898                                 while ((n = w.nextNode()) != null) {\r
4899                                         if (n == sn)\r
4900                                                 d.start = p;\r
4901 \r
4902                                         if (n == en) {\r
4903                                                 d.end = p;\r
4904                                                 return d;\r
4905                                         }\r
4906 \r
4907                                         p += trimNl(n.nodeValue || '').length;\r
4908                                 }\r
4909 \r
4910                                 return null;\r
4911                         };\r
4912 \r
4913                         // Caret or selection\r
4914                         if (s.anchorNode == s.focusNode && s.anchorOffset == s.focusOffset) {\r
4915                                 e = getPos(ro, s.anchorNode, s.focusNode);\r
4916 \r
4917                                 if (!e)\r
4918                                         return {scrollX : sx, scrollY : sy};\r
4919 \r
4920                                 // Count whitespace before\r
4921                                 trimNl(s.anchorNode.nodeValue || '').replace(/^\s+/, function(a) {wb = a.length;});\r
4922 \r
4923                                 return {\r
4924                                         start : Math.max(e.start + s.anchorOffset - wb, 0),\r
4925                                         end : Math.max(e.end + s.focusOffset - wb, 0),\r
4926                                         scrollX : sx,\r
4927                                         scrollY : sy,\r
4928                                         beg : s.anchorOffset - wb == 0\r
4929                                 };\r
4930                         } else {\r
4931                                 e = getPos(ro, r.startContainer, r.endContainer);\r
4932 \r
4933                                 // Count whitespace before start and end container\r
4934                                 //(r.startContainer.nodeValue || '').replace(/^\s+/, function(a) {wb = a.length;});\r
4935                                 //(r.endContainer.nodeValue || '').replace(/^\s+/, function(a) {wa = a.length;});\r
4936 \r
4937                                 if (!e)\r
4938                                         return {scrollX : sx, scrollY : sy};\r
4939 \r
4940                                 return {\r
4941                                         start : Math.max(e.start + r.startOffset - wb, 0),\r
4942                                         end : Math.max(e.end + r.endOffset - wa, 0),\r
4943                                         scrollX : sx,\r
4944                                         scrollY : sy,\r
4945                                         beg : r.startOffset - wb == 0\r
4946                                 };\r
4947                         }\r
4948                 },\r
4949 \r
4950                 moveToBookmark : function(b) {\r
4951                         var t = this, r = t.getRng(), s = t.getSel(), ro = t.dom.getRoot(), sd, nvl, nv;\r
4952 \r
4953                         function getPos(r, sp, ep) {\r
4954                                 var w = t.dom.doc.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {}, o, v, wa, wb;\r
4955 \r
4956                                 while ((n = w.nextNode()) != null) {\r
4957                                         wa = wb = 0;\r
4958 \r
4959                                         nv = n.nodeValue || '';\r
4960                                         //nv.replace(/^\s+[^\s]/, function(a) {wb = a.length - 1;});\r
4961                                         //nv.replace(/[^\s]\s+$/, function(a) {wa = a.length - 1;});\r
4962 \r
4963                                         nvl = trimNl(nv).length;\r
4964                                         p += nvl;\r
4965 \r
4966                                         if (p >= sp && !d.startNode) {\r
4967                                                 o = sp - (p - nvl);\r
4968 \r
4969                                                 // Fix for odd quirk in FF\r
4970                                                 if (b.beg && o >= nvl)\r
4971                                                         continue;\r
4972 \r
4973                                                 d.startNode = n;\r
4974                                                 d.startOffset = o + wb;\r
4975                                         }\r
4976 \r
4977                                         if (p >= ep) {\r
4978                                                 d.endNode = n;\r
4979                                                 d.endOffset = ep - (p - nvl) + wb;\r
4980                                                 return d;\r
4981                                         }\r
4982                                 }\r
4983 \r
4984                                 return null;\r
4985                         };\r
4986 \r
4987                         if (!b)\r
4988                                 return false;\r
4989 \r
4990                         t.win.scrollTo(b.scrollX, b.scrollY);\r
4991 \r
4992                         // Handle explorer\r
4993                         if (isIE) {\r
4994                                 // Handle simple\r
4995                                 if (r = b.rng) {\r
4996                                         try {\r
4997                                                 r.select();\r
4998                                         } catch (ex) {\r
4999                                                 // Ignore\r
5000                                         }\r
5001 \r
5002                                         return true;\r
5003                                 }\r
5004 \r
5005                                 t.win.focus();\r
5006 \r
5007                                 // Handle control bookmark\r
5008                                 if (b.tag) {\r
5009                                         r = ro.createControlRange();\r
5010 \r
5011                                         each(t.dom.select(b.tag), function(n, i) {\r
5012                                                 if (i == b.index)\r
5013                                                         r.addElement(n);\r
5014                                         });\r
5015                                 } else {\r
5016                                         // Try/catch needed since this operation breaks when TinyMCE is placed in hidden divs/tabs\r
5017                                         try {\r
5018                                                 // Incorrect bookmark\r
5019                                                 if (b.start < 0)\r
5020                                                         return true;\r
5021 \r
5022                                                 r = s.createRange();\r
5023                                                 r.moveToElementText(ro);\r
5024                                                 r.collapse(true);\r
5025                                                 r.moveStart('character', b.start);\r
5026                                                 r.moveEnd('character', b.length);\r
5027                                         } catch (ex2) {\r
5028                                                 return true;\r
5029                                         }\r
5030                                 }\r
5031 \r
5032                                 try {\r
5033                                         r.select();\r
5034                                 } catch (ex) {\r
5035                                         // Needed for some odd IE bug #1843306\r
5036                                 }\r
5037 \r
5038                                 return true;\r
5039                         }\r
5040 \r
5041                         // Handle W3C\r
5042                         if (!s)\r
5043                                 return false;\r
5044 \r
5045                         // Handle simple\r
5046                         if (b.rng) {\r
5047                                 s.removeAllRanges();\r
5048                                 s.addRange(b.rng);\r
5049                         } else {\r
5050                                 if (is(b.start) && is(b.end)) {\r
5051                                         try {\r
5052                                                 sd = getPos(ro, b.start, b.end);\r
5053 \r
5054                                                 if (sd) {\r
5055                                                         r = t.dom.doc.createRange();\r
5056                                                         r.setStart(sd.startNode, sd.startOffset);\r
5057                                                         r.setEnd(sd.endNode, sd.endOffset);\r
5058                                                         s.removeAllRanges();\r
5059                                                         s.addRange(r);\r
5060                                                 }\r
5061 \r
5062                                                 if (!tinymce.isOpera)\r
5063                                                         t.win.focus();\r
5064                                         } catch (ex) {\r
5065                                                 // Ignore\r
5066                                         }\r
5067                                 }\r
5068                         }\r
5069                 },\r
5070 \r
5071                 select : function(n, c) {\r
5072                         var t = this, r = t.getRng(), s = t.getSel(), b, fn, ln, d = t.win.document;\r
5073 \r
5074                         function find(n, start) {\r
5075                                 var walker, o;\r
5076 \r
5077                                 if (n) {\r
5078                                         walker = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);\r
5079 \r
5080                                         // Find first/last non empty text node\r
5081                                         while (n = walker.nextNode()) {\r
5082                                                 o = n;\r
5083 \r
5084                                                 if (tinymce.trim(n.nodeValue).length != 0) {\r
5085                                                         if (start)\r
5086                                                                 return n;\r
5087                                                         else\r
5088                                                                 o = n;\r
5089                                                 }\r
5090                                         }\r
5091                                 }\r
5092 \r
5093                                 return o;\r
5094                         };\r
5095 \r
5096                         if (isIE) {\r
5097                                 try {\r
5098                                         b = d.body;\r
5099 \r
5100                                         if (/^(IMG|TABLE)$/.test(n.nodeName)) {\r
5101                                                 r = b.createControlRange();\r
5102                                                 r.addElement(n);\r
5103                                         } else {\r
5104                                                 r = b.createTextRange();\r
5105                                                 r.moveToElementText(n);\r
5106                                         }\r
5107 \r
5108                                         r.select();\r
5109                                 } catch (ex) {\r
5110                                         // Throws illigal agrument in IE some times\r
5111                                 }\r
5112                         } else {\r
5113                                 if (c) {\r
5114                                         fn = find(n, 1) || t.dom.select('br:first', n)[0];\r
5115                                         ln = find(n, 0) || t.dom.select('br:last', n)[0];\r
5116 \r
5117                                         if (fn && ln) {\r
5118                                                 r = d.createRange();\r
5119 \r
5120                                                 if (fn.nodeName == 'BR')\r
5121                                                         r.setStartBefore(fn);\r
5122                                                 else\r
5123                                                         r.setStart(fn, 0);\r
5124 \r
5125                                                 if (ln.nodeName == 'BR')\r
5126                                                         r.setEndBefore(ln);\r
5127                                                 else\r
5128                                                         r.setEnd(ln, ln.nodeValue.length);\r
5129                                         } else\r
5130                                                 r.selectNode(n);\r
5131                                 } else\r
5132                                         r.selectNode(n);\r
5133 \r
5134                                 t.setRng(r);\r
5135                         }\r
5136 \r
5137                         return n;\r
5138                 },\r
5139 \r
5140                 isCollapsed : function() {\r
5141                         var t = this, r = t.getRng(), s = t.getSel();\r
5142 \r
5143                         if (!r || r.item)\r
5144                                 return false;\r
5145 \r
5146                         return !s || r.boundingWidth == 0 || r.collapsed;\r
5147                 },\r
5148 \r
5149                 collapse : function(b) {\r
5150                         var t = this, r = t.getRng(), n;\r
5151 \r
5152                         // Control range on IE\r
5153                         if (r.item) {\r
5154                                 n = r.item(0);\r
5155                                 r = this.win.document.body.createTextRange();\r
5156                                 r.moveToElementText(n);\r
5157                         }\r
5158 \r
5159                         r.collapse(!!b);\r
5160                         t.setRng(r);\r
5161                 },\r
5162 \r
5163                 getSel : function() {\r
5164                         var t = this, w = this.win;\r
5165 \r
5166                         return w.getSelection ? w.getSelection() : w.document.selection;\r
5167                 },\r
5168 \r
5169                 getRng : function(w3c) {\r
5170                         var t = this, s, r;\r
5171 \r
5172                         // Found tridentSel object then we need to use that one\r
5173                         if (w3c && t.tridentSel)\r
5174                                 return t.tridentSel.getRangeAt(0);\r
5175 \r
5176                         try {\r
5177                                 if (s = t.getSel())\r
5178                                         r = s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ? s.createRange() : t.win.document.createRange());\r
5179                         } catch (ex) {\r
5180                                 // IE throws unspecified error here if TinyMCE is placed in a frame/iframe\r
5181                         }\r
5182 \r
5183                         // No range found then create an empty one\r
5184                         // This can occur when the editor is placed in a hidden container element on Gecko\r
5185                         // Or on IE when there was an exception\r
5186                         if (!r)\r
5187                                 r = isIE ? t.win.document.body.createTextRange() : t.win.document.createRange();\r
5188 \r
5189                         return r;\r
5190                 },\r
5191 \r
5192                 setRng : function(r) {\r
5193                         var s, t = this;\r
5194 \r
5195                         if (!t.tridentSel) {\r
5196                                 s = t.getSel();\r
5197 \r
5198                                 if (s) {\r
5199                                         s.removeAllRanges();\r
5200                                         s.addRange(r);\r
5201                                 }\r
5202                         } else {\r
5203                                 // Is W3C Range\r
5204                                 if (r.cloneRange) {\r
5205                                         t.tridentSel.addRange(r);\r
5206                                         return;\r
5207                                 }\r
5208 \r
5209                                 // Is IE specific range\r
5210                                 try {\r
5211                                         r.select();\r
5212                                 } catch (ex) {\r
5213                                         // Needed for some odd IE bug #1843306\r
5214                                 }\r
5215                         }\r
5216                 },\r
5217 \r
5218                 setNode : function(n) {\r
5219                         var t = this;\r
5220 \r
5221                         t.setContent(t.dom.getOuterHTML(n));\r
5222 \r
5223                         return n;\r
5224                 },\r
5225 \r
5226                 getNode : function() {\r
5227                         var t = this, r = t.getRng(), s = t.getSel(), e;\r
5228 \r
5229                         if (!isIE) {\r
5230                                 // Range maybe lost after the editor is made visible again\r
5231                                 if (!r)\r
5232                                         return t.dom.getRoot();\r
5233 \r
5234                                 e = r.commonAncestorContainer;\r
5235 \r
5236                                 // Handle selection a image or other control like element such as anchors\r
5237                                 if (!r.collapsed) {\r
5238                                         // If the anchor node is a element instead of a text node then return this element\r
5239                                         if (tinymce.isWebKit && s.anchorNode && s.anchorNode.nodeType == 1) \r
5240                                                 return s.anchorNode.childNodes[s.anchorOffset]; \r
5241 \r
5242                                         if (r.startContainer == r.endContainer) {\r
5243                                                 if (r.startOffset - r.endOffset < 2) {\r
5244                                                         if (r.startContainer.hasChildNodes())\r
5245                                                                 e = r.startContainer.childNodes[r.startOffset];\r
5246                                                 }\r
5247                                         }\r
5248                                 }\r
5249 \r
5250                                 return t.dom.getParent(e, '*');\r
5251                         }\r
5252 \r
5253                         return r.item ? r.item(0) : r.parentElement();\r
5254                 },\r
5255 \r
5256                 getSelectedBlocks : function(st, en) {\r
5257                         var t = this, dom = t.dom, sb, eb, n, bl = [];\r
5258 \r
5259                         sb = dom.getParent(st || t.getStart(), dom.isBlock);\r
5260                         eb = dom.getParent(en || t.getEnd(), dom.isBlock);\r
5261 \r
5262                         if (sb)\r
5263                                 bl.push(sb);\r
5264 \r
5265                         if (sb && eb && sb != eb) {\r
5266                                 n = sb;\r
5267 \r
5268                                 while ((n = n.nextSibling) && n != eb) {\r
5269                                         if (dom.isBlock(n))\r
5270                                                 bl.push(n);\r
5271                                 }\r
5272                         }\r
5273 \r
5274                         if (eb && sb != eb)\r
5275                                 bl.push(eb);\r
5276 \r
5277                         return bl;\r
5278                 },\r
5279 \r
5280                 destroy : function(s) {\r
5281                         var t = this;\r
5282 \r
5283                         t.win = null;\r
5284 \r
5285                         if (t.tridentSel)\r
5286                                 t.tridentSel.destroy();\r
5287 \r
5288                         // Manual destroy then remove unload handler\r
5289                         if (!s)\r
5290                                 tinymce.removeUnload(t.destroy);\r
5291                 }\r
5292 \r
5293                 });\r
5294 })(tinymce);\r
5295 (function(tinymce) {\r
5296         tinymce.create('tinymce.dom.XMLWriter', {\r
5297                 node : null,\r
5298 \r
5299                 XMLWriter : function(s) {\r
5300                         // Get XML document\r
5301                         function getXML() {\r
5302                                 var i = document.implementation;\r
5303 \r
5304                                 if (!i || !i.createDocument) {\r
5305                                         // Try IE objects\r
5306                                         try {return new ActiveXObject('MSXML2.DOMDocument');} catch (ex) {}\r
5307                                         try {return new ActiveXObject('Microsoft.XmlDom');} catch (ex) {}\r
5308                                 } else\r
5309                                         return i.createDocument('', '', null);\r
5310                         };\r
5311 \r
5312                         this.doc = getXML();\r
5313                         \r
5314                         // Since Opera and WebKit doesn't escape > into &gt; we need to do it our self to normalize the output for all browsers\r
5315                         this.valid = tinymce.isOpera || tinymce.isWebKit;\r
5316 \r
5317                         this.reset();\r
5318                 },\r
5319 \r
5320                 reset : function() {\r
5321                         var t = this, d = t.doc;\r
5322 \r
5323                         if (d.firstChild)\r
5324                                 d.removeChild(d.firstChild);\r
5325 \r
5326                         t.node = d.appendChild(d.createElement("html"));\r
5327                 },\r
5328 \r
5329                 writeStartElement : function(n) {\r
5330                         var t = this;\r
5331 \r
5332                         t.node = t.node.appendChild(t.doc.createElement(n));\r
5333                 },\r
5334 \r
5335                 writeAttribute : function(n, v) {\r
5336                         if (this.valid)\r
5337                                 v = v.replace(/>/g, '%MCGT%');\r
5338 \r
5339                         this.node.setAttribute(n, v);\r
5340                 },\r
5341 \r
5342                 writeEndElement : function() {\r
5343                         this.node = this.node.parentNode;\r
5344                 },\r
5345 \r
5346                 writeFullEndElement : function() {\r
5347                         var t = this, n = t.node;\r
5348 \r
5349                         n.appendChild(t.doc.createTextNode(""));\r
5350                         t.node = n.parentNode;\r
5351                 },\r
5352 \r
5353                 writeText : function(v) {\r
5354                         if (this.valid)\r
5355                                 v = v.replace(/>/g, '%MCGT%');\r
5356 \r
5357                         this.node.appendChild(this.doc.createTextNode(v));\r
5358                 },\r
5359 \r
5360                 writeCDATA : function(v) {\r
5361                         this.node.appendChild(this.doc.createCDATA(v));\r
5362                 },\r
5363 \r
5364                 writeComment : function(v) {\r
5365                         // Fix for bug #2035694\r
5366                         if (tinymce.isIE)\r
5367                                 v = v.replace(/^\-|\-$/g, ' ');\r
5368 \r
5369                         this.node.appendChild(this.doc.createComment(v.replace(/\-\-/g, ' ')));\r
5370                 },\r
5371 \r
5372                 getContent : function() {\r
5373                         var h;\r
5374 \r
5375                         h = this.doc.xml || new XMLSerializer().serializeToString(this.doc);\r
5376                         h = h.replace(/<\?[^?]+\?>|<html>|<\/html>|<html\/>|<!DOCTYPE[^>]+>/g, '');\r
5377                         h = h.replace(/ ?\/>/g, ' />');\r
5378 \r
5379                         if (this.valid)\r
5380                                 h = h.replace(/\%MCGT%/g, '&gt;');\r
5381 \r
5382                         return h;\r
5383                 }\r
5384 \r
5385                 });\r
5386 })(tinymce);\r
5387 (function(tinymce) {\r
5388         tinymce.create('tinymce.dom.StringWriter', {\r
5389                 str : null,\r
5390                 tags : null,\r
5391                 count : 0,\r
5392                 settings : null,\r
5393                 indent : null,\r
5394 \r
5395                 StringWriter : function(s) {\r
5396                         this.settings = tinymce.extend({\r
5397                                 indent_char : ' ',\r
5398                                 indentation : 1\r
5399                         }, s);\r
5400 \r
5401                         this.reset();\r
5402                 },\r
5403 \r
5404                 reset : function() {\r
5405                         this.indent = '';\r
5406                         this.str = "";\r
5407                         this.tags = [];\r
5408                         this.count = 0;\r
5409                 },\r
5410 \r
5411                 writeStartElement : function(n) {\r
5412                         this._writeAttributesEnd();\r
5413                         this.writeRaw('<' + n);\r
5414                         this.tags.push(n);\r
5415                         this.inAttr = true;\r
5416                         this.count++;\r
5417                         this.elementCount = this.count;\r
5418                 },\r
5419 \r
5420                 writeAttribute : function(n, v) {\r
5421                         var t = this;\r
5422 \r
5423                         t.writeRaw(" " + t.encode(n) + '="' + t.encode(v) + '"');\r
5424                 },\r
5425 \r
5426                 writeEndElement : function() {\r
5427                         var n;\r
5428 \r
5429                         if (this.tags.length > 0) {\r
5430                                 n = this.tags.pop();\r
5431 \r
5432                                 if (this._writeAttributesEnd(1))\r
5433                                         this.writeRaw('</' + n + '>');\r
5434 \r
5435                                 if (this.settings.indentation > 0)\r
5436                                         this.writeRaw('\n');\r
5437                         }\r
5438                 },\r
5439 \r
5440                 writeFullEndElement : function() {\r
5441                         if (this.tags.length > 0) {\r
5442                                 this._writeAttributesEnd();\r
5443                                 this.writeRaw('</' + this.tags.pop() + '>');\r
5444 \r
5445                                 if (this.settings.indentation > 0)\r
5446                                         this.writeRaw('\n');\r
5447                         }\r
5448                 },\r
5449 \r
5450                 writeText : function(v) {\r
5451                         this._writeAttributesEnd();\r
5452                         this.writeRaw(this.encode(v));\r
5453                         this.count++;\r
5454                 },\r
5455 \r
5456                 writeCDATA : function(v) {\r
5457                         this._writeAttributesEnd();\r
5458                         this.writeRaw('<![CDATA[' + v + ']]>');\r
5459                         this.count++;\r
5460                 },\r
5461 \r
5462                 writeComment : function(v) {\r
5463                         this._writeAttributesEnd();\r
5464                         this.writeRaw('<!-- ' + v + '-->');\r
5465                         this.count++;\r
5466                 },\r
5467 \r
5468                 writeRaw : function(v) {\r
5469                         this.str += v;\r
5470                 },\r
5471 \r
5472                 encode : function(s) {\r
5473                         return s.replace(/[<>&"]/g, function(v) {\r
5474                                 switch (v) {\r
5475                                         case '<':\r
5476                                                 return '&lt;';\r
5477 \r
5478                                         case '>':\r
5479                                                 return '&gt;';\r
5480 \r
5481                                         case '&':\r
5482                                                 return '&amp;';\r
5483 \r
5484                                         case '"':\r
5485                                                 return '&quot;';\r
5486                                 }\r
5487 \r
5488                                 return v;\r
5489                         });\r
5490                 },\r
5491 \r
5492                 getContent : function() {\r
5493                         return this.str;\r
5494                 },\r
5495 \r
5496                 _writeAttributesEnd : function(s) {\r
5497                         if (!this.inAttr)\r
5498                                 return;\r
5499 \r
5500                         this.inAttr = false;\r
5501 \r
5502                         if (s && this.elementCount == this.count) {\r
5503                                 this.writeRaw(' />');\r
5504                                 return false;\r
5505                         }\r
5506 \r
5507                         this.writeRaw('>');\r
5508 \r
5509                         return true;\r
5510                 }\r
5511 \r
5512                 });\r
5513 })(tinymce);\r
5514 (function(tinymce) {\r
5515         // Shorten names\r
5516         var extend = tinymce.extend, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher, isIE = tinymce.isIE, isGecko = tinymce.isGecko;\r
5517 \r
5518         function wildcardToRE(s) {\r
5519                 return s.replace(/([?+*])/g, '.$1');\r
5520         };\r
5521 \r
5522         tinymce.create('tinymce.dom.Serializer', {\r
5523                 Serializer : function(s) {\r
5524                         var t = this;\r
5525 \r
5526                         t.key = 0;\r
5527                         t.onPreProcess = new Dispatcher(t);\r
5528                         t.onPostProcess = new Dispatcher(t);\r
5529 \r
5530                         try {\r
5531                                 t.writer = new tinymce.dom.XMLWriter();\r
5532                         } catch (ex) {\r
5533                                 // IE might throw exception if ActiveX is disabled so we then switch to the slightly slower StringWriter\r
5534                                 t.writer = new tinymce.dom.StringWriter();\r
5535                         }\r
5536 \r
5537                         // Default settings\r
5538                         t.settings = s = extend({\r
5539                                 dom : tinymce.DOM,\r
5540                                 valid_nodes : 0,\r
5541                                 node_filter : 0,\r
5542                                 attr_filter : 0,\r
5543                                 invalid_attrs : /^(mce_|_moz_)/,\r
5544                                 closed : /^(br|hr|input|meta|img|link|param|area)$/,\r
5545                                 entity_encoding : 'named',\r
5546                                 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',\r
5547                                 bool_attrs : /(checked|disabled|readonly|selected|nowrap)/,\r
5548                                 valid_elements : '*[*]',\r
5549                                 extended_valid_elements : 0,\r
5550                                 valid_child_elements : 0,\r
5551                                 invalid_elements : 0,\r
5552                                 fix_table_elements : 1,\r
5553                                 fix_list_elements : true,\r
5554                                 fix_content_duplication : true,\r
5555                                 convert_fonts_to_spans : false,\r
5556                                 font_size_classes : 0,\r
5557                                 font_size_style_values : 0,\r
5558                                 apply_source_formatting : 0,\r
5559                                 indent_mode : 'simple',\r
5560                                 indent_char : '\t',\r
5561                                 indent_levels : 1,\r
5562                                 remove_linebreaks : 1,\r
5563                                 remove_redundant_brs : 1,\r
5564                                 element_format : 'xhtml'\r
5565                         }, s);\r
5566 \r
5567                         t.dom = s.dom;\r
5568 \r
5569                         if (s.remove_redundant_brs) {\r
5570                                 t.onPostProcess.add(function(se, o) {\r
5571                                         // Remove single BR at end of block elements since they get rendered\r
5572                                         o.content = o.content.replace(/(<br \/>\s*)+<\/(p|h[1-6]|div|li)>/gi, function(a, b, c) {\r
5573                                                 // Check if it's a single element\r
5574                                                 if (/^<br \/>\s*<\//.test(a))\r
5575                                                         return '</' + c + '>';\r
5576 \r
5577                                                 return a;\r
5578                                         });\r
5579                                 });\r
5580                         }\r
5581 \r
5582                         // Remove XHTML element endings i.e. produce crap :) XHTML is better\r
5583                         if (s.element_format == 'html') {\r
5584                                 t.onPostProcess.add(function(se, o) {\r
5585                                         o.content = o.content.replace(/<([^>]+) \/>/g, '<$1>');\r
5586                                 });\r
5587                         }\r
5588 \r
5589                         if (s.fix_list_elements) {\r
5590                                 t.onPreProcess.add(function(se, o) {\r
5591                                         var nl, x, a = ['ol', 'ul'], i, n, p, r = /^(OL|UL)$/, np;\r
5592 \r
5593                                         function prevNode(e, n) {\r
5594                                                 var a = n.split(','), i;\r
5595 \r
5596                                                 while ((e = e.previousSibling) != null) {\r
5597                                                         for (i=0; i<a.length; i++) {\r
5598                                                                 if (e.nodeName == a[i])\r
5599                                                                         return e;\r
5600                                                         }\r
5601                                                 }\r
5602 \r
5603                                                 return null;\r
5604                                         };\r
5605 \r
5606                                         for (x=0; x<a.length; x++) {\r
5607                                                 nl = t.dom.select(a[x], o.node);\r
5608 \r
5609                                                 for (i=0; i<nl.length; i++) {\r
5610                                                         n = nl[i];\r
5611                                                         p = n.parentNode;\r
5612 \r
5613                                                         if (r.test(p.nodeName)) {\r
5614                                                                 np = prevNode(n, 'LI');\r
5615 \r
5616                                                                 if (!np) {\r
5617                                                                         np = t.dom.create('li');\r
5618                                                                         np.innerHTML = '&nbsp;';\r
5619                                                                         np.appendChild(n);\r
5620                                                                         p.insertBefore(np, p.firstChild);\r
5621                                                                 } else\r
5622                                                                         np.appendChild(n);\r
5623                                                         }\r
5624                                                 }\r
5625                                         }\r
5626                                 });\r
5627                         }\r
5628 \r
5629                         if (s.fix_table_elements) {\r
5630                                 t.onPreProcess.add(function(se, o) {\r
5631                                         each(t.dom.select('p table', o.node), function(n) {\r
5632                                                 t.dom.split(t.dom.getParent(n, 'p'), n);\r
5633                                         });\r
5634                                 });\r
5635                         }\r
5636                 },\r
5637 \r
5638                 setEntities : function(s) {\r
5639                         var t = this, a, i, l = {}, re = '', v;\r
5640 \r
5641                         // No need to setup more than once\r
5642                         if (t.entityLookup)\r
5643                                 return;\r
5644 \r
5645                         // Build regex and lookup array\r
5646                         a = s.split(',');\r
5647                         for (i = 0; i < a.length; i += 2) {\r
5648                                 v = a[i];\r
5649 \r
5650                                 // Don't add default &amp; &quot; etc.\r
5651                                 if (v == 34 || v == 38 || v == 60 || v == 62)\r
5652                                         continue;\r
5653 \r
5654                                 l[String.fromCharCode(a[i])] = a[i + 1];\r
5655 \r
5656                                 v = parseInt(a[i]).toString(16);\r
5657                                 re += '\\u' + '0000'.substring(v.length) + v;\r
5658                         }\r
5659 \r
5660                         if (!re) {\r
5661                                 t.settings.entity_encoding = 'raw';\r
5662                                 return;\r
5663                         }\r
5664 \r
5665                         t.entitiesRE = new RegExp('[' + re + ']', 'g');\r
5666                         t.entityLookup = l;\r
5667                 },\r
5668 \r
5669                 setValidChildRules : function(s) {\r
5670                         this.childRules = null;\r
5671                         this.addValidChildRules(s);\r
5672                 },\r
5673 \r
5674                 addValidChildRules : function(s) {\r
5675                         var t = this, inst, intr, bloc;\r
5676 \r
5677                         if (!s)\r
5678                                 return;\r
5679 \r
5680                         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';\r
5681                         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';\r
5682                         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';\r
5683 \r
5684                         each(s.split(','), function(s) {\r
5685                                 var p = s.split(/\[|\]/), re;\r
5686 \r
5687                                 s = '';\r
5688                                 each(p[1].split('|'), function(v) {\r
5689                                         if (s)\r
5690                                                 s += '|';\r
5691 \r
5692                                         switch (v) {\r
5693                                                 case '%itrans':\r
5694                                                         v = intr;\r
5695                                                         break;\r
5696 \r
5697                                                 case '%itrans_na':\r
5698                                                         v = intr.substring(2);\r
5699                                                         break;\r
5700 \r
5701                                                 case '%istrict':\r
5702                                                         v = inst;\r
5703                                                         break;\r
5704 \r
5705                                                 case '%istrict_na':\r
5706                                                         v = inst.substring(2);\r
5707                                                         break;\r
5708 \r
5709                                                 case '%btrans':\r
5710                                                         v = bloc;\r
5711                                                         break;\r
5712 \r
5713                                                 case '%bstrict':\r
5714                                                         v = bloc;\r
5715                                                         break;\r
5716                                         }\r
5717 \r
5718                                         s += v;\r
5719                                 });\r
5720                                 re = new RegExp('^(' + s.toLowerCase() + ')$', 'i');\r
5721 \r
5722                                 each(p[0].split('/'), function(s) {\r
5723                                         t.childRules = t.childRules || {};\r
5724                                         t.childRules[s] = re;\r
5725                                 });\r
5726                         });\r
5727 \r
5728                         // Build regex\r
5729                         s = '';\r
5730                         each(t.childRules, function(v, k) {\r
5731                                 if (s)\r
5732                                         s += '|';\r
5733 \r
5734                                 s += k;\r
5735                         });\r
5736 \r
5737                         t.parentElementsRE = new RegExp('^(' + s.toLowerCase() + ')$', 'i');\r
5738 \r
5739                         /*console.debug(t.parentElementsRE.toString());\r
5740                         each(t.childRules, function(v) {\r
5741                                 console.debug(v.toString());\r
5742                         });*/\r
5743                 },\r
5744 \r
5745                 setRules : function(s) {\r
5746                         var t = this;\r
5747 \r
5748                         t._setup();\r
5749                         t.rules = {};\r
5750                         t.wildRules = [];\r
5751                         t.validElements = {};\r
5752 \r
5753                         return t.addRules(s);\r
5754                 },\r
5755 \r
5756                 addRules : function(s) {\r
5757                         var t = this, dr;\r
5758 \r
5759                         if (!s)\r
5760                                 return;\r
5761 \r
5762                         t._setup();\r
5763 \r
5764                         each(s.split(','), function(s) {\r
5765                                 var p = s.split(/\[|\]/), tn = p[0].split('/'), ra, at, wat, va = [];\r
5766 \r
5767                                 // Extend with default rules\r
5768                                 if (dr)\r
5769                                         at = tinymce.extend([], dr.attribs);\r
5770 \r
5771                                 // Parse attributes\r
5772                                 if (p.length > 1) {\r
5773                                         each(p[1].split('|'), function(s) {\r
5774                                                 var ar = {}, i;\r
5775 \r
5776                                                 at = at || [];\r
5777 \r
5778                                                 // Parse attribute rule\r
5779                                                 s = s.replace(/::/g, '~');\r
5780                                                 s = /^([!\-])?([\w*.?~_\-]+|)([=:<])?(.+)?$/.exec(s);\r
5781                                                 s[2] = s[2].replace(/~/g, ':');\r
5782 \r
5783                                                 // Add required attributes\r
5784                                                 if (s[1] == '!') {\r
5785                                                         ra = ra || [];\r
5786                                                         ra.push(s[2]);\r
5787                                                 }\r
5788 \r
5789                                                 // Remove inherited attributes\r
5790                                                 if (s[1] == '-') {\r
5791                                                         for (i = 0; i <at.length; i++) {\r
5792                                                                 if (at[i].name == s[2]) {\r
5793                                                                         at.splice(i, 1);\r
5794                                                                         return;\r
5795                                                                 }\r
5796                                                         }\r
5797                                                 }\r
5798 \r
5799                                                 switch (s[3]) {\r
5800                                                         // Add default attrib values\r
5801                                                         case '=':\r
5802                                                                 ar.defaultVal = s[4] || '';\r
5803                                                                 break;\r
5804 \r
5805                                                         // Add forced attrib values\r
5806                                                         case ':':\r
5807                                                                 ar.forcedVal = s[4];\r
5808                                                                 break;\r
5809 \r
5810                                                         // Add validation values\r
5811                                                         case '<':\r
5812                                                                 ar.validVals = s[4].split('?');\r
5813                                                                 break;\r
5814                                                 }\r
5815 \r
5816                                                 if (/[*.?]/.test(s[2])) {\r
5817                                                         wat = wat || [];\r
5818                                                         ar.nameRE = new RegExp('^' + wildcardToRE(s[2]) + '$');\r
5819                                                         wat.push(ar);\r
5820                                                 } else {\r
5821                                                         ar.name = s[2];\r
5822                                                         at.push(ar);\r
5823                                                 }\r
5824 \r
5825                                                 va.push(s[2]);\r
5826                                         });\r
5827                                 }\r
5828 \r
5829                                 // Handle element names\r
5830                                 each(tn, function(s, i) {\r
5831                                         var pr = s.charAt(0), x = 1, ru = {};\r
5832 \r
5833                                         // Extend with default rule data\r
5834                                         if (dr) {\r
5835                                                 if (dr.noEmpty)\r
5836                                                         ru.noEmpty = dr.noEmpty;\r
5837 \r
5838                                                 if (dr.fullEnd)\r
5839                                                         ru.fullEnd = dr.fullEnd;\r
5840 \r
5841                                                 if (dr.padd)\r
5842                                                         ru.padd = dr.padd;\r
5843                                         }\r
5844 \r
5845                                         // Handle prefixes\r
5846                                         switch (pr) {\r
5847                                                 case '-':\r
5848                                                         ru.noEmpty = true;\r
5849                                                         break;\r
5850 \r
5851                                                 case '+':\r
5852                                                         ru.fullEnd = true;\r
5853                                                         break;\r
5854 \r
5855                                                 case '#':\r
5856                                                         ru.padd = true;\r
5857                                                         break;\r
5858 \r
5859                                                 default:\r
5860                                                         x = 0;\r
5861                                         }\r
5862 \r
5863                                         tn[i] = s = s.substring(x);\r
5864                                         t.validElements[s] = 1;\r
5865 \r
5866                                         // Add element name or element regex\r
5867                                         if (/[*.?]/.test(tn[0])) {\r
5868                                                 ru.nameRE = new RegExp('^' + wildcardToRE(tn[0]) + '$');\r
5869                                                 t.wildRules = t.wildRules || {};\r
5870                                                 t.wildRules.push(ru);\r
5871                                         } else {\r
5872                                                 ru.name = tn[0];\r
5873 \r
5874                                                 // Store away default rule\r
5875                                                 if (tn[0] == '@')\r
5876                                                         dr = ru;\r
5877 \r
5878                                                 t.rules[s] = ru;\r
5879                                         }\r
5880 \r
5881                                         ru.attribs = at;\r
5882 \r
5883                                         if (ra)\r
5884                                                 ru.requiredAttribs = ra;\r
5885 \r
5886                                         if (wat) {\r
5887                                                 // Build valid attributes regexp\r
5888                                                 s = '';\r
5889                                                 each(va, function(v) {\r
5890                                                         if (s)\r
5891                                                                 s += '|';\r
5892 \r
5893                                                         s += '(' + wildcardToRE(v) + ')';\r
5894                                                 });\r
5895                                                 ru.validAttribsRE = new RegExp('^' + s.toLowerCase() + '$');\r
5896                                                 ru.wildAttribs = wat;\r
5897                                         }\r
5898                                 });\r
5899                         });\r
5900 \r
5901                         // Build valid elements regexp\r
5902                         s = '';\r
5903                         each(t.validElements, function(v, k) {\r
5904                                 if (s)\r
5905                                         s += '|';\r
5906 \r
5907                                 if (k != '@')\r
5908                                         s += k;\r
5909                         });\r
5910                         t.validElementsRE = new RegExp('^(' + wildcardToRE(s.toLowerCase()) + ')$');\r
5911 \r
5912                         //console.debug(t.validElementsRE.toString());\r
5913                         //console.dir(t.rules);\r
5914                         //console.dir(t.wildRules);\r
5915                 },\r
5916 \r
5917                 findRule : function(n) {\r
5918                         var t = this, rl = t.rules, i, r;\r
5919 \r
5920                         t._setup();\r
5921 \r
5922                         // Exact match\r
5923                         r = rl[n];\r
5924                         if (r)\r
5925                                 return r;\r
5926 \r
5927                         // Try wildcards\r
5928                         rl = t.wildRules;\r
5929                         for (i = 0; i < rl.length; i++) {\r
5930                                 if (rl[i].nameRE.test(n))\r
5931                                         return rl[i];\r
5932                         }\r
5933 \r
5934                         return null;\r
5935                 },\r
5936 \r
5937                 findAttribRule : function(ru, n) {\r
5938                         var i, wa = ru.wildAttribs;\r
5939 \r
5940                         for (i = 0; i < wa.length; i++) {\r
5941                                 if (wa[i].nameRE.test(n))\r
5942                                         return wa[i];\r
5943                         }\r
5944 \r
5945                         return null;\r
5946                 },\r
5947 \r
5948                 serialize : function(n, o) {\r
5949                         var h, t = this;\r
5950 \r
5951                         t._setup();\r
5952                         o = o || {};\r
5953                         o.format = o.format || 'html';\r
5954                         t.processObj = o;\r
5955                         n = n.cloneNode(true);\r
5956                         t.key = '' + (parseInt(t.key) + 1);\r
5957 \r
5958                         // Pre process\r
5959                         if (!o.no_events) {\r
5960                                 o.node = n;\r
5961                                 t.onPreProcess.dispatch(t, o);\r
5962                         }\r
5963 \r
5964                         // Serialize HTML DOM into a string\r
5965                         t.writer.reset();\r
5966                         t._serializeNode(n, o.getInner);\r
5967 \r
5968                         // Post process\r
5969                         o.content = t.writer.getContent();\r
5970 \r
5971                         if (!o.no_events)\r
5972                                 t.onPostProcess.dispatch(t, o);\r
5973 \r
5974                         t._postProcess(o);\r
5975                         o.node = null;\r
5976 \r
5977                         return tinymce.trim(o.content);\r
5978                 },\r
5979 \r
5980                 // Internal functions\r
5981 \r
5982                 _postProcess : function(o) {\r
5983                         var t = this, s = t.settings, h = o.content, sc = [], p;\r
5984 \r
5985                         if (o.format == 'html') {\r
5986                                 // Protect some elements\r
5987                                 p = t._protect({\r
5988                                         content : h,\r
5989                                         patterns : [\r
5990                                                 {pattern : /(<script[^>]*>)(.*?)(<\/script>)/g},\r
5991                                                 {pattern : /(<style[^>]*>)(.*?)(<\/style>)/g},\r
5992                                                 {pattern : /(<pre[^>]*>)(.*?)(<\/pre>)/g, encode : 1},\r
5993                                                 {pattern : /(<!--\[CDATA\[)(.*?)(\]\]-->)/g}\r
5994                                         ]\r
5995                                 });\r
5996 \r
5997                                 h = p.content;\r
5998 \r
5999                                 // Entity encode\r
6000                                 if (s.entity_encoding !== 'raw')\r
6001                                         h = t._encode(h);\r
6002 \r
6003                                 // Use BR instead of &nbsp; padded P elements inside editor and use <p>&nbsp;</p> outside editor\r
6004 /*                              if (o.set)\r
6005                                         h = h.replace(/<p>\s+(&nbsp;|&#160;|\u00a0|<br \/>)\s+<\/p>/g, '<p><br /></p>');\r
6006                                 else\r
6007                                         h = h.replace(/<p>\s+(&nbsp;|&#160;|\u00a0|<br \/>)\s+<\/p>/g, '<p>$1</p>');*/\r
6008 \r
6009                                 // Since Gecko and Safari keeps whitespace in the DOM we need to\r
6010                                 // remove it inorder to match other browsers. But I think Gecko and Safari is right.\r
6011                                 // This process is only done when getting contents out from the editor.\r
6012                                 if (!o.set) {\r
6013                                         // We need to replace paragraph whitespace with an nbsp before indentation to keep the \u00a0 char\r
6014                                         h = h.replace(/<p>\s+<\/p>|<p([^>]+)>\s+<\/p>/g, s.entity_encoding == 'numeric' ? '<p$1>&#160;</p>' : '<p$1>&nbsp;</p>');\r
6015 \r
6016                                         if (s.remove_linebreaks) {\r
6017                                                 h = h.replace(/\r?\n|\r/g, ' ');\r
6018                                                 h = h.replace(/(<[^>]+>)\s+/g, '$1 ');\r
6019                                                 h = h.replace(/\s+(<\/[^>]+>)/g, ' $1');\r
6020                                                 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\r
6021                                                 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\r
6022                                                 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\r
6023                                         }\r
6024 \r
6025                                         // Simple indentation\r
6026                                         if (s.apply_source_formatting && s.indent_mode == 'simple') {\r
6027                                                 // Add line breaks before and after block elements\r
6028                                                 h = h.replace(/<(\/?)(ul|hr|table|meta|link|tbody|tr|object|body|head|html|map)(|[^>]+)>\s*/g, '\n<$1$2$3>\n');\r
6029                                                 h = h.replace(/\s*<(p|h[1-6]|blockquote|div|title|style|pre|script|td|li|area)(|[^>]+)>/g, '\n<$1$2>');\r
6030                                                 h = h.replace(/<\/(p|h[1-6]|blockquote|div|title|style|pre|script|td|li)>\s*/g, '</$1>\n');\r
6031                                                 h = h.replace(/\n\n/g, '\n');\r
6032                                         }\r
6033                                 }\r
6034 \r
6035                                 h = t._unprotect(h, p);\r
6036 \r
6037                                 // Restore CDATA sections\r
6038                                 h = h.replace(/<!--\[CDATA\[([\s\S]+)\]\]-->/g, '<![CDATA[$1]]>');\r
6039 \r
6040                                 // Restore the \u00a0 character if raw mode is enabled\r
6041                                 if (s.entity_encoding == 'raw')\r
6042                                         h = h.replace(/<p>&nbsp;<\/p>|<p([^>]+)>&nbsp;<\/p>/g, '<p$1>\u00a0</p>');\r
6043                         }\r
6044 \r
6045                         o.content = h;\r
6046                 },\r
6047 \r
6048                 _serializeNode : function(n, inn) {\r
6049                         var t = this, s = t.settings, w = t.writer, hc, el, cn, i, l, a, at, no, v, nn, ru, ar, iv;\r
6050 \r
6051                         if (!s.node_filter || s.node_filter(n)) {\r
6052                                 switch (n.nodeType) {\r
6053                                         case 1: // Element\r
6054                                                 if (n.hasAttribute ? n.hasAttribute('mce_bogus') : n.getAttribute('mce_bogus'))\r
6055                                                         return;\r
6056 \r
6057                                                 iv = false;\r
6058                                                 hc = n.hasChildNodes();\r
6059                                                 nn = n.getAttribute('mce_name') || n.nodeName.toLowerCase();\r
6060 \r
6061                                                 // Add correct prefix on IE\r
6062                                                 if (isIE) {\r
6063                                                         if (n.scopeName !== 'HTML' && n.scopeName !== 'html')\r
6064                                                                 nn = n.scopeName + ':' + nn;\r
6065                                                 }\r
6066 \r
6067                                                 // Remove mce prefix on IE needed for the abbr element\r
6068                                                 if (nn.indexOf('mce:') === 0)\r
6069                                                         nn = nn.substring(4);\r
6070 \r
6071                                                 // Check if valid\r
6072                                                 if (!t.validElementsRE.test(nn) || (t.invalidElementsRE && t.invalidElementsRE.test(nn)) || inn) {\r
6073                                                         iv = true;\r
6074                                                         break;\r
6075                                                 }\r
6076 \r
6077                                                 if (isIE) {\r
6078                                                         // Fix IE content duplication (DOM can have multiple copies of the same node)\r
6079                                                         if (s.fix_content_duplication) {\r
6080                                                                 if (n.mce_serialized == t.key)\r
6081                                                                         return;\r
6082 \r
6083                                                                 n.mce_serialized = t.key;\r
6084                                                         }\r
6085 \r
6086                                                         // IE sometimes adds a / infront of the node name\r
6087                                                         if (nn.charAt(0) == '/')\r
6088                                                                 nn = nn.substring(1);\r
6089                                                 } else if (isGecko) {\r
6090                                                         // Ignore br elements\r
6091                                                         if (n.nodeName === 'BR' && n.getAttribute('type') == '_moz')\r
6092                                                                 return;\r
6093                                                 }\r
6094 \r
6095                                                 // Check if valid child\r
6096                                                 if (t.childRules) {\r
6097                                                         if (t.parentElementsRE.test(t.elementName)) {\r
6098                                                                 if (!t.childRules[t.elementName].test(nn)) {\r
6099                                                                         iv = true;\r
6100                                                                         break;\r
6101                                                                 }\r
6102                                                         }\r
6103 \r
6104                                                         t.elementName = nn;\r
6105                                                 }\r
6106 \r
6107                                                 ru = t.findRule(nn);\r
6108                                                 nn = ru.name || nn;\r
6109 \r
6110                                                 // Skip empty nodes or empty node name in IE\r
6111                                                 if ((!hc && ru.noEmpty) || (isIE && !nn)) {\r
6112                                                         iv = true;\r
6113                                                         break;\r
6114                                                 }\r
6115 \r
6116                                                 // Check required\r
6117                                                 if (ru.requiredAttribs) {\r
6118                                                         a = ru.requiredAttribs;\r
6119 \r
6120                                                         for (i = a.length - 1; i >= 0; i--) {\r
6121                                                                 if (this.dom.getAttrib(n, a[i]) !== '')\r
6122                                                                         break;\r
6123                                                         }\r
6124 \r
6125                                                         // None of the required was there\r
6126                                                         if (i == -1) {\r
6127                                                                 iv = true;\r
6128                                                                 break;\r
6129                                                         }\r
6130                                                 }\r
6131 \r
6132                                                 w.writeStartElement(nn);\r
6133 \r
6134                                                 // Add ordered attributes\r
6135                                                 if (ru.attribs) {\r
6136                                                         for (i=0, at = ru.attribs, l = at.length; i<l; i++) {\r
6137                                                                 a = at[i];\r
6138                                                                 v = t._getAttrib(n, a);\r
6139 \r
6140                                                                 if (v !== null)\r
6141                                                                         w.writeAttribute(a.name, v);\r
6142                                                         }\r
6143                                                 }\r
6144 \r
6145                                                 // Add wild attributes\r
6146                                                 if (ru.validAttribsRE) {\r
6147                                                         at = t.dom.getAttribs(n);\r
6148                                                         for (i=at.length-1; i>-1; i--) {\r
6149                                                                 no = at[i];\r
6150 \r
6151                                                                 if (no.specified) {\r
6152                                                                         a = no.nodeName.toLowerCase();\r
6153 \r
6154                                                                         if (s.invalid_attrs.test(a) || !ru.validAttribsRE.test(a))\r
6155                                                                                 continue;\r
6156 \r
6157                                                                         ar = t.findAttribRule(ru, a);\r
6158                                                                         v = t._getAttrib(n, ar, a);\r
6159 \r
6160                                                                         if (v !== null)\r
6161                                                                                 w.writeAttribute(a, v);\r
6162                                                                 }\r
6163                                                         }\r
6164                                                 }\r
6165 \r
6166                                                 // Padd empty nodes with a &nbsp;\r
6167                                                 if (ru.padd) {\r
6168                                                         // If it has only one bogus child, padd it anyway workaround for <td><br /></td> bug\r
6169                                                         if (hc && (cn = n.firstChild) && cn.nodeType === 1 && n.childNodes.length === 1) {\r
6170                                                                 if (cn.hasAttribute ? cn.hasAttribute('mce_bogus') : cn.getAttribute('mce_bogus'))\r
6171                                                                         w.writeText('\u00a0');\r
6172                                                         } else if (!hc)\r
6173                                                                 w.writeText('\u00a0'); // No children then padd it\r
6174                                                 }\r
6175 \r
6176                                                 break;\r
6177 \r
6178                                         case 3: // Text\r
6179                                                 // Check if valid child\r
6180                                                 if (t.childRules && t.parentElementsRE.test(t.elementName)) {\r
6181                                                         if (!t.childRules[t.elementName].test(n.nodeName))\r
6182                                                                 return;\r
6183                                                 }\r
6184 \r
6185                                                 return w.writeText(n.nodeValue);\r
6186 \r
6187                                         case 4: // CDATA\r
6188                                                 return w.writeCDATA(n.nodeValue);\r
6189 \r
6190                                         case 8: // Comment\r
6191                                                 return w.writeComment(n.nodeValue);\r
6192                                 }\r
6193                         } else if (n.nodeType == 1)\r
6194                                 hc = n.hasChildNodes();\r
6195 \r
6196                         if (hc) {\r
6197                                 cn = n.firstChild;\r
6198 \r
6199                                 while (cn) {\r
6200                                         t._serializeNode(cn);\r
6201                                         t.elementName = nn;\r
6202                                         cn = cn.nextSibling;\r
6203                                 }\r
6204                         }\r
6205 \r
6206                         // Write element end\r
6207                         if (!iv) {\r
6208                                 if (hc || !s.closed.test(nn))\r
6209                                         w.writeFullEndElement();\r
6210                                 else\r
6211                                         w.writeEndElement();\r
6212                         }\r
6213                 },\r
6214 \r
6215                 _protect : function(o) {\r
6216                         var t = this;\r
6217 \r
6218                         o.items = o.items || [];\r
6219 \r
6220                         function enc(s) {\r
6221                                 return s.replace(/[\r\n\\]/g, function(c) {\r
6222                                         if (c === '\n')\r
6223                                                 return '\\n';\r
6224                                         else if (c === '\\')\r
6225                                                 return '\\\\';\r
6226 \r
6227                                         return '\\r';\r
6228                                 });\r
6229                         };\r
6230 \r
6231                         function dec(s) {\r
6232                                 return s.replace(/\\[\\rn]/g, function(c) {\r
6233                                         if (c === '\\n')\r
6234                                                 return '\n';\r
6235                                         else if (c === '\\\\')\r
6236                                                 return '\\';\r
6237 \r
6238                                         return '\r';\r
6239                                 });\r
6240                         };\r
6241 \r
6242                         each(o.patterns, function(p) {\r
6243                                 o.content = dec(enc(o.content).replace(p.pattern, function(x, a, b, c) {\r
6244                                         b = dec(b);\r
6245 \r
6246                                         if (p.encode)\r
6247                                                 b = t._encode(b);\r
6248 \r
6249                                         o.items.push(b);\r
6250                                         return a + '<!--mce:' + (o.items.length - 1) + '-->' + c;\r
6251                                 }));\r
6252                         });\r
6253 \r
6254                         return o;\r
6255                 },\r
6256 \r
6257                 _unprotect : function(h, o) {\r
6258                         h = h.replace(/\<!--mce:([0-9]+)--\>/g, function(a, b) {\r
6259                                 return o.items[parseInt(b)];\r
6260                         });\r
6261 \r
6262                         o.items = [];\r
6263 \r
6264                         return h;\r
6265                 },\r
6266 \r
6267                 _encode : function(h) {\r
6268                         var t = this, s = t.settings, l;\r
6269 \r
6270                         // Entity encode\r
6271                         if (s.entity_encoding !== 'raw') {\r
6272                                 if (s.entity_encoding.indexOf('named') != -1) {\r
6273                                         t.setEntities(s.entities);\r
6274                                         l = t.entityLookup;\r
6275 \r
6276                                         h = h.replace(t.entitiesRE, function(a) {\r
6277                                                 var v;\r
6278 \r
6279                                                 if (v = l[a])\r
6280                                                         a = '&' + v + ';';\r
6281 \r
6282                                                 return a;\r
6283                                         });\r
6284                                 }\r
6285 \r
6286                                 if (s.entity_encoding.indexOf('numeric') != -1) {\r
6287                                         h = h.replace(/[\u007E-\uFFFF]/g, function(a) {\r
6288                                                 return '&#' + a.charCodeAt(0) + ';';\r
6289                                         });\r
6290                                 }\r
6291                         }\r
6292 \r
6293                         return h;\r
6294                 },\r
6295 \r
6296                 _setup : function() {\r
6297                         var t = this, s = this.settings;\r
6298 \r
6299                         if (t.done)\r
6300                                 return;\r
6301 \r
6302                         t.done = 1;\r
6303 \r
6304                         t.setRules(s.valid_elements);\r
6305                         t.addRules(s.extended_valid_elements);\r
6306                         t.addValidChildRules(s.valid_child_elements);\r
6307 \r
6308                         if (s.invalid_elements)\r
6309                                 t.invalidElementsRE = new RegExp('^(' + wildcardToRE(s.invalid_elements.replace(/,/g, '|').toLowerCase()) + ')$');\r
6310 \r
6311                         if (s.attrib_value_filter)\r
6312                                 t.attribValueFilter = s.attribValueFilter;\r
6313                 },\r
6314 \r
6315                 _getAttrib : function(n, a, na) {\r
6316                         var i, v;\r
6317 \r
6318                         na = na || a.name;\r
6319 \r
6320                         if (a.forcedVal && (v = a.forcedVal)) {\r
6321                                 if (v === '{$uid}')\r
6322                                         return this.dom.uniqueId();\r
6323 \r
6324                                 return v;\r
6325                         }\r
6326 \r
6327                         v = this.dom.getAttrib(n, na);\r
6328 \r
6329                         // Bool attr\r
6330                         if (this.settings.bool_attrs.test(na) && v) {\r
6331                                 v = ('' + v).toLowerCase();\r
6332 \r
6333                                 if (v === 'false' || v === '0')\r
6334                                         return null;\r
6335 \r
6336                                 v = na;\r
6337                         }\r
6338 \r
6339                         switch (na) {\r
6340                                 case 'rowspan':\r
6341                                 case 'colspan':\r
6342                                         // Whats the point? Remove usless attribute value\r
6343                                         if (v == '1')\r
6344                                                 v = '';\r
6345 \r
6346                                         break;\r
6347                         }\r
6348 \r
6349                         if (this.attribValueFilter)\r
6350                                 v = this.attribValueFilter(na, v, n);\r
6351 \r
6352                         if (a.validVals) {\r
6353                                 for (i = a.validVals.length - 1; i >= 0; i--) {\r
6354                                         if (v == a.validVals[i])\r
6355                                                 break;\r
6356                                 }\r
6357 \r
6358                                 if (i == -1)\r
6359                                         return null;\r
6360                         }\r
6361 \r
6362                         if (v === '' && typeof(a.defaultVal) != 'undefined') {\r
6363                                 v = a.defaultVal;\r
6364 \r
6365                                 if (v === '{$uid}')\r
6366                                         return this.dom.uniqueId();\r
6367 \r
6368                                 return v;\r
6369                         } else {\r
6370                                 // Remove internal mceItemXX classes when content is extracted from editor\r
6371                                 if (na == 'class' && this.processObj.get)\r
6372                                         v = v.replace(/\s?mceItem\w+\s?/g, '');\r
6373                         }\r
6374 \r
6375                         if (v === '')\r
6376                                 return null;\r
6377 \r
6378 \r
6379                         return v;\r
6380                 }\r
6381 \r
6382                 });\r
6383 })(tinymce);\r
6384 (function(tinymce) {\r
6385         var each = tinymce.each, Event = tinymce.dom.Event;\r
6386 \r
6387         tinymce.create('tinymce.dom.ScriptLoader', {\r
6388                 ScriptLoader : function(s) {\r
6389                         this.settings = s || {};\r
6390                         this.queue = [];\r
6391                         this.lookup = {};\r
6392                 },\r
6393 \r
6394                 isDone : function(u) {\r
6395                         return this.lookup[u] ? this.lookup[u].state == 2 : 0;\r
6396                 },\r
6397 \r
6398                 markDone : function(u) {\r
6399                         this.lookup[u] = {state : 2, url : u};\r
6400                 },\r
6401 \r
6402                 add : function(u, cb, s, pr) {\r
6403                         var t = this, lo = t.lookup, o;\r
6404 \r
6405                         if (o = lo[u]) {\r
6406                                 // Is loaded fire callback\r
6407                                 if (cb && o.state == 2)\r
6408                                         cb.call(s || this);\r
6409 \r
6410                                 return o;\r
6411                         }\r
6412 \r
6413                         o = {state : 0, url : u, func : cb, scope : s || this};\r
6414 \r
6415                         if (pr)\r
6416                                 t.queue.unshift(o);\r
6417                         else\r
6418                                 t.queue.push(o);\r
6419 \r
6420                         lo[u] = o;\r
6421 \r
6422                         return o;\r
6423                 },\r
6424 \r
6425                 load : function(u, cb, s) {\r
6426                         var t = this, o;\r
6427 \r
6428                         if (o = t.lookup[u]) {\r
6429                                 // Is loaded fire callback\r
6430                                 if (cb && o.state == 2)\r
6431                                         cb.call(s || t);\r
6432 \r
6433                                 return o;\r
6434                         }\r
6435 \r
6436                         function loadScript(u) {\r
6437                                 if (Event.domLoaded || t.settings.strict_mode) {\r
6438                                         tinymce.util.XHR.send({\r
6439                                                 url : tinymce._addVer(u),\r
6440                                                 error : t.settings.error,\r
6441                                                 async : false,\r
6442                                                 success : function(co) {\r
6443                                                         t.eval(co);\r
6444                                                 }\r
6445                                         });\r
6446                                 } else\r
6447                                         document.write('<script type="text/javascript" src="' + tinymce._addVer(u) + '"></script>');\r
6448                         };\r
6449 \r
6450                         if (!tinymce.is(u, 'string')) {\r
6451                                 each(u, function(u) {\r
6452                                         loadScript(u);\r
6453                                 });\r
6454 \r
6455                                 if (cb)\r
6456                                         cb.call(s || t);\r
6457                         } else {\r
6458                                 loadScript(u);\r
6459 \r
6460                                 if (cb)\r
6461                                         cb.call(s || t);\r
6462                         }\r
6463                 },\r
6464 \r
6465                 loadQueue : function(cb, s) {\r
6466                         var t = this;\r
6467 \r
6468                         if (!t.queueLoading) {\r
6469                                 t.queueLoading = 1;\r
6470                                 t.queueCallbacks = [];\r
6471 \r
6472                                 t.loadScripts(t.queue, function() {\r
6473                                         t.queueLoading = 0;\r
6474 \r
6475                                         if (cb)\r
6476                                                 cb.call(s || t);\r
6477 \r
6478                                         each(t.queueCallbacks, function(o) {\r
6479                                                 o.func.call(o.scope);\r
6480                                         });\r
6481                                 });\r
6482                         } else if (cb)\r
6483                                 t.queueCallbacks.push({func : cb, scope : s || t});\r
6484                 },\r
6485 \r
6486                 eval : function(co) {\r
6487                         var w = window;\r
6488 \r
6489                         // Evaluate script\r
6490                         if (!w.execScript) {\r
6491                                 try {\r
6492                                         eval.call(w, co);\r
6493                                 } catch (ex) {\r
6494                                         eval(co, w); // Firefox 3.0a8\r
6495                                 }\r
6496                         } else\r
6497                                 w.execScript(co); // IE\r
6498                 },\r
6499 \r
6500                 loadScripts : function(sc, cb, s) {\r
6501                         var t = this, lo = t.lookup;\r
6502 \r
6503                         function done(o) {\r
6504                                 o.state = 2; // Has been loaded\r
6505 \r
6506                                 // Run callback\r
6507                                 if (o.func)\r
6508                                         o.func.call(o.scope || t);\r
6509                         };\r
6510 \r
6511                         function allDone() {\r
6512                                 var l;\r
6513 \r
6514                                 // Check if all files are loaded\r
6515                                 l = sc.length;\r
6516                                 each(sc, function(o) {\r
6517                                         o = lo[o.url];\r
6518 \r
6519                                         if (o.state === 2) {// It has finished loading\r
6520                                                 done(o);\r
6521                                                 l--;\r
6522                                         } else\r
6523                                                 load(o);\r
6524                                 });\r
6525 \r
6526                                 // They are all loaded\r
6527                                 if (l === 0 && cb) {\r
6528                                         cb.call(s || t);\r
6529                                         cb = 0;\r
6530                                 }\r
6531                         };\r
6532 \r
6533                         function load(o) {\r
6534                                 if (o.state > 0)\r
6535                                         return;\r
6536 \r
6537                                 o.state = 1; // Is loading\r
6538 \r
6539                                 tinymce.dom.ScriptLoader.loadScript(o.url, function() {\r
6540                                         done(o);\r
6541                                         allDone();\r
6542                                 });\r
6543 \r
6544                                 /*\r
6545                                 tinymce.util.XHR.send({\r
6546                                         url : o.url,\r
6547                                         error : t.settings.error,\r
6548                                         success : function(co) {\r
6549                                                 t.eval(co);\r
6550                                                 done(o);\r
6551                                                 allDone();\r
6552                                         }\r
6553                                 });\r
6554                                 */\r
6555                         };\r
6556 \r
6557                         each(sc, function(o) {\r
6558                                 var u = o.url;\r
6559 \r
6560                                 // Add to queue if needed\r
6561                                 if (!lo[u]) {\r
6562                                         lo[u] = o;\r
6563                                         t.queue.push(o);\r
6564                                 } else\r
6565                                         o = lo[u];\r
6566 \r
6567                                 // Is already loading or has been loaded\r
6568                                 if (o.state > 0)\r
6569                                         return;\r
6570 \r
6571                                 if (!Event.domLoaded && !t.settings.strict_mode) {\r
6572                                         var ix, ol = '';\r
6573 \r
6574                                         // Add onload events\r
6575                                         if (cb || o.func) {\r
6576                                                 o.state = 1; // Is loading\r
6577 \r
6578                                                 ix = tinymce.dom.ScriptLoader._addOnLoad(function() {\r
6579                                                         done(o);\r
6580                                                         allDone();\r
6581                                                 });\r
6582 \r
6583                                                 if (tinymce.isIE)\r
6584                                                         ol = ' onreadystatechange="';\r
6585                                                 else\r
6586                                                         ol = ' onload="';\r
6587 \r
6588                                                 ol += 'tinymce.dom.ScriptLoader._onLoad(this,\'' + u + '\',' + ix + ');"';\r
6589                                         }\r
6590 \r
6591                                         document.write('<script type="text/javascript" src="' + tinymce._addVer(u) + '"' + ol + '></script>');\r
6592 \r
6593                                         if (!o.func)\r
6594                                                 done(o);\r
6595                                 } else\r
6596                                         load(o);\r
6597                         });\r
6598 \r
6599                         allDone();\r
6600                 },\r
6601 \r
6602                 // Static methods\r
6603                 'static' : {\r
6604                         _addOnLoad : function(f) {\r
6605                                 var t = this;\r
6606 \r
6607                                 t._funcs = t._funcs || [];\r
6608                                 t._funcs.push(f);\r
6609 \r
6610                                 return t._funcs.length - 1;\r
6611                         },\r
6612 \r
6613                         _onLoad : function(e, u, ix) {\r
6614                                 if (!tinymce.isIE || e.readyState == 'complete')\r
6615                                         this._funcs[ix].call(this);\r
6616                         },\r
6617 \r
6618                         loadScript : function(u, cb) {\r
6619                                 var id = tinymce.DOM.uniqueId(), e;\r
6620 \r
6621                                 function done() {\r
6622                                         Event.clear(id);\r
6623                                         tinymce.DOM.remove(id);\r
6624 \r
6625                                         if (cb) {\r
6626                                                 cb.call(document, u);\r
6627                                                 cb = 0;\r
6628                                         }\r
6629                                 };\r
6630 \r
6631                                 if (tinymce.isIE) {\r
6632 /*                                      Event.add(e, 'readystatechange', function(e) {\r
6633                                                 if (e.target && e.target.readyState == 'complete')\r
6634                                                         done();\r
6635                                         });*/\r
6636 \r
6637                                         tinymce.util.XHR.send({\r
6638                                                 url : tinymce._addVer(u),\r
6639                                                 async : false,\r
6640                                                 success : function(co) {\r
6641                                                         window.execScript(co);\r
6642                                                         done();\r
6643                                                 }\r
6644                                         });\r
6645                                 } else {\r
6646                                         e = tinymce.DOM.create('script', {id : id, type : 'text/javascript', src : tinymce._addVer(u)});\r
6647                                         Event.add(e, 'load', done);\r
6648 \r
6649                                         // Check for head or body\r
6650                                         (document.getElementsByTagName('head')[0] || document.body).appendChild(e);\r
6651                                 }\r
6652                         }\r
6653                 }\r
6654 \r
6655                 });\r
6656 \r
6657         // Global script loader\r
6658         tinymce.ScriptLoader = new tinymce.dom.ScriptLoader();\r
6659 })(tinymce);\r
6660 (function(tinymce) {\r
6661         // Shorten class names\r
6662         var DOM = tinymce.DOM, is = tinymce.is;\r
6663 \r
6664         tinymce.create('tinymce.ui.Control', {\r
6665                 Control : function(id, s) {\r
6666                         this.id = id;\r
6667                         this.settings = s = s || {};\r
6668                         this.rendered = false;\r
6669                         this.onRender = new tinymce.util.Dispatcher(this);\r
6670                         this.classPrefix = '';\r
6671                         this.scope = s.scope || this;\r
6672                         this.disabled = 0;\r
6673                         this.active = 0;\r
6674                 },\r
6675 \r
6676                 setDisabled : function(s) {\r
6677                         var e;\r
6678 \r
6679                         if (s != this.disabled) {\r
6680                                 e = DOM.get(this.id);\r
6681 \r
6682                                 // Add accessibility title for unavailable actions\r
6683                                 if (e && this.settings.unavailable_prefix) {\r
6684                                         if (s) {\r
6685                                                 this.prevTitle = e.title;\r
6686                                                 e.title = this.settings.unavailable_prefix + ": " + e.title;\r
6687                                         } else\r
6688                                                 e.title = this.prevTitle;\r
6689                                 }\r
6690 \r
6691                                 this.setState('Disabled', s);\r
6692                                 this.setState('Enabled', !s);\r
6693                                 this.disabled = s;\r
6694                         }\r
6695                 },\r
6696 \r
6697                 isDisabled : function() {\r
6698                         return this.disabled;\r
6699                 },\r
6700 \r
6701                 setActive : function(s) {\r
6702                         if (s != this.active) {\r
6703                                 this.setState('Active', s);\r
6704                                 this.active = s;\r
6705                         }\r
6706                 },\r
6707 \r
6708                 isActive : function() {\r
6709                         return this.active;\r
6710                 },\r
6711 \r
6712                 setState : function(c, s) {\r
6713                         var n = DOM.get(this.id);\r
6714 \r
6715                         c = this.classPrefix + c;\r
6716 \r
6717                         if (s)\r
6718                                 DOM.addClass(n, c);\r
6719                         else\r
6720                                 DOM.removeClass(n, c);\r
6721                 },\r
6722 \r
6723                 isRendered : function() {\r
6724                         return this.rendered;\r
6725                 },\r
6726 \r
6727                 renderHTML : function() {\r
6728                 },\r
6729 \r
6730                 renderTo : function(n) {\r
6731                         DOM.setHTML(n, this.renderHTML());\r
6732                 },\r
6733 \r
6734                 postRender : function() {\r
6735                         var t = this, b;\r
6736 \r
6737                         // Set pending states\r
6738                         if (is(t.disabled)) {\r
6739                                 b = t.disabled;\r
6740                                 t.disabled = -1;\r
6741                                 t.setDisabled(b);\r
6742                         }\r
6743 \r
6744                         if (is(t.active)) {\r
6745                                 b = t.active;\r
6746                                 t.active = -1;\r
6747                                 t.setActive(b);\r
6748                         }\r
6749                 },\r
6750 \r
6751                 remove : function() {\r
6752                         DOM.remove(this.id);\r
6753                         this.destroy();\r
6754                 },\r
6755 \r
6756                 destroy : function() {\r
6757                         tinymce.dom.Event.clear(this.id);\r
6758                 }\r
6759 \r
6760                 });\r
6761 })(tinymce);tinymce.create('tinymce.ui.Container:tinymce.ui.Control', {\r
6762         Container : function(id, s) {\r
6763                 this.parent(id, s);\r
6764                 this.controls = [];\r
6765                 this.lookup = {};\r
6766         },\r
6767 \r
6768         add : function(c) {\r
6769                 this.lookup[c.id] = c;\r
6770                 this.controls.push(c);\r
6771 \r
6772                 return c;\r
6773         },\r
6774 \r
6775         get : function(n) {\r
6776                 return this.lookup[n];\r
6777         }\r
6778 \r
6779         });\r
6780 \r
6781 tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {\r
6782         Separator : function(id, s) {\r
6783                 this.parent(id, s);\r
6784                 this.classPrefix = 'mceSeparator';\r
6785         },\r
6786 \r
6787         renderHTML : function() {\r
6788                 return tinymce.DOM.createHTML('span', {'class' : this.classPrefix});\r
6789         }\r
6790 \r
6791         });\r
6792 (function(tinymce) {\r
6793         var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;\r
6794 \r
6795         tinymce.create('tinymce.ui.MenuItem:tinymce.ui.Control', {\r
6796                 MenuItem : function(id, s) {\r
6797                         this.parent(id, s);\r
6798                         this.classPrefix = 'mceMenuItem';\r
6799                 },\r
6800 \r
6801                 setSelected : function(s) {\r
6802                         this.setState('Selected', s);\r
6803                         this.selected = s;\r
6804                 },\r
6805 \r
6806                 isSelected : function() {\r
6807                         return this.selected;\r
6808                 },\r
6809 \r
6810                 postRender : function() {\r
6811                         var t = this;\r
6812                         \r
6813                         t.parent();\r
6814 \r
6815                         // Set pending state\r
6816                         if (is(t.selected))\r
6817                                 t.setSelected(t.selected);\r
6818                 }\r
6819 \r
6820                 });\r
6821 })(tinymce);\r
6822 (function(tinymce) {\r
6823         var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;\r
6824 \r
6825         tinymce.create('tinymce.ui.Menu:tinymce.ui.MenuItem', {\r
6826                 Menu : function(id, s) {\r
6827                         var t = this;\r
6828 \r
6829                         t.parent(id, s);\r
6830                         t.items = {};\r
6831                         t.collapsed = false;\r
6832                         t.menuCount = 0;\r
6833                         t.onAddItem = new tinymce.util.Dispatcher(this);\r
6834                 },\r
6835 \r
6836                 expand : function(d) {\r
6837                         var t = this;\r
6838 \r
6839                         if (d) {\r
6840                                 walk(t, function(o) {\r
6841                                         if (o.expand)\r
6842                                                 o.expand();\r
6843                                 }, 'items', t);\r
6844                         }\r
6845 \r
6846                         t.collapsed = false;\r
6847                 },\r
6848 \r
6849                 collapse : function(d) {\r
6850                         var t = this;\r
6851 \r
6852                         if (d) {\r
6853                                 walk(t, function(o) {\r
6854                                         if (o.collapse)\r
6855                                                 o.collapse();\r
6856                                 }, 'items', t);\r
6857                         }\r
6858 \r
6859                         t.collapsed = true;\r
6860                 },\r
6861 \r
6862                 isCollapsed : function() {\r
6863                         return this.collapsed;\r
6864                 },\r
6865 \r
6866                 add : function(o) {\r
6867                         if (!o.settings)\r
6868                                 o = new tinymce.ui.MenuItem(o.id || DOM.uniqueId(), o);\r
6869 \r
6870                         this.onAddItem.dispatch(this, o);\r
6871 \r
6872                         return this.items[o.id] = o;\r
6873                 },\r
6874 \r
6875                 addSeparator : function() {\r
6876                         return this.add({separator : true});\r
6877                 },\r
6878 \r
6879                 addMenu : function(o) {\r
6880                         if (!o.collapse)\r
6881                                 o = this.createMenu(o);\r
6882 \r
6883                         this.menuCount++;\r
6884 \r
6885                         return this.add(o);\r
6886                 },\r
6887 \r
6888                 hasMenus : function() {\r
6889                         return this.menuCount !== 0;\r
6890                 },\r
6891 \r
6892                 remove : function(o) {\r
6893                         delete this.items[o.id];\r
6894                 },\r
6895 \r
6896                 removeAll : function() {\r
6897                         var t = this;\r
6898 \r
6899                         walk(t, function(o) {\r
6900                                 if (o.removeAll)\r
6901                                         o.removeAll();\r
6902                                 else\r
6903                                         o.remove();\r
6904 \r
6905                                 o.destroy();\r
6906                         }, 'items', t);\r
6907 \r
6908                         t.items = {};\r
6909                 },\r
6910 \r
6911                 createMenu : function(o) {\r
6912                         var m = new tinymce.ui.Menu(o.id || DOM.uniqueId(), o);\r
6913 \r
6914                         m.onAddItem.add(this.onAddItem.dispatch, this.onAddItem);\r
6915 \r
6916                         return m;\r
6917                 }\r
6918 \r
6919                 });\r
6920 })(tinymce);(function(tinymce) {\r
6921         var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, Event = tinymce.dom.Event, Element = tinymce.dom.Element;\r
6922 \r
6923         tinymce.create('tinymce.ui.DropMenu:tinymce.ui.Menu', {\r
6924                 DropMenu : function(id, s) {\r
6925                         s = s || {};\r
6926                         s.container = s.container || DOM.doc.body;\r
6927                         s.offset_x = s.offset_x || 0;\r
6928                         s.offset_y = s.offset_y || 0;\r
6929                         s.vp_offset_x = s.vp_offset_x || 0;\r
6930                         s.vp_offset_y = s.vp_offset_y || 0;\r
6931 \r
6932                         if (is(s.icons) && !s.icons)\r
6933                                 s['class'] += ' mceNoIcons';\r
6934 \r
6935                         this.parent(id, s);\r
6936                         this.onShowMenu = new tinymce.util.Dispatcher(this);\r
6937                         this.onHideMenu = new tinymce.util.Dispatcher(this);\r
6938                         this.classPrefix = 'mceMenu';\r
6939                 },\r
6940 \r
6941                 createMenu : function(s) {\r
6942                         var t = this, cs = t.settings, m;\r
6943 \r
6944                         s.container = s.container || cs.container;\r
6945                         s.parent = t;\r
6946                         s.constrain = s.constrain || cs.constrain;\r
6947                         s['class'] = s['class'] || cs['class'];\r
6948                         s.vp_offset_x = s.vp_offset_x || cs.vp_offset_x;\r
6949                         s.vp_offset_y = s.vp_offset_y || cs.vp_offset_y;\r
6950                         m = new tinymce.ui.DropMenu(s.id || DOM.uniqueId(), s);\r
6951 \r
6952                         m.onAddItem.add(t.onAddItem.dispatch, t.onAddItem);\r
6953 \r
6954                         return m;\r
6955                 },\r
6956 \r
6957                 update : function() {\r
6958                         var t = this, s = t.settings, tb = DOM.get('menu_' + t.id + '_tbl'), co = DOM.get('menu_' + t.id + '_co'), tw, th;\r
6959 \r
6960                         tw = s.max_width ? Math.min(tb.clientWidth, s.max_width) : tb.clientWidth;\r
6961                         th = s.max_height ? Math.min(tb.clientHeight, s.max_height) : tb.clientHeight;\r
6962 \r
6963                         if (!DOM.boxModel)\r
6964                                 t.element.setStyles({width : tw + 2, height : th + 2});\r
6965                         else\r
6966                                 t.element.setStyles({width : tw, height : th});\r
6967 \r
6968                         if (s.max_width)\r
6969                                 DOM.setStyle(co, 'width', tw);\r
6970 \r
6971                         if (s.max_height) {\r
6972                                 DOM.setStyle(co, 'height', th);\r
6973 \r
6974                                 if (tb.clientHeight < s.max_height)\r
6975                                         DOM.setStyle(co, 'overflow', 'hidden');\r
6976                         }\r
6977                 },\r
6978 \r
6979                 showMenu : function(x, y, px) {\r
6980                         var t = this, s = t.settings, co, vp = DOM.getViewPort(), w, h, mx, my, ot = 2, dm, tb, cp = t.classPrefix;\r
6981 \r
6982                         t.collapse(1);\r
6983 \r
6984                         if (t.isMenuVisible)\r
6985                                 return;\r
6986 \r
6987                         if (!t.rendered) {\r
6988                                 co = DOM.add(t.settings.container, t.renderNode());\r
6989 \r
6990                                 each(t.items, function(o) {\r
6991                                         o.postRender();\r
6992                                 });\r
6993 \r
6994                                 t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});\r
6995                         } else\r
6996                                 co = DOM.get('menu_' + t.id);\r
6997 \r
6998                         // Move layer out of sight unless it's Opera since it scrolls to top of page due to an bug\r
6999                         if (!tinymce.isOpera)\r
7000                                 DOM.setStyles(co, {left : -0xFFFF , top : -0xFFFF});\r
7001 \r
7002                         DOM.show(co);\r
7003                         t.update();\r
7004 \r
7005                         x += s.offset_x || 0;\r
7006                         y += s.offset_y || 0;\r
7007                         vp.w -= 4;\r
7008                         vp.h -= 4;\r
7009 \r
7010                         // Move inside viewport if not submenu\r
7011                         if (s.constrain) {\r
7012                                 w = co.clientWidth - ot;\r
7013                                 h = co.clientHeight - ot;\r
7014                                 mx = vp.x + vp.w;\r
7015                                 my = vp.y + vp.h;\r
7016 \r
7017                                 if ((x + s.vp_offset_x + w) > mx)\r
7018                                         x = px ? px - w : Math.max(0, (mx - s.vp_offset_x) - w);\r
7019 \r
7020                                 if ((y + s.vp_offset_y + h) > my)\r
7021                                         y = Math.max(0, (my - s.vp_offset_y) - h);\r
7022                         }\r
7023 \r
7024                         DOM.setStyles(co, {left : x , top : y});\r
7025                         t.element.update();\r
7026 \r
7027                         t.isMenuVisible = 1;\r
7028                         t.mouseClickFunc = Event.add(co, 'click', function(e) {\r
7029                                 var m;\r
7030 \r
7031                                 e = e.target;\r
7032 \r
7033                                 if (e && (e = DOM.getParent(e, 'tr')) && !DOM.hasClass(e, cp + 'ItemSub')) {\r
7034                                         m = t.items[e.id];\r
7035 \r
7036                                         if (m.isDisabled())\r
7037                                                 return;\r
7038 \r
7039                                         dm = t;\r
7040 \r
7041                                         while (dm) {\r
7042                                                 if (dm.hideMenu)\r
7043                                                         dm.hideMenu();\r
7044 \r
7045                                                 dm = dm.settings.parent;\r
7046                                         }\r
7047 \r
7048                                         if (m.settings.onclick)\r
7049                                                 m.settings.onclick(e);\r
7050 \r
7051                                         return Event.cancel(e); // Cancel to fix onbeforeunload problem\r
7052                                 }\r
7053                         });\r
7054 \r
7055                         if (t.hasMenus()) {\r
7056                                 t.mouseOverFunc = Event.add(co, 'mouseover', function(e) {\r
7057                                         var m, r, mi;\r
7058 \r
7059                                         e = e.target;\r
7060                                         if (e && (e = DOM.getParent(e, 'tr'))) {\r
7061                                                 m = t.items[e.id];\r
7062 \r
7063                                                 if (t.lastMenu)\r
7064                                                         t.lastMenu.collapse(1);\r
7065 \r
7066                                                 if (m.isDisabled())\r
7067                                                         return;\r
7068 \r
7069                                                 if (e && DOM.hasClass(e, cp + 'ItemSub')) {\r
7070                                                         //p = DOM.getPos(s.container);\r
7071                                                         r = DOM.getRect(e);\r
7072                                                         m.showMenu((r.x + r.w - ot), r.y - ot, r.x);\r
7073                                                         t.lastMenu = m;\r
7074                                                         DOM.addClass(DOM.get(m.id).firstChild, cp + 'ItemActive');\r
7075                                                 }\r
7076                                         }\r
7077                                 });\r
7078                         }\r
7079 \r
7080                         t.onShowMenu.dispatch(t);\r
7081 \r
7082                         if (s.keyboard_focus) {\r
7083                                 Event.add(co, 'keydown', t._keyHandler, t);\r
7084                                 DOM.select('a', 'menu_' + t.id)[0].focus(); // Select first link\r
7085                                 t._focusIdx = 0;\r
7086                         }\r
7087                 },\r
7088 \r
7089                 hideMenu : function(c) {\r
7090                         var t = this, co = DOM.get('menu_' + t.id), e;\r
7091 \r
7092                         if (!t.isMenuVisible)\r
7093                                 return;\r
7094 \r
7095                         Event.remove(co, 'mouseover', t.mouseOverFunc);\r
7096                         Event.remove(co, 'click', t.mouseClickFunc);\r
7097                         Event.remove(co, 'keydown', t._keyHandler);\r
7098                         DOM.hide(co);\r
7099                         t.isMenuVisible = 0;\r
7100 \r
7101                         if (!c)\r
7102                                 t.collapse(1);\r
7103 \r
7104                         if (t.element)\r
7105                                 t.element.hide();\r
7106 \r
7107                         if (e = DOM.get(t.id))\r
7108                                 DOM.removeClass(e.firstChild, t.classPrefix + 'ItemActive');\r
7109 \r
7110                         t.onHideMenu.dispatch(t);\r
7111                 },\r
7112 \r
7113                 add : function(o) {\r
7114                         var t = this, co;\r
7115 \r
7116                         o = t.parent(o);\r
7117 \r
7118                         if (t.isRendered && (co = DOM.get('menu_' + t.id)))\r
7119                                 t._add(DOM.select('tbody', co)[0], o);\r
7120 \r
7121                         return o;\r
7122                 },\r
7123 \r
7124                 collapse : function(d) {\r
7125                         this.parent(d);\r
7126                         this.hideMenu(1);\r
7127                 },\r
7128 \r
7129                 remove : function(o) {\r
7130                         DOM.remove(o.id);\r
7131                         this.destroy();\r
7132 \r
7133                         return this.parent(o);\r
7134                 },\r
7135 \r
7136                 destroy : function() {\r
7137                         var t = this, co = DOM.get('menu_' + t.id);\r
7138 \r
7139                         Event.remove(co, 'mouseover', t.mouseOverFunc);\r
7140                         Event.remove(co, 'click', t.mouseClickFunc);\r
7141 \r
7142                         if (t.element)\r
7143                                 t.element.remove();\r
7144 \r
7145                         DOM.remove(co);\r
7146                 },\r
7147 \r
7148                 renderNode : function() {\r
7149                         var t = this, s = t.settings, n, tb, co, w;\r
7150 \r
7151                         w = DOM.create('div', {id : 'menu_' + t.id, 'class' : s['class'], 'style' : 'position:absolute;left:0;top:0;z-index:200000'});\r
7152                         co = DOM.add(w, 'div', {id : 'menu_' + t.id + '_co', 'class' : t.classPrefix + (s['class'] ? ' ' + s['class'] : '')});\r
7153                         t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});\r
7154 \r
7155                         if (s.menu_line)\r
7156                                 DOM.add(co, 'span', {'class' : t.classPrefix + 'Line'});\r
7157 \r
7158 //                      n = DOM.add(co, 'div', {id : 'menu_' + t.id + '_co', 'class' : 'mceMenuContainer'});\r
7159                         n = DOM.add(co, 'table', {id : 'menu_' + t.id + '_tbl', border : 0, cellPadding : 0, cellSpacing : 0});\r
7160                         tb = DOM.add(n, 'tbody');\r
7161 \r
7162                         each(t.items, function(o) {\r
7163                                 t._add(tb, o);\r
7164                         });\r
7165 \r
7166                         t.rendered = true;\r
7167 \r
7168                         return w;\r
7169                 },\r
7170 \r
7171                 // Internal functions\r
7172 \r
7173                 _keyHandler : function(e) {\r
7174                         var t = this, kc = e.keyCode;\r
7175 \r
7176                         function focus(d) {\r
7177                                 var i = t._focusIdx + d, e = DOM.select('a', 'menu_' + t.id)[i];\r
7178 \r
7179                                 if (e) {\r
7180                                         t._focusIdx = i;\r
7181                                         e.focus();\r
7182                                 }\r
7183                         };\r
7184 \r
7185                         switch (kc) {\r
7186                                 case 38:\r
7187                                         focus(-1); // Select first link\r
7188                                         return;\r
7189 \r
7190                                 case 40:\r
7191                                         focus(1);\r
7192                                         return;\r
7193 \r
7194                                 case 13:\r
7195                                         return;\r
7196 \r
7197                                 case 27:\r
7198                                         return this.hideMenu();\r
7199                         }\r
7200                 },\r
7201 \r
7202                 _add : function(tb, o) {\r
7203                         var n, s = o.settings, a, ro, it, cp = this.classPrefix, ic;\r
7204 \r
7205                         if (s.separator) {\r
7206                                 ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'ItemSeparator'});\r
7207                                 DOM.add(ro, 'td', {'class' : cp + 'ItemSeparator'});\r
7208 \r
7209                                 if (n = ro.previousSibling)\r
7210                                         DOM.addClass(n, 'mceLast');\r
7211 \r
7212                                 return;\r
7213                         }\r
7214 \r
7215                         n = ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'Item ' + cp + 'ItemEnabled'});\r
7216                         n = it = DOM.add(n, 'td');\r
7217                         n = a = DOM.add(n, 'a', {href : 'javascript:;', onclick : "return false;", onmousedown : 'return false;'});\r
7218 \r
7219                         DOM.addClass(it, s['class']);\r
7220 //                      n = DOM.add(n, 'span', {'class' : 'item'});\r
7221 \r
7222                         ic = DOM.add(n, 'span', {'class' : 'mceIcon' + (s.icon ? ' mce_' + s.icon : '')});\r
7223 \r
7224                         if (s.icon_src)\r
7225                                 DOM.add(ic, 'img', {src : s.icon_src});\r
7226 \r
7227                         n = DOM.add(n, s.element || 'span', {'class' : 'mceText', title : o.settings.title}, o.settings.title);\r
7228 \r
7229                         if (o.settings.style)\r
7230                                 DOM.setAttrib(n, 'style', o.settings.style);\r
7231 \r
7232                         if (tb.childNodes.length == 1)\r
7233                                 DOM.addClass(ro, 'mceFirst');\r
7234 \r
7235                         if ((n = ro.previousSibling) && DOM.hasClass(n, cp + 'ItemSeparator'))\r
7236                                 DOM.addClass(ro, 'mceFirst');\r
7237 \r
7238                         if (o.collapse)\r
7239                                 DOM.addClass(ro, cp + 'ItemSub');\r
7240 \r
7241                         if (n = ro.previousSibling)\r
7242                                 DOM.removeClass(n, 'mceLast');\r
7243 \r
7244                         DOM.addClass(ro, 'mceLast');\r
7245                 }\r
7246 \r
7247                 });\r
7248 })(tinymce);(function(tinymce) {\r
7249         var DOM = tinymce.DOM;\r
7250 \r
7251         tinymce.create('tinymce.ui.Button:tinymce.ui.Control', {\r
7252                 Button : function(id, s) {\r
7253                         this.parent(id, s);\r
7254                         this.classPrefix = 'mceButton';\r
7255                 },\r
7256 \r
7257                 renderHTML : function() {\r
7258                         var cp = this.classPrefix, s = this.settings, h, l;\r
7259 \r
7260                         l = DOM.encode(s.label || '');\r
7261                         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) + '">';\r
7262 \r
7263                         if (s.image)\r
7264                                 h += '<img class="mceIcon" src="' + s.image + '" />' + l + '</a>';\r
7265                         else\r
7266                                 h += '<span class="mceIcon ' + s['class'] + '"></span>' + (l ? '<span class="' + cp + 'Label">' + l + '</span>' : '') + '</a>';\r
7267 \r
7268                         return h;\r
7269                 },\r
7270 \r
7271                 postRender : function() {\r
7272                         var t = this, s = t.settings;\r
7273 \r
7274                         tinymce.dom.Event.add(t.id, 'click', function(e) {\r
7275                                 if (!t.isDisabled())\r
7276                                         return s.onclick.call(s.scope, e);\r
7277                         });\r
7278                 }\r
7279 \r
7280                 });\r
7281 })(tinymce);\r
7282 (function(tinymce) {\r
7283         var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;\r
7284 \r
7285         tinymce.create('tinymce.ui.ListBox:tinymce.ui.Control', {\r
7286                 ListBox : function(id, s) {\r
7287                         var t = this;\r
7288 \r
7289                         t.parent(id, s);\r
7290                         t.items = [];\r
7291                         t.onChange = new Dispatcher(t);\r
7292                         t.onPostRender = new Dispatcher(t);\r
7293                         t.onAdd = new Dispatcher(t);\r
7294                         t.onRenderMenu = new tinymce.util.Dispatcher(this);\r
7295                         t.classPrefix = 'mceListBox';\r
7296                 },\r
7297 \r
7298                 select : function(va) {\r
7299                         var t = this, fv, f;\r
7300 \r
7301                         if (va == undefined)\r
7302                                 return t.selectByIndex(-1);\r
7303 \r
7304                         // Is string or number make function selector\r
7305                         if (va && va.call)\r
7306                                 f = va;\r
7307                         else {\r
7308                                 f = function(v) {\r
7309                                         return v == va;\r
7310                                 };\r
7311                         }\r
7312 \r
7313                         // Do we need to do something?\r
7314                         if (va != t.selectedValue) {\r
7315                                 // Find item\r
7316                                 each(t.items, function(o, i) {\r
7317                                         if (f(o.value)) {\r
7318                                                 fv = 1;\r
7319                                                 t.selectByIndex(i);\r
7320                                                 return false;\r
7321                                         }\r
7322                                 });\r
7323 \r
7324                                 if (!fv)\r
7325                                         t.selectByIndex(-1);\r
7326                         }\r
7327                 },\r
7328 \r
7329                 selectByIndex : function(idx) {\r
7330                         var t = this, e, o;\r
7331 \r
7332                         if (idx != t.selectedIndex) {\r
7333                                 e = DOM.get(t.id + '_text');\r
7334                                 o = t.items[idx];\r
7335 \r
7336                                 if (o) {\r
7337                                         t.selectedValue = o.value;\r
7338                                         t.selectedIndex = idx;\r
7339                                         DOM.setHTML(e, DOM.encode(o.title));\r
7340                                         DOM.removeClass(e, 'mceTitle');\r
7341                                 } else {\r
7342                                         DOM.setHTML(e, DOM.encode(t.settings.title));\r
7343                                         DOM.addClass(e, 'mceTitle');\r
7344                                         t.selectedValue = t.selectedIndex = null;\r
7345                                 }\r
7346 \r
7347                                 e = 0;\r
7348                         }\r
7349                 },\r
7350 \r
7351                 add : function(n, v, o) {\r
7352                         var t = this;\r
7353 \r
7354                         o = o || {};\r
7355                         o = tinymce.extend(o, {\r
7356                                 title : n,\r
7357                                 value : v\r
7358                         });\r
7359 \r
7360                         t.items.push(o);\r
7361                         t.onAdd.dispatch(t, o);\r
7362                 },\r
7363 \r
7364                 getLength : function() {\r
7365                         return this.items.length;\r
7366                 },\r
7367 \r
7368                 renderHTML : function() {\r
7369                         var h = '', t = this, s = t.settings, cp = t.classPrefix;\r
7370 \r
7371                         h = '<table id="' + t.id + '" cellpadding="0" cellspacing="0" class="' + cp + ' ' + cp + 'Enabled' + (s['class'] ? (' ' + s['class']) : '') + '"><tbody><tr>';\r
7372                         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>';\r
7373                         h += '<td>' + DOM.createHTML('a', {id : t.id + '_open', tabindex : -1, href : 'javascript:;', 'class' : 'mceOpen', onclick : "return false;", onmousedown : 'return false;'}, '<span></span>') + '</td>';\r
7374                         h += '</tr></tbody></table>';\r
7375 \r
7376                         return h;\r
7377                 },\r
7378 \r
7379                 showMenu : function() {\r
7380                         var t = this, p1, p2, e = DOM.get(this.id), m;\r
7381 \r
7382                         if (t.isDisabled() || t.items.length == 0)\r
7383                                 return;\r
7384 \r
7385                         if (t.menu && t.menu.isMenuVisible)\r
7386                                 return t.hideMenu();\r
7387 \r
7388                         if (!t.isMenuRendered) {\r
7389                                 t.renderMenu();\r
7390                                 t.isMenuRendered = true;\r
7391                         }\r
7392 \r
7393                         p1 = DOM.getPos(this.settings.menu_container);\r
7394                         p2 = DOM.getPos(e);\r
7395 \r
7396                         m = t.menu;\r
7397                         m.settings.offset_x = p2.x;\r
7398                         m.settings.offset_y = p2.y;\r
7399                         m.settings.keyboard_focus = !tinymce.isOpera; // Opera is buggy when it comes to auto focus\r
7400 \r
7401                         // Select in menu\r
7402                         if (t.oldID)\r
7403                                 m.items[t.oldID].setSelected(0);\r
7404 \r
7405                         each(t.items, function(o) {\r
7406                                 if (o.value === t.selectedValue) {\r
7407                                         m.items[o.id].setSelected(1);\r
7408                                         t.oldID = o.id;\r
7409                                 }\r
7410                         });\r
7411 \r
7412                         m.showMenu(0, e.clientHeight);\r
7413 \r
7414                         Event.add(DOM.doc, 'mousedown', t.hideMenu, t);\r
7415                         DOM.addClass(t.id, t.classPrefix + 'Selected');\r
7416 \r
7417                         //DOM.get(t.id + '_text').focus();\r
7418                 },\r
7419 \r
7420                 hideMenu : function(e) {\r
7421                         var t = this;\r
7422 \r
7423                         // Prevent double toogles by canceling the mouse click event to the button\r
7424                         if (e && e.type == "mousedown" && (e.target.id == t.id + '_text' || e.target.id == t.id + '_open'))\r
7425                                 return;\r
7426 \r
7427                         if (!e || !DOM.getParent(e.target, '.mceMenu')) {\r
7428                                 DOM.removeClass(t.id, t.classPrefix + 'Selected');\r
7429                                 Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);\r
7430 \r
7431                                 if (t.menu)\r
7432                                         t.menu.hideMenu();\r
7433                         }\r
7434                 },\r
7435 \r
7436                 renderMenu : function() {\r
7437                         var t = this, m;\r
7438 \r
7439                         m = t.settings.control_manager.createDropMenu(t.id + '_menu', {\r
7440                                 menu_line : 1,\r
7441                                 'class' : t.classPrefix + 'Menu mceNoIcons',\r
7442                                 max_width : 150,\r
7443                                 max_height : 150\r
7444                         });\r
7445 \r
7446                         m.onHideMenu.add(t.hideMenu, t);\r
7447 \r
7448                         m.add({\r
7449                                 title : t.settings.title,\r
7450                                 'class' : 'mceMenuItemTitle',\r
7451                                 onclick : function() {\r
7452                                         if (t.settings.onselect('') !== false)\r
7453                                                 t.select(''); // Must be runned after\r
7454                                 }\r
7455                         });\r
7456 \r
7457                         each(t.items, function(o) {\r
7458                                 o.id = DOM.uniqueId();\r
7459                                 o.onclick = function() {\r
7460                                         if (t.settings.onselect(o.value) !== false)\r
7461                                                 t.select(o.value); // Must be runned after\r
7462                                 };\r
7463 \r
7464                                 m.add(o);\r
7465                         });\r
7466 \r
7467                         t.onRenderMenu.dispatch(t, m);\r
7468                         t.menu = m;\r
7469                 },\r
7470 \r
7471                 postRender : function() {\r
7472                         var t = this, cp = t.classPrefix;\r
7473 \r
7474                         Event.add(t.id, 'click', t.showMenu, t);\r
7475                         Event.add(t.id + '_text', 'focus', function(e) {\r
7476                                 if (!t._focused) {\r
7477                                         t.keyDownHandler = Event.add(t.id + '_text', 'keydown', function(e) {\r
7478                                                 var idx = -1, v, kc = e.keyCode;\r
7479 \r
7480                                                 // Find current index\r
7481                                                 each(t.items, function(v, i) {\r
7482                                                         if (t.selectedValue == v.value)\r
7483                                                                 idx = i;\r
7484                                                 });\r
7485 \r
7486                                                 // Move up/down\r
7487                                                 if (kc == 38)\r
7488                                                         v = t.items[idx - 1];\r
7489                                                 else if (kc == 40)\r
7490                                                         v = t.items[idx + 1];\r
7491                                                 else if (kc == 13) {\r
7492                                                         // Fake select on enter\r
7493                                                         v = t.selectedValue;\r
7494                                                         t.selectedValue = null; // Needs to be null to fake change\r
7495                                                         t.settings.onselect(v);\r
7496                                                         return Event.cancel(e);\r
7497                                                 }\r
7498 \r
7499                                                 if (v) {\r
7500                                                         t.hideMenu();\r
7501                                                         t.select(v.value);\r
7502                                                 }\r
7503                                         });\r
7504                                 }\r
7505 \r
7506                                 t._focused = 1;\r
7507                         });\r
7508                         Event.add(t.id + '_text', 'blur', function() {Event.remove(t.id + '_text', 'keydown', t.keyDownHandler); t._focused = 0;});\r
7509 \r
7510                         // Old IE doesn't have hover on all elements\r
7511                         if (tinymce.isIE6 || !DOM.boxModel) {\r
7512                                 Event.add(t.id, 'mouseover', function() {\r
7513                                         if (!DOM.hasClass(t.id, cp + 'Disabled'))\r
7514                                                 DOM.addClass(t.id, cp + 'Hover');\r
7515                                 });\r
7516 \r
7517                                 Event.add(t.id, 'mouseout', function() {\r
7518                                         if (!DOM.hasClass(t.id, cp + 'Disabled'))\r
7519                                                 DOM.removeClass(t.id, cp + 'Hover');\r
7520                                 });\r
7521                         }\r
7522 \r
7523                         t.onPostRender.dispatch(t, DOM.get(t.id));\r
7524                 },\r
7525 \r
7526                 destroy : function() {\r
7527                         this.parent();\r
7528 \r
7529                         Event.clear(this.id + '_text');\r
7530                 }\r
7531 \r
7532                 });\r
7533 })(tinymce);(function(tinymce) {\r
7534         var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;\r
7535 \r
7536         tinymce.create('tinymce.ui.NativeListBox:tinymce.ui.ListBox', {\r
7537                 NativeListBox : function(id, s) {\r
7538                         this.parent(id, s);\r
7539                         this.classPrefix = 'mceNativeListBox';\r
7540                 },\r
7541 \r
7542                 setDisabled : function(s) {\r
7543                         DOM.get(this.id).disabled = s;\r
7544                 },\r
7545 \r
7546                 isDisabled : function() {\r
7547                         return DOM.get(this.id).disabled;\r
7548                 },\r
7549 \r
7550                 select : function(va) {\r
7551                         var t = this, fv, f;\r
7552 \r
7553                         if (va == undefined)\r
7554                                 return t.selectByIndex(-1);\r
7555 \r
7556                         // Is string or number make function selector\r
7557                         if (va && va.call)\r
7558                                 f = va;\r
7559                         else {\r
7560                                 f = function(v) {\r
7561                                         return v == va;\r
7562                                 };\r
7563                         }\r
7564 \r
7565                         // Do we need to do something?\r
7566                         if (va != t.selectedValue) {\r
7567                                 // Find item\r
7568                                 each(t.items, function(o, i) {\r
7569                                         if (f(o.value)) {\r
7570                                                 fv = 1;\r
7571                                                 t.selectByIndex(i);\r
7572                                                 return false;\r
7573                                         }\r
7574                                 });\r
7575 \r
7576                                 if (!fv)\r
7577                                         t.selectByIndex(-1);\r
7578                         }\r
7579                 },\r
7580 \r
7581                 selectByIndex : function(idx) {\r
7582                         DOM.get(this.id).selectedIndex = idx + 1;\r
7583                         this.selectedValue = this.items[idx] ? this.items[idx].value : null;\r
7584                 },\r
7585 \r
7586                 add : function(n, v, a) {\r
7587                         var o, t = this;\r
7588 \r
7589                         a = a || {};\r
7590                         a.value = v;\r
7591 \r
7592                         if (t.isRendered())\r
7593                                 DOM.add(DOM.get(this.id), 'option', a, n);\r
7594 \r
7595                         o = {\r
7596                                 title : n,\r
7597                                 value : v,\r
7598                                 attribs : a\r
7599                         };\r
7600 \r
7601                         t.items.push(o);\r
7602                         t.onAdd.dispatch(t, o);\r
7603                 },\r
7604 \r
7605                 getLength : function() {\r
7606                         return DOM.get(this.id).options.length - 1;\r
7607                 },\r
7608 \r
7609                 renderHTML : function() {\r
7610                         var h, t = this;\r
7611 \r
7612                         h = DOM.createHTML('option', {value : ''}, '-- ' + t.settings.title + ' --');\r
7613 \r
7614                         each(t.items, function(it) {\r
7615                                 h += DOM.createHTML('option', {value : it.value}, it.title);\r
7616                         });\r
7617 \r
7618                         h = DOM.createHTML('select', {id : t.id, 'class' : 'mceNativeListBox'}, h);\r
7619 \r
7620                         return h;\r
7621                 },\r
7622 \r
7623                 postRender : function() {\r
7624                         var t = this, ch;\r
7625 \r
7626                         t.rendered = true;\r
7627 \r
7628                         function onChange(e) {\r
7629                                 var v = t.items[e.target.selectedIndex - 1];\r
7630 \r
7631                                 if (v && (v = v.value)) {\r
7632                                         t.onChange.dispatch(t, v);\r
7633 \r
7634                                         if (t.settings.onselect)\r
7635                                                 t.settings.onselect(v);\r
7636                                 }\r
7637                         };\r
7638 \r
7639                         Event.add(t.id, 'change', onChange);\r
7640 \r
7641                         // Accessibility keyhandler\r
7642                         Event.add(t.id, 'keydown', function(e) {\r
7643                                 var bf;\r
7644 \r
7645                                 Event.remove(t.id, 'change', ch);\r
7646 \r
7647                                 bf = Event.add(t.id, 'blur', function() {\r
7648                                         Event.add(t.id, 'change', onChange);\r
7649                                         Event.remove(t.id, 'blur', bf);\r
7650                                 });\r
7651 \r
7652                                 if (e.keyCode == 13 || e.keyCode == 32) {\r
7653                                         onChange(e);\r
7654                                         return Event.cancel(e);\r
7655                                 }\r
7656                         });\r
7657 \r
7658                         t.onPostRender.dispatch(t, DOM.get(t.id));\r
7659                 }\r
7660 \r
7661                 });\r
7662 })(tinymce);(function(tinymce) {\r
7663         var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;\r
7664 \r
7665         tinymce.create('tinymce.ui.MenuButton:tinymce.ui.Button', {\r
7666                 MenuButton : function(id, s) {\r
7667                         this.parent(id, s);\r
7668                         this.onRenderMenu = new tinymce.util.Dispatcher(this);\r
7669                         s.menu_container = s.menu_container || DOM.doc.body;\r
7670                 },\r
7671 \r
7672                 showMenu : function() {\r
7673                         var t = this, p1, p2, e = DOM.get(t.id), m;\r
7674 \r
7675                         if (t.isDisabled())\r
7676                                 return;\r
7677 \r
7678                         if (!t.isMenuRendered) {\r
7679                                 t.renderMenu();\r
7680                                 t.isMenuRendered = true;\r
7681                         }\r
7682 \r
7683                         if (t.isMenuVisible)\r
7684                                 return t.hideMenu();\r
7685 \r
7686                         p1 = DOM.getPos(t.settings.menu_container);\r
7687                         p2 = DOM.getPos(e);\r
7688 \r
7689                         m = t.menu;\r
7690                         m.settings.offset_x = p2.x;\r
7691                         m.settings.offset_y = p2.y;\r
7692                         m.settings.vp_offset_x = p2.x;\r
7693                         m.settings.vp_offset_y = p2.y;\r
7694                         m.settings.keyboard_focus = t._focused;\r
7695                         m.showMenu(0, e.clientHeight);\r
7696 \r
7697                         Event.add(DOM.doc, 'mousedown', t.hideMenu, t);\r
7698                         t.setState('Selected', 1);\r
7699 \r
7700                         t.isMenuVisible = 1;\r
7701                 },\r
7702 \r
7703                 renderMenu : function() {\r
7704                         var t = this, m;\r
7705 \r
7706                         m = t.settings.control_manager.createDropMenu(t.id + '_menu', {\r
7707                                 menu_line : 1,\r
7708                                 'class' : this.classPrefix + 'Menu',\r
7709                                 icons : t.settings.icons\r
7710                         });\r
7711 \r
7712                         m.onHideMenu.add(t.hideMenu, t);\r
7713 \r
7714                         t.onRenderMenu.dispatch(t, m);\r
7715                         t.menu = m;\r
7716                 },\r
7717 \r
7718                 hideMenu : function(e) {\r
7719                         var t = this;\r
7720 \r
7721                         // Prevent double toogles by canceling the mouse click event to the button\r
7722                         if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id || e.id === t.id + '_open';}))\r
7723                                 return;\r
7724 \r
7725                         if (!e || !DOM.getParent(e.target, '.mceMenu')) {\r
7726                                 t.setState('Selected', 0);\r
7727                                 Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);\r
7728                                 if (t.menu)\r
7729                                         t.menu.hideMenu();\r
7730                         }\r
7731 \r
7732                         t.isMenuVisible = 0;\r
7733                 },\r
7734 \r
7735                 postRender : function() {\r
7736                         var t = this, s = t.settings;\r
7737 \r
7738                         Event.add(t.id, 'click', function() {\r
7739                                 if (!t.isDisabled()) {\r
7740                                         if (s.onclick)\r
7741                                                 s.onclick(t.value);\r
7742 \r
7743                                         t.showMenu();\r
7744                                 }\r
7745                         });\r
7746                 }\r
7747 \r
7748                 });\r
7749 })(tinymce);\r
7750 (function(tinymce) {\r
7751         var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;\r
7752 \r
7753         tinymce.create('tinymce.ui.SplitButton:tinymce.ui.MenuButton', {\r
7754                 SplitButton : function(id, s) {\r
7755                         this.parent(id, s);\r
7756                         this.classPrefix = 'mceSplitButton';\r
7757                 },\r
7758 \r
7759                 renderHTML : function() {\r
7760                         var h, t = this, s = t.settings, h1;\r
7761 \r
7762                         h = '<tbody><tr>';\r
7763 \r
7764                         if (s.image)\r
7765                                 h1 = DOM.createHTML('img ', {src : s.image, 'class' : 'mceAction ' + s['class']});\r
7766                         else\r
7767                                 h1 = DOM.createHTML('span', {'class' : 'mceAction ' + s['class']}, '');\r
7768 \r
7769                         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>';\r
7770         \r
7771                         h1 = DOM.createHTML('span', {'class' : 'mceOpen ' + s['class']});\r
7772                         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>';\r
7773 \r
7774                         h += '</tr></tbody>';\r
7775 \r
7776                         return DOM.createHTML('table', {id : t.id, 'class' : 'mceSplitButton mceSplitButtonEnabled ' + s['class'], cellpadding : '0', cellspacing : '0', onmousedown : 'return false;', title : s.title}, h);\r
7777                 },\r
7778 \r
7779                 postRender : function() {\r
7780                         var t = this, s = t.settings;\r
7781 \r
7782                         if (s.onclick) {\r
7783                                 Event.add(t.id + '_action', 'click', function() {\r
7784                                         if (!t.isDisabled())\r
7785                                                 s.onclick(t.value);\r
7786                                 });\r
7787                         }\r
7788 \r
7789                         Event.add(t.id + '_open', 'click', t.showMenu, t);\r
7790                         Event.add(t.id + '_open', 'focus', function() {t._focused = 1;});\r
7791                         Event.add(t.id + '_open', 'blur', function() {t._focused = 0;});\r
7792 \r
7793                         // Old IE doesn't have hover on all elements\r
7794                         if (tinymce.isIE6 || !DOM.boxModel) {\r
7795                                 Event.add(t.id, 'mouseover', function() {\r
7796                                         if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))\r
7797                                                 DOM.addClass(t.id, 'mceSplitButtonHover');\r
7798                                 });\r
7799 \r
7800                                 Event.add(t.id, 'mouseout', function() {\r
7801                                         if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))\r
7802                                                 DOM.removeClass(t.id, 'mceSplitButtonHover');\r
7803                                 });\r
7804                         }\r
7805                 },\r
7806 \r
7807                 destroy : function() {\r
7808                         this.parent();\r
7809 \r
7810                         Event.clear(this.id + '_action');\r
7811                         Event.clear(this.id + '_open');\r
7812                 }\r
7813 \r
7814                 });\r
7815 })(tinymce);\r
7816 (function(tinymce) {\r
7817         var DOM = tinymce.DOM, Event = tinymce.dom.Event, is = tinymce.is, each = tinymce.each;\r
7818 \r
7819         tinymce.create('tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton', {\r
7820                 ColorSplitButton : function(id, s) {\r
7821                         var t = this;\r
7822 \r
7823                         t.parent(id, s);\r
7824 \r
7825                         t.settings = s = tinymce.extend({\r
7826                                 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',\r
7827                                 grid_width : 8,\r
7828                                 default_color : '#888888'\r
7829                         }, t.settings);\r
7830 \r
7831                         t.onShowMenu = new tinymce.util.Dispatcher(t);\r
7832                         t.onHideMenu = new tinymce.util.Dispatcher(t);\r
7833 \r
7834                         t.value = s.default_color;\r
7835                 },\r
7836 \r
7837                 showMenu : function() {\r
7838                         var t = this, r, p, e, p2;\r
7839 \r
7840                         if (t.isDisabled())\r
7841                                 return;\r
7842 \r
7843                         if (!t.isMenuRendered) {\r
7844                                 t.renderMenu();\r
7845                                 t.isMenuRendered = true;\r
7846                         }\r
7847 \r
7848                         if (t.isMenuVisible)\r
7849                                 return t.hideMenu();\r
7850 \r
7851                         e = DOM.get(t.id);\r
7852                         DOM.show(t.id + '_menu');\r
7853                         DOM.addClass(e, 'mceSplitButtonSelected');\r
7854                         p2 = DOM.getPos(e);\r
7855                         DOM.setStyles(t.id + '_menu', {\r
7856                                 left : p2.x,\r
7857                                 top : p2.y + e.clientHeight,\r
7858                                 zIndex : 200000\r
7859                         });\r
7860                         e = 0;\r
7861 \r
7862                         Event.add(DOM.doc, 'mousedown', t.hideMenu, t);\r
7863 \r
7864                         if (t._focused) {\r
7865                                 t._keyHandler = Event.add(t.id + '_menu', 'keydown', function(e) {\r
7866                                         if (e.keyCode == 27)\r
7867                                                 t.hideMenu();\r
7868                                 });\r
7869 \r
7870                                 DOM.select('a', t.id + '_menu')[0].focus(); // Select first link\r
7871                         }\r
7872 \r
7873                         t.onShowMenu.dispatch(t);\r
7874 \r
7875                         t.isMenuVisible = 1;\r
7876                 },\r
7877 \r
7878                 hideMenu : function(e) {\r
7879                         var t = this;\r
7880 \r
7881                         // Prevent double toogles by canceling the mouse click event to the button\r
7882                         if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id + '_open';}))\r
7883                                 return;\r
7884 \r
7885                         if (!e || !DOM.getParent(e.target, '.mceSplitButtonMenu')) {\r
7886                                 DOM.removeClass(t.id, 'mceSplitButtonSelected');\r
7887                                 Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);\r
7888                                 Event.remove(t.id + '_menu', 'keydown', t._keyHandler);\r
7889                                 DOM.hide(t.id + '_menu');\r
7890                         }\r
7891 \r
7892                         t.onHideMenu.dispatch(t);\r
7893 \r
7894                         t.isMenuVisible = 0;\r
7895                 },\r
7896 \r
7897                 renderMenu : function() {\r
7898                         var t = this, m, i = 0, s = t.settings, n, tb, tr, w;\r
7899 \r
7900                         w = DOM.add(s.menu_container, 'div', {id : t.id + '_menu', 'class' : s['menu_class'] + ' ' + s['class'], style : 'position:absolute;left:0;top:-1000px;'});\r
7901                         m = DOM.add(w, 'div', {'class' : s['class'] + ' mceSplitButtonMenu'});\r
7902                         DOM.add(m, 'span', {'class' : 'mceMenuLine'});\r
7903 \r
7904                         n = DOM.add(m, 'table', {'class' : 'mceColorSplitMenu'});\r
7905                         tb = DOM.add(n, 'tbody');\r
7906 \r
7907                         // Generate color grid\r
7908                         i = 0;\r
7909                         each(is(s.colors, 'array') ? s.colors : s.colors.split(','), function(c) {\r
7910                                 c = c.replace(/^#/, '');\r
7911 \r
7912                                 if (!i--) {\r
7913                                         tr = DOM.add(tb, 'tr');\r
7914                                         i = s.grid_width - 1;\r
7915                                 }\r
7916 \r
7917                                 n = DOM.add(tr, 'td');\r
7918 \r
7919                                 n = DOM.add(n, 'a', {\r
7920                                         href : 'javascript:;',\r
7921                                         style : {\r
7922                                                 backgroundColor : '#' + c\r
7923                                         },\r
7924                                         mce_color : '#' + c\r
7925                                 });\r
7926                         });\r
7927 \r
7928                         if (s.more_colors_func) {\r
7929                                 n = DOM.add(tb, 'tr');\r
7930                                 n = DOM.add(n, 'td', {colspan : s.grid_width, 'class' : 'mceMoreColors'});\r
7931                                 n = DOM.add(n, 'a', {id : t.id + '_more', href : 'javascript:;', onclick : 'return false;', 'class' : 'mceMoreColors'}, s.more_colors_title);\r
7932 \r
7933                                 Event.add(n, 'click', function(e) {\r
7934                                         s.more_colors_func.call(s.more_colors_scope || this);\r
7935                                         return Event.cancel(e); // Cancel to fix onbeforeunload problem\r
7936                                 });\r
7937                         }\r
7938 \r
7939                         DOM.addClass(m, 'mceColorSplitMenu');\r
7940 \r
7941                         Event.add(t.id + '_menu', 'click', function(e) {\r
7942                                 var c;\r
7943 \r
7944                                 e = e.target;\r
7945 \r
7946                                 if (e.nodeName == 'A' && (c = e.getAttribute('mce_color')))\r
7947                                         t.setColor(c);\r
7948 \r
7949                                 return Event.cancel(e); // Prevent IE auto save warning\r
7950                         });\r
7951 \r
7952                         return w;\r
7953                 },\r
7954 \r
7955                 setColor : function(c) {\r
7956                         var t = this;\r
7957 \r
7958                         DOM.setStyle(t.id + '_preview', 'backgroundColor', c);\r
7959 \r
7960                         t.value = c;\r
7961                         t.hideMenu();\r
7962                         t.settings.onselect(c);\r
7963                 },\r
7964 \r
7965                 postRender : function() {\r
7966                         var t = this, id = t.id;\r
7967 \r
7968                         t.parent();\r
7969                         DOM.add(id + '_action', 'div', {id : id + '_preview', 'class' : 'mceColorPreview'});\r
7970                         DOM.setStyle(t.id + '_preview', 'backgroundColor', t.value);\r
7971                 },\r
7972 \r
7973                 destroy : function() {\r
7974                         this.parent();\r
7975 \r
7976                         Event.clear(this.id + '_menu');\r
7977                         Event.clear(this.id + '_more');\r
7978                         DOM.remove(this.id + '_menu');\r
7979                 }\r
7980 \r
7981                 });\r
7982 })(tinymce);\r
7983 tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {\r
7984         renderHTML : function() {\r
7985                 var t = this, h = '', c, co, dom = tinymce.DOM, s = t.settings, i, pr, nx, cl;\r
7986 \r
7987                 cl = t.controls;\r
7988                 for (i=0; i<cl.length; i++) {\r
7989                         // Get current control, prev control, next control and if the control is a list box or not\r
7990                         co = cl[i];\r
7991                         pr = cl[i - 1];\r
7992                         nx = cl[i + 1];\r
7993 \r
7994                         // Add toolbar start\r
7995                         if (i === 0) {\r
7996                                 c = 'mceToolbarStart';\r
7997 \r
7998                                 if (co.Button)\r
7999                                         c += ' mceToolbarStartButton';\r
8000                                 else if (co.SplitButton)\r
8001                                         c += ' mceToolbarStartSplitButton';\r
8002                                 else if (co.ListBox)\r
8003                                         c += ' mceToolbarStartListBox';\r
8004 \r
8005                                 h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));\r
8006                         }\r
8007 \r
8008                         // Add toolbar end before list box and after the previous button\r
8009                         // This is to fix the o2k7 editor skins\r
8010                         if (pr && co.ListBox) {\r
8011                                 if (pr.Button || pr.SplitButton)\r
8012                                         h += dom.createHTML('td', {'class' : 'mceToolbarEnd'}, dom.createHTML('span', null, '<!-- IE -->'));\r
8013                         }\r
8014 \r
8015                         // Render control HTML\r
8016 \r
8017                         // IE 8 quick fix, needed to propertly generate a hit area for anchors\r
8018                         if (dom.stdMode)\r
8019                                 h += '<td style="position: relative">' + co.renderHTML() + '</td>';\r
8020                         else\r
8021                                 h += '<td>' + co.renderHTML() + '</td>';\r
8022 \r
8023                         // Add toolbar start after list box and before the next button\r
8024                         // This is to fix the o2k7 editor skins\r
8025                         if (nx && co.ListBox) {\r
8026                                 if (nx.Button || nx.SplitButton)\r
8027                                         h += dom.createHTML('td', {'class' : 'mceToolbarStart'}, dom.createHTML('span', null, '<!-- IE -->'));\r
8028                         }\r
8029                 }\r
8030 \r
8031                 c = 'mceToolbarEnd';\r
8032 \r
8033                 if (co.Button)\r
8034                         c += ' mceToolbarEndButton';\r
8035                 else if (co.SplitButton)\r
8036                         c += ' mceToolbarEndSplitButton';\r
8037                 else if (co.ListBox)\r
8038                         c += ' mceToolbarEndListBox';\r
8039 \r
8040                 h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));\r
8041 \r
8042                 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>');\r
8043         }\r
8044 \r
8045         });\r
8046 (function(tinymce) {\r
8047         var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each;\r
8048 \r
8049         tinymce.create('tinymce.AddOnManager', {\r
8050                 items : [],\r
8051                 urls : {},\r
8052                 lookup : {},\r
8053                 onAdd : new Dispatcher(this),\r
8054 \r
8055                 get : function(n) {\r
8056                         return this.lookup[n];\r
8057                 },\r
8058 \r
8059                 requireLangPack : function(n) {\r
8060                         var u, s = tinymce.EditorManager.settings;\r
8061 \r
8062                         if (s && s.language) {\r
8063                                 u = this.urls[n] + '/langs/' + s.language + '.js';\r
8064 \r
8065                                 if (!tinymce.dom.Event.domLoaded && !s.strict_mode)\r
8066                                         tinymce.ScriptLoader.load(u);\r
8067                                 else\r
8068                                         tinymce.ScriptLoader.add(u);\r
8069                         }\r
8070                 },\r
8071 \r
8072                 add : function(id, o) {\r
8073                         this.items.push(o);\r
8074                         this.lookup[id] = o;\r
8075                         this.onAdd.dispatch(this, id, o);\r
8076 \r
8077                         return o;\r
8078                 },\r
8079 \r
8080                 load : function(n, u, cb, s) {\r
8081                         var t = this;\r
8082 \r
8083                         if (t.urls[n])\r
8084                                 return;\r
8085 \r
8086                         if (u.indexOf('/') != 0 && u.indexOf('://') == -1)\r
8087                                 u = tinymce.baseURL + '/' +  u;\r
8088 \r
8089                         t.urls[n] = u.substring(0, u.lastIndexOf('/'));\r
8090                         tinymce.ScriptLoader.add(u, cb, s);\r
8091                 }\r
8092 \r
8093                 });\r
8094 \r
8095         // Create plugin and theme managers\r
8096         tinymce.PluginManager = new tinymce.AddOnManager();\r
8097         tinymce.ThemeManager = new tinymce.AddOnManager();\r
8098 }(tinymce));(function(tinymce) {\r
8099         // Shorten names\r
8100         var each = tinymce.each, extend = tinymce.extend, DOM = tinymce.DOM, Event = tinymce.dom.Event, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, explode = tinymce.explode;\r
8101 \r
8102         tinymce.create('static tinymce.EditorManager', {\r
8103                 editors : {},\r
8104                 i18n : {},\r
8105                 activeEditor : null,\r
8106 \r
8107                 preInit : function() {\r
8108                         var t = this, lo = window.location;\r
8109 \r
8110                         // Setup some URLs where the editor API is located and where the document is\r
8111                         tinymce.documentBaseURL = lo.href.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');\r
8112                         if (!/[\/\\]$/.test(tinymce.documentBaseURL))\r
8113                                 tinymce.documentBaseURL += '/';\r
8114 \r
8115                         tinymce.baseURL = new tinymce.util.URI(tinymce.documentBaseURL).toAbsolute(tinymce.baseURL);\r
8116                         tinymce.EditorManager.baseURI = new tinymce.util.URI(tinymce.baseURL);\r
8117 \r
8118                         // User specified a document.domain value\r
8119                         if (document.domain && lo.hostname != document.domain)\r
8120                                 tinymce.relaxedDomain = document.domain;\r
8121 \r
8122                         // Add before unload listener\r
8123                         // This was required since IE was leaking memory if you added and removed beforeunload listeners\r
8124                         // with attachEvent/detatchEvent so this only adds one listener and instances can the attach to the onBeforeUnload event\r
8125                         t.onBeforeUnload = new tinymce.util.Dispatcher(t);\r
8126 \r
8127                         // Must be on window or IE will leak if the editor is placed in frame or iframe\r
8128                         Event.add(window, 'beforeunload', function(e) {\r
8129                                 t.onBeforeUnload.dispatch(t, e);\r
8130                         });\r
8131                 },\r
8132 \r
8133                 init : function(s) {\r
8134                         var t = this, pl, sl = tinymce.ScriptLoader, c, e, el = [], ed;\r
8135 \r
8136                         function execCallback(se, n, s) {\r
8137                                 var f = se[n];\r
8138 \r
8139                                 if (!f)\r
8140                                         return;\r
8141 \r
8142                                 if (tinymce.is(f, 'string')) {\r
8143                                         s = f.replace(/\.\w+$/, '');\r
8144                                         s = s ? tinymce.resolve(s) : 0;\r
8145                                         f = tinymce.resolve(f);\r
8146                                 }\r
8147 \r
8148                                 return f.apply(s || this, Array.prototype.slice.call(arguments, 2));\r
8149                         };\r
8150 \r
8151                         s = extend({\r
8152                                 theme : "simple",\r
8153                                 language : "en",\r
8154                                 strict_loading_mode : document.contentType == 'application/xhtml+xml'\r
8155                         }, s);\r
8156 \r
8157                         t.settings = s;\r
8158 \r
8159                         // If page not loaded and strict mode isn't enabled then load them\r
8160                         if (!Event.domLoaded && !s.strict_loading_mode) {\r
8161                                 // Load language\r
8162                                 if (s.language)\r
8163                                         sl.add(tinymce.baseURL + '/langs/' + s.language + '.js');\r
8164 \r
8165                                 // Load theme\r
8166                                 if (s.theme && s.theme.charAt(0) != '-' && !ThemeManager.urls[s.theme])\r
8167                                         ThemeManager.load(s.theme, 'themes/' + s.theme + '/editor_template' + tinymce.suffix + '.js');\r
8168 \r
8169                                 // Load plugins\r
8170                                 if (s.plugins) {\r
8171                                         pl = explode(s.plugins);\r
8172 \r
8173                                         // Load compat2x first\r
8174                                         if (tinymce.inArray(pl, 'compat2x') != -1)\r
8175                                                 PluginManager.load('compat2x', 'plugins/compat2x/editor_plugin' + tinymce.suffix + '.js');\r
8176 \r
8177                                         // Load rest if plugins\r
8178                                         each(pl, function(v) {\r
8179                                                 if (v && v.charAt(0) != '-' && !PluginManager.urls[v]) {\r
8180                                                         // Skip safari plugin for other browsers\r
8181                                                         if (!tinymce.isWebKit && v == 'safari')\r
8182                                                                 return;\r
8183 \r
8184                                                         PluginManager.load(v, 'plugins/' + v + '/editor_plugin' + tinymce.suffix + '.js');\r
8185                                                 }\r
8186                                         });\r
8187                                 }\r
8188 \r
8189                                 sl.loadQueue();\r
8190                         }\r
8191 \r
8192                         // Legacy call\r
8193                         Event.add(document, 'init', function() {\r
8194                                 var l, co;\r
8195 \r
8196                                 execCallback(s, 'onpageload');\r
8197 \r
8198                                 // Verify that it's a valid browser\r
8199                                 if (s.browsers) {\r
8200                                         l = false;\r
8201 \r
8202                                         each(explode(s.browsers), function(v) {\r
8203                                                 switch (v) {\r
8204                                                         case 'ie':\r
8205                                                         case 'msie':\r
8206                                                                 if (tinymce.isIE)\r
8207                                                                         l = true;\r
8208                                                                 break;\r
8209 \r
8210                                                         case 'gecko':\r
8211                                                                 if (tinymce.isGecko)\r
8212                                                                         l = true;\r
8213                                                                 break;\r
8214 \r
8215                                                         case 'safari':\r
8216                                                         case 'webkit':\r
8217                                                                 if (tinymce.isWebKit)\r
8218                                                                         l = true;\r
8219                                                                 break;\r
8220 \r
8221                                                         case 'opera':\r
8222                                                                 if (tinymce.isOpera)\r
8223                                                                         l = true;\r
8224 \r
8225                                                                 break;\r
8226                                                 }\r
8227                                         });\r
8228 \r
8229                                         // Not a valid one\r
8230                                         if (!l)\r
8231                                                 return;\r
8232                                 }\r
8233 \r
8234                                 switch (s.mode) {\r
8235                                         case "exact":\r
8236                                                 l = s.elements || '';\r
8237 \r
8238                                                 if(l.length > 0) {\r
8239                                                         each(explode(l), function(v) {\r
8240                                                                 if (DOM.get(v)) {\r
8241                                                                         ed = new tinymce.Editor(v, s);\r
8242                                                                         el.push(ed);\r
8243                                                                         ed.render(1);\r
8244                                                                 } else {\r
8245                                                                         c = 0;\r
8246 \r
8247                                                                         each(document.forms, function(f) {\r
8248                                                                                 each(f.elements, function(e) {\r
8249                                                                                         if (e.name === v) {\r
8250                                                                                                 v = 'mce_editor_' + c;\r
8251                                                                                                 DOM.setAttrib(e, 'id', v);\r
8252 \r
8253                                                                                                 ed = new tinymce.Editor(v, s);\r
8254                                                                                                 el.push(ed);\r
8255                                                                                                 ed.render(1);\r
8256                                                                                         }\r
8257                                                                                 });\r
8258                                                                         });\r
8259                                                                 }\r
8260                                                         });\r
8261                                                 }\r
8262                                                 break;\r
8263 \r
8264                                         case "textareas":\r
8265                                         case "specific_textareas":\r
8266                                                 function hasClass(n, c) {\r
8267                                                         return c.constructor === RegExp ? c.test(n.className) : DOM.hasClass(n, c);\r
8268                                                 };\r
8269 \r
8270                                                 each(DOM.select('textarea'), function(v) {\r
8271                                                         if (s.editor_deselector && hasClass(v, s.editor_deselector))\r
8272                                                                 return;\r
8273 \r
8274                                                         if (!s.editor_selector || hasClass(v, s.editor_selector)) {\r
8275                                                                 // Can we use the name\r
8276                                                                 e = DOM.get(v.name);\r
8277                                                                 if (!v.id && !e)\r
8278                                                                         v.id = v.name;\r
8279 \r
8280                                                                 // Generate unique name if missing or already exists\r
8281                                                                 if (!v.id || t.get(v.id))\r
8282                                                                         v.id = DOM.uniqueId();\r
8283 \r
8284                                                                 ed = new tinymce.Editor(v.id, s);\r
8285                                                                 el.push(ed);\r
8286                                                                 ed.render(1);\r
8287                                                         }\r
8288                                                 });\r
8289                                                 break;\r
8290                                 }\r
8291 \r
8292                                 // Call onInit when all editors are initialized\r
8293                                 if (s.oninit) {\r
8294                                         l = co = 0;\r
8295 \r
8296                                         each (el, function(ed) {\r
8297                                                 co++;\r
8298 \r
8299                                                 if (!ed.initialized) {\r
8300                                                         // Wait for it\r
8301                                                         ed.onInit.add(function() {\r
8302                                                                 l++;\r
8303 \r
8304                                                                 // All done\r
8305                                                                 if (l == co)\r
8306                                                                         execCallback(s, 'oninit');\r
8307                                                         });\r
8308                                                 } else\r
8309                                                         l++;\r
8310 \r
8311                                                 // All done\r
8312                                                 if (l == co)\r
8313                                                         execCallback(s, 'oninit');                                      \r
8314                                         });\r
8315                                 }\r
8316                         });\r
8317                 },\r
8318 \r
8319                 get : function(id) {\r
8320                         return this.editors[id];\r
8321                 },\r
8322 \r
8323                 getInstanceById : function(id) {\r
8324                         return this.get(id);\r
8325                 },\r
8326 \r
8327                 add : function(e) {\r
8328                         this.editors[e.id] = e;\r
8329                         this._setActive(e);\r
8330 \r
8331                         return e;\r
8332                 },\r
8333 \r
8334                 remove : function(e) {\r
8335                         var t = this;\r
8336 \r
8337                         // Not in the collection\r
8338                         if (!t.editors[e.id])\r
8339                                 return null;\r
8340 \r
8341                         delete t.editors[e.id];\r
8342 \r
8343                         // Select another editor since the active one was removed\r
8344                         if (t.activeEditor == e) {\r
8345                                 each(t.editors, function(e) {\r
8346                                         t._setActive(e);\r
8347                                         return false; // Break\r
8348                                 });\r
8349                         }\r
8350 \r
8351                         e.destroy();\r
8352 \r
8353                         return e;\r
8354                 },\r
8355 \r
8356                 execCommand : function(c, u, v) {\r
8357                         var t = this, ed = t.get(v), w;\r
8358 \r
8359                         // Manager commands\r
8360                         switch (c) {\r
8361                                 case "mceFocus":\r
8362                                         ed.focus();\r
8363                                         return true;\r
8364 \r
8365                                 case "mceAddEditor":\r
8366                                 case "mceAddControl":\r
8367                                         if (!t.get(v))\r
8368                                                 new tinymce.Editor(v, t.settings).render();\r
8369 \r
8370                                         return true;\r
8371 \r
8372                                 case "mceAddFrameControl":\r
8373                                         w = v.window;\r
8374 \r
8375                                         // Add tinyMCE global instance and tinymce namespace to specified window\r
8376                                         w.tinyMCE = tinyMCE;\r
8377                                         w.tinymce = tinymce;\r
8378 \r
8379                                         tinymce.DOM.doc = w.document;\r
8380                                         tinymce.DOM.win = w;\r
8381 \r
8382                                         ed = new tinymce.Editor(v.element_id, v);\r
8383                                         ed.render();\r
8384 \r
8385                                         // Fix IE memory leaks\r
8386                                         if (tinymce.isIE) {\r
8387                                                 function clr() {\r
8388                                                         ed.destroy();\r
8389                                                         w.detachEvent('onunload', clr);\r
8390                                                         w = w.tinyMCE = w.tinymce = null; // IE leak\r
8391                                                 };\r
8392 \r
8393                                                 w.attachEvent('onunload', clr);\r
8394                                         }\r
8395 \r
8396                                         v.page_window = null;\r
8397 \r
8398                                         return true;\r
8399 \r
8400                                 case "mceRemoveEditor":\r
8401                                 case "mceRemoveControl":\r
8402                                         if (ed)\r
8403                                                 ed.remove();\r
8404 \r
8405                                         return true;\r
8406 \r
8407                                 case 'mceToggleEditor':\r
8408                                         if (!ed) {\r
8409                                                 t.execCommand('mceAddControl', 0, v);\r
8410                                                 return true;\r
8411                                         }\r
8412 \r
8413                                         if (ed.isHidden())\r
8414                                                 ed.show();\r
8415                                         else\r
8416                                                 ed.hide();\r
8417 \r
8418                                         return true;\r
8419                         }\r
8420 \r
8421                         // Run command on active editor\r
8422                         if (t.activeEditor)\r
8423                                 return t.activeEditor.execCommand(c, u, v);\r
8424 \r
8425                         return false;\r
8426                 },\r
8427 \r
8428                 execInstanceCommand : function(id, c, u, v) {\r
8429                         var ed = this.get(id);\r
8430 \r
8431                         if (ed)\r
8432                                 return ed.execCommand(c, u, v);\r
8433 \r
8434                         return false;\r
8435                 },\r
8436 \r
8437                 triggerSave : function() {\r
8438                         each(this.editors, function(e) {\r
8439                                 e.save();\r
8440                         });\r
8441                 },\r
8442 \r
8443                 addI18n : function(p, o) {\r
8444                         var lo, i18n = this.i18n;\r
8445 \r
8446                         if (!tinymce.is(p, 'string')) {\r
8447                                 each(p, function(o, lc) {\r
8448                                         each(o, function(o, g) {\r
8449                                                 each(o, function(o, k) {\r
8450                                                         if (g === 'common')\r
8451                                                                 i18n[lc + '.' + k] = o;\r
8452                                                         else\r
8453                                                                 i18n[lc + '.' + g + '.' + k] = o;\r
8454                                                 });\r
8455                                         });\r
8456                                 });\r
8457                         } else {\r
8458                                 each(o, function(o, k) {\r
8459                                         i18n[p + '.' + k] = o;\r
8460                                 });\r
8461                         }\r
8462                 },\r
8463 \r
8464                 // Private methods\r
8465 \r
8466                 _setActive : function(e) {\r
8467                         this.selectedInstance = this.activeEditor = e;\r
8468                 }\r
8469 \r
8470                 });\r
8471 \r
8472         tinymce.EditorManager.preInit();\r
8473 })(tinymce);\r
8474 \r
8475 // Short for editor manager window.tinyMCE is needed when TinyMCE gets loaded though a XHR call\r
8476 var tinyMCE = window.tinyMCE = tinymce.EditorManager;\r
8477 (function(tinymce) {\r
8478         var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, Dispatcher = tinymce.util.Dispatcher;\r
8479         var each = tinymce.each, isGecko = tinymce.isGecko, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit;\r
8480         var is = tinymce.is, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, EditorManager = tinymce.EditorManager;\r
8481         var inArray = tinymce.inArray, grep = tinymce.grep, explode = tinymce.explode;\r
8482 \r
8483         tinymce.create('tinymce.Editor', {\r
8484                 Editor : function(id, s) {\r
8485                         var t = this;\r
8486 \r
8487                         t.id = t.editorId = id;\r
8488                         t.execCommands = {};\r
8489                         t.queryStateCommands = {};\r
8490                         t.queryValueCommands = {};\r
8491                         t.plugins = {};\r
8492 \r
8493                         // Add events to the editor\r
8494                         each([\r
8495                                 'onPreInit',\r
8496                                 'onBeforeRenderUI',\r
8497                                 'onPostRender',\r
8498                                 'onInit',\r
8499                                 'onRemove',\r
8500                                 'onActivate',\r
8501                                 'onDeactivate',\r
8502                                 'onClick',\r
8503                                 'onEvent',\r
8504                                 'onMouseUp',\r
8505                                 'onMouseDown',\r
8506                                 'onDblClick',\r
8507                                 'onKeyDown',\r
8508                                 'onKeyUp',\r
8509                                 'onKeyPress',\r
8510                                 'onContextMenu',\r
8511                                 'onSubmit',\r
8512                                 'onReset',\r
8513                                 'onPaste',\r
8514                                 'onPreProcess',\r
8515                                 'onPostProcess',\r
8516                                 'onBeforeSetContent',\r
8517                                 'onBeforeGetContent',\r
8518                                 'onSetContent',\r
8519                                 'onGetContent',\r
8520                                 'onLoadContent',\r
8521                                 'onSaveContent',\r
8522                                 'onNodeChange',\r
8523                                 'onChange',\r
8524                                 'onBeforeExecCommand',\r
8525                                 'onExecCommand',\r
8526                                 'onUndo',\r
8527                                 'onRedo',\r
8528                                 'onVisualAid',\r
8529                                 'onSetProgressState'\r
8530                         ], function(e) {\r
8531                                 t[e] = new Dispatcher(t);\r
8532                         });\r
8533 \r
8534                         // Default editor config\r
8535                         t.settings = s = extend({\r
8536                                 id : id,\r
8537                                 language : 'en',\r
8538                                 docs_language : 'en',\r
8539                                 theme : 'simple',\r
8540                                 skin : 'default',\r
8541                                 delta_width : 0,\r
8542                                 delta_height : 0,\r
8543                                 popup_css : '',\r
8544                                 plugins : '',\r
8545                                 document_base_url : tinymce.documentBaseURL,\r
8546                                 add_form_submit_trigger : 1,\r
8547                                 submit_patch : 1,\r
8548                                 add_unload_trigger : 1,\r
8549                                 convert_urls : 1,\r
8550                                 relative_urls : 1,\r
8551                                 remove_script_host : 1,\r
8552                                 table_inline_editing : 0,\r
8553                                 object_resizing : 1,\r
8554                                 cleanup : 1,\r
8555                                 accessibility_focus : 1,\r
8556                                 custom_shortcuts : 1,\r
8557                                 custom_undo_redo_keyboard_shortcuts : 1,\r
8558                                 custom_undo_redo_restore_selection : 1,\r
8559                                 custom_undo_redo : 1,\r
8560                                 doctype : '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">',\r
8561                                 visual_table_class : 'mceItemTable',\r
8562                                 visual : 1,\r
8563                                 inline_styles : true,\r
8564                                 convert_fonts_to_spans : true,\r
8565                                 font_size_style_values : 'xx-small,x-small,small,medium,large,x-large,xx-large',\r
8566                                 apply_source_formatting : 1,\r
8567                                 directionality : 'ltr',\r
8568                                 forced_root_block : 'p',\r
8569                                 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',\r
8570                                 hidden_input : 1,\r
8571                                 padd_empty_editor : 1,\r
8572                                 render_ui : 1,\r
8573                                 init_theme : 1,\r
8574                                 force_p_newlines : 1,\r
8575                                 indentation : '30px',\r
8576                                 keep_styles : 1,\r
8577                                 fix_table_elements : 1,\r
8578                                 removeformat_selector : 'span,b,strong,em,i,font,u,strike'\r
8579                         }, s);\r
8580 \r
8581                         // Setup URIs\r
8582                         t.documentBaseURI = new tinymce.util.URI(s.document_base_url || tinymce.documentBaseURL, {\r
8583                                 base_uri : tinyMCE.baseURI\r
8584                         });\r
8585                         t.baseURI = EditorManager.baseURI;\r
8586 \r
8587                         // Call setup\r
8588                         t.execCallback('setup', t);\r
8589                 },\r
8590 \r
8591                 render : function(nst) {\r
8592                         var t = this, s = t.settings, id = t.id, sl = tinymce.ScriptLoader;\r
8593 \r
8594                         // Page is not loaded yet, wait for it\r
8595                         if (!Event.domLoaded) {\r
8596                                 Event.add(document, 'init', function() {\r
8597                                         t.render();\r
8598                                 });\r
8599                                 return;\r
8600                         }\r
8601 \r
8602                         // Force strict loading mode if render us called by user and not internally\r
8603                         if (!nst) {\r
8604                                 s.strict_loading_mode = 1;\r
8605                                 tinyMCE.settings = s;\r
8606                         }\r
8607 \r
8608                         // Element not found, then skip initialization\r
8609                         if (!t.getElement())\r
8610                                 return;\r
8611 \r
8612                         if (s.strict_loading_mode) {\r
8613                                 sl.settings.strict_mode = s.strict_loading_mode;\r
8614                                 tinymce.DOM.settings.strict = 1;\r
8615                         }\r
8616 \r
8617                         // Add hidden input for non input elements inside form elements\r
8618                         if (!/TEXTAREA|INPUT/i.test(t.getElement().nodeName) && s.hidden_input && DOM.getParent(id, 'form'))\r
8619                                 DOM.insertAfter(DOM.create('input', {type : 'hidden', name : id}), id);\r
8620 \r
8621                         if (tinymce.WindowManager)\r
8622                                 t.windowManager = new tinymce.WindowManager(t);\r
8623 \r
8624                         if (s.encoding == 'xml') {\r
8625                                 t.onGetContent.add(function(ed, o) {\r
8626                                         if (o.save)\r
8627                                                 o.content = DOM.encode(o.content);\r
8628                                 });\r
8629                         }\r
8630 \r
8631                         if (s.add_form_submit_trigger) {\r
8632                                 t.onSubmit.addToTop(function() {\r
8633                                         if (t.initialized) {\r
8634                                                 t.save();\r
8635                                                 t.isNotDirty = 1;\r
8636                                         }\r
8637                                 });\r
8638                         }\r
8639 \r
8640                         if (s.add_unload_trigger) {\r
8641                                 t._beforeUnload = tinyMCE.onBeforeUnload.add(function() {\r
8642                                         if (t.initialized && !t.destroyed && !t.isHidden())\r
8643                                                 t.save({format : 'raw', no_events : true});\r
8644                                 });\r
8645                         }\r
8646 \r
8647                         tinymce.addUnload(t.destroy, t);\r
8648 \r
8649                         if (s.submit_patch) {\r
8650                                 t.onBeforeRenderUI.add(function() {\r
8651                                         var n = t.getElement().form;\r
8652 \r
8653                                         if (!n)\r
8654                                                 return;\r
8655 \r
8656                                         // Already patched\r
8657                                         if (n._mceOldSubmit)\r
8658                                                 return;\r
8659 \r
8660                                         // Check page uses id="submit" or name="submit" for it's submit button\r
8661                                         if (!n.submit.nodeType && !n.submit.length) {\r
8662                                                 t.formElement = n;\r
8663                                                 n._mceOldSubmit = n.submit;\r
8664                                                 n.submit = function() {\r
8665                                                         // Save all instances\r
8666                                                         EditorManager.triggerSave();\r
8667                                                         t.isNotDirty = 1;\r
8668 \r
8669                                                         return t.formElement._mceOldSubmit(t.formElement);\r
8670                                                 };\r
8671                                         }\r
8672 \r
8673                                         n = null;\r
8674                                 });\r
8675                         }\r
8676 \r
8677                         // Load scripts\r
8678                         function loadScripts() {\r
8679                                 if (s.language)\r
8680                                         sl.add(tinymce.baseURL + '/langs/' + s.language + '.js');\r
8681 \r
8682                                 if (s.theme && s.theme.charAt(0) != '-' && !ThemeManager.urls[s.theme])\r
8683                                         ThemeManager.load(s.theme, 'themes/' + s.theme + '/editor_template' + tinymce.suffix + '.js');\r
8684 \r
8685                                 each(explode(s.plugins), function(p) {\r
8686                                         if (p && p.charAt(0) != '-' && !PluginManager.urls[p]) {\r
8687                                                 // Skip safari plugin for other browsers\r
8688                                                 if (!isWebKit && p == 'safari')\r
8689                                                         return;\r
8690 \r
8691                                                 PluginManager.load(p, 'plugins/' + p + '/editor_plugin' + tinymce.suffix + '.js');\r
8692                                         }\r
8693                                 });\r
8694 \r
8695                                 // Init when que is loaded\r
8696                                 sl.loadQueue(function() {\r
8697                                         if (!t.removed)\r
8698                                                 t.init();\r
8699                                 });\r
8700                         };\r
8701 \r
8702                         // Load compat2x first\r
8703                         if (s.plugins.indexOf('compat2x') != -1) {\r
8704                                 PluginManager.load('compat2x', 'plugins/compat2x/editor_plugin' + tinymce.suffix + '.js');\r
8705                                 sl.loadQueue(loadScripts);\r
8706                         } else\r
8707                                 loadScripts();\r
8708                 },\r
8709 \r
8710                 init : function() {\r
8711                         var n, t = this, s = t.settings, w, h, e = t.getElement(), o, ti, u, bi, bc, re;\r
8712 \r
8713                         EditorManager.add(t);\r
8714 \r
8715                         // Create theme\r
8716                         if (s.theme) {\r
8717                                 s.theme = s.theme.replace(/-/, '');\r
8718                                 o = ThemeManager.get(s.theme);\r
8719                                 t.theme = new o();\r
8720 \r
8721                                 if (t.theme.init && s.init_theme)\r
8722                                         t.theme.init(t, ThemeManager.urls[s.theme] || tinymce.documentBaseURL.replace(/\/$/, ''));\r
8723                         }\r
8724 \r
8725                         // Create all plugins\r
8726                         each(explode(s.plugins.replace(/\-/g, '')), function(p) {\r
8727                                 var c = PluginManager.get(p), u = PluginManager.urls[p] || tinymce.documentBaseURL.replace(/\/$/, ''), po;\r
8728 \r
8729                                 if (c) {\r
8730                                         po = new c(t, u);\r
8731 \r
8732                                         t.plugins[p] = po;\r
8733 \r
8734                                         if (po.init)\r
8735                                                 po.init(t, u);\r
8736                                 }\r
8737                         });\r
8738 \r
8739                         // Setup popup CSS path(s)\r
8740                         if (s.popup_css !== false) {\r
8741                                 if (s.popup_css)\r
8742                                         s.popup_css = t.documentBaseURI.toAbsolute(s.popup_css);\r
8743                                 else\r
8744                                         s.popup_css = t.baseURI.toAbsolute("themes/" + s.theme + "/skins/" + s.skin + "/dialog.css");\r
8745                         }\r
8746 \r
8747                         if (s.popup_css_add)\r
8748                                 s.popup_css += ',' + t.documentBaseURI.toAbsolute(s.popup_css_add);\r
8749 \r
8750                         // Setup control factory\r
8751                         t.controlManager = new tinymce.ControlManager(t);\r
8752                         t.undoManager = new tinymce.UndoManager(t);\r
8753 \r
8754                         // Pass through\r
8755                         t.undoManager.onAdd.add(function(um, l) {\r
8756                                 if (!l.initial)\r
8757                                         return t.onChange.dispatch(t, l, um);\r
8758                         });\r
8759 \r
8760                         t.undoManager.onUndo.add(function(um, l) {\r
8761                                 return t.onUndo.dispatch(t, l, um);\r
8762                         });\r
8763 \r
8764                         t.undoManager.onRedo.add(function(um, l) {\r
8765                                 return t.onRedo.dispatch(t, l, um);\r
8766                         });\r
8767 \r
8768                         if (s.custom_undo_redo) {\r
8769                                 t.onExecCommand.add(function(ed, cmd, ui, val, a) {\r
8770                                         if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint' && (!a || !a.skip_undo))\r
8771                                                 t.undoManager.add();\r
8772                                 });\r
8773                         }\r
8774 \r
8775                         t.onExecCommand.add(function(ed, c) {\r
8776                                 // Don't refresh the select lists until caret move\r
8777                                 if (!/^(FontName|FontSize)$/.test(c))\r
8778                                         t.nodeChanged();\r
8779                         });\r
8780 \r
8781                         // Remove ghost selections on images and tables in Gecko\r
8782                         if (isGecko) {\r
8783                                 function repaint(a, o) {\r
8784                                         if (!o || !o.initial)\r
8785                                                 t.execCommand('mceRepaint');\r
8786                                 };\r
8787 \r
8788                                 t.onUndo.add(repaint);\r
8789                                 t.onRedo.add(repaint);\r
8790                                 t.onSetContent.add(repaint);\r
8791                         }\r
8792 \r
8793                         // Enables users to override the control factory\r
8794                         t.onBeforeRenderUI.dispatch(t, t.controlManager);\r
8795 \r
8796                         // Measure box\r
8797                         if (s.render_ui) {\r
8798                                 w = s.width || e.style.width || e.offsetWidth;\r
8799                                 h = s.height || e.style.height || e.offsetHeight;\r
8800                                 t.orgDisplay = e.style.display;\r
8801                                 re = /^[0-9\.]+(|px)$/i;\r
8802 \r
8803                                 if (re.test('' + w))\r
8804                                         w = Math.max(parseInt(w) + (o.deltaWidth || 0), 100);\r
8805 \r
8806                                 if (re.test('' + h))\r
8807                                         h = Math.max(parseInt(h) + (o.deltaHeight || 0), 100);\r
8808 \r
8809                                 // Render UI\r
8810                                 o = t.theme.renderUI({\r
8811                                         targetNode : e,\r
8812                                         width : w,\r
8813                                         height : h,\r
8814                                         deltaWidth : s.delta_width,\r
8815                                         deltaHeight : s.delta_height\r
8816                                 });\r
8817 \r
8818                                 t.editorContainer = o.editorContainer;\r
8819                         }\r
8820 \r
8821 \r
8822                         // Resize editor\r
8823                         DOM.setStyles(o.sizeContainer || o.editorContainer, {\r
8824                                 width : w,\r
8825                                 height : h\r
8826                         });\r
8827 \r
8828                         h = (o.iframeHeight || h) + (typeof(h) == 'number' ? (o.deltaHeight || 0) : '');\r
8829                         if (h < 100)\r
8830                                 h = 100;\r
8831 \r
8832                         t.iframeHTML = s.doctype + '<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="' + t.documentBaseURI.getURI() + '" />';\r
8833                         t.iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';\r
8834 \r
8835                         if (tinymce.relaxedDomain)\r
8836                                 t.iframeHTML += '<script type="text/javascript">document.domain = "' + tinymce.relaxedDomain + '";</script>';\r
8837 \r
8838                         bi = s.body_id || 'tinymce';\r
8839                         if (bi.indexOf('=') != -1) {\r
8840                                 bi = t.getParam('body_id', '', 'hash');\r
8841                                 bi = bi[t.id] || bi;\r
8842                         }\r
8843 \r
8844                         bc = s.body_class || '';\r
8845                         if (bc.indexOf('=') != -1) {\r
8846                                 bc = t.getParam('body_class', '', 'hash');\r
8847                                 bc = bc[t.id] || '';\r
8848                         }\r
8849 \r
8850                         t.iframeHTML += '</head><body id="' + bi + '" class="mceContentBody ' + bc + '"></body></html>';\r
8851 \r
8852                         // Domain relaxing enabled, then set document domain\r
8853                         if (tinymce.relaxedDomain) {\r
8854                                 // We need to write the contents here in IE since multiple writes messes up refresh button and back button\r
8855                                 if (isIE || (tinymce.isOpera && parseFloat(opera.version()) >= 9.5))\r
8856                                         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();})()';\r
8857                                 else if (tinymce.isOpera)\r
8858                                         u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";document.close();ed.setupIframe();})()';                                  \r
8859                         }\r
8860 \r
8861                         // Create iframe\r
8862                         n = DOM.add(o.iframeContainer, 'iframe', {\r
8863                                 id : t.id + "_ifr",\r
8864                                 src : u || 'javascript:""', // Workaround for HTTPS warning in IE6/7\r
8865                                 frameBorder : '0',\r
8866                                 style : {\r
8867                                         width : '100%',\r
8868                                         height : h\r
8869                                 }\r
8870                         });\r
8871 \r
8872                         t.contentAreaContainer = o.iframeContainer;\r
8873                         DOM.get(o.editorContainer).style.display = t.orgDisplay;\r
8874                         DOM.get(t.id).style.display = 'none';\r
8875 \r
8876                         if (!isIE || !tinymce.relaxedDomain)\r
8877                                 t.setupIframe();\r
8878 \r
8879                         e = n = o = null; // Cleanup\r
8880                 },\r
8881 \r
8882                 setupIframe : function() {\r
8883                         var t = this, s = t.settings, e = DOM.get(t.id), d = t.getDoc(), h, b;\r
8884 \r
8885                         // Setup iframe body\r
8886                         if (!isIE || !tinymce.relaxedDomain) {\r
8887                                 d.open();\r
8888                                 d.write(t.iframeHTML);\r
8889                                 d.close();\r
8890                         }\r
8891 \r
8892                         // Design mode needs to be added here Ctrl+A will fail otherwise\r
8893                         if (!isIE) {\r
8894                                 try {\r
8895                                         if (!s.readonly)\r
8896                                                 d.designMode = 'On';\r
8897                                 } catch (ex) {\r
8898                                         // Will fail on Gecko if the editor is placed in an hidden container element\r
8899                                         // The design mode will be set ones the editor is focused\r
8900                                 }\r
8901                         }\r
8902 \r
8903                         // IE needs to use contentEditable or it will display non secure items for HTTPS\r
8904                         if (isIE) {\r
8905                                 // It will not steal focus if we hide it while setting contentEditable\r
8906                                 b = t.getBody();\r
8907                                 DOM.hide(b);\r
8908 \r
8909                                 if (!s.readonly)\r
8910                                         b.contentEditable = true;\r
8911 \r
8912                                 DOM.show(b);\r
8913                         }\r
8914 \r
8915                         // Setup objects\r
8916                         t.dom = new tinymce.DOM.DOMUtils(t.getDoc(), {\r
8917                                 keep_values : true,\r
8918                                 url_converter : t.convertURL,\r
8919                                 url_converter_scope : t,\r
8920                                 hex_colors : s.force_hex_style_colors,\r
8921                                 class_filter : s.class_filter,\r
8922                                 update_styles : 1,\r
8923                                 fix_ie_paragraphs : 1\r
8924                         });\r
8925 \r
8926                         t.serializer = new tinymce.dom.Serializer({\r
8927                                 entity_encoding : s.entity_encoding,\r
8928                                 entities : s.entities,\r
8929                                 valid_elements : s.verify_html === false ? '*[*]' : s.valid_elements,\r
8930                                 extended_valid_elements : s.extended_valid_elements,\r
8931                                 valid_child_elements : s.valid_child_elements,\r
8932                                 invalid_elements : s.invalid_elements,\r
8933                                 fix_table_elements : s.fix_table_elements,\r
8934                                 fix_list_elements : s.fix_list_elements,\r
8935                                 fix_content_duplication : s.fix_content_duplication,\r
8936                                 convert_fonts_to_spans : s.convert_fonts_to_spans,\r
8937                                 font_size_classes  : s.font_size_classes,\r
8938                                 font_size_style_values : s.font_size_style_values,\r
8939                                 apply_source_formatting : s.apply_source_formatting,\r
8940                                 remove_linebreaks : s.remove_linebreaks,\r
8941                                 element_format : s.element_format,\r
8942                                 dom : t.dom\r
8943                         });\r
8944 \r
8945                         t.selection = new tinymce.dom.Selection(t.dom, t.getWin(), t.serializer);\r
8946                         t.forceBlocks = new tinymce.ForceBlocks(t, {\r
8947                                 forced_root_block : s.forced_root_block\r
8948                         });\r
8949                         t.editorCommands = new tinymce.EditorCommands(t);\r
8950 \r
8951                         // Pass through\r
8952                         t.serializer.onPreProcess.add(function(se, o) {\r
8953                                 return t.onPreProcess.dispatch(t, o, se);\r
8954                         });\r
8955 \r
8956                         t.serializer.onPostProcess.add(function(se, o) {\r
8957                                 return t.onPostProcess.dispatch(t, o, se);\r
8958                         });\r
8959 \r
8960                         t.onPreInit.dispatch(t);\r
8961 \r
8962                         if (!s.gecko_spellcheck)\r
8963                                 t.getBody().spellcheck = 0;\r
8964 \r
8965                         if (!s.readonly)\r
8966                                 t._addEvents();\r
8967 \r
8968                         t.controlManager.onPostRender.dispatch(t, t.controlManager);\r
8969                         t.onPostRender.dispatch(t);\r
8970 \r
8971                         if (s.directionality)\r
8972                                 t.getBody().dir = s.directionality;\r
8973 \r
8974                         if (s.nowrap)\r
8975                                 t.getBody().style.whiteSpace = "nowrap";\r
8976 \r
8977                         if (s.auto_resize)\r
8978                                 t.onNodeChange.add(t.resizeToContent, t);\r
8979 \r
8980                         if (s.custom_elements) {\r
8981                                 function handleCustom(ed, o) {\r
8982                                         each(explode(s.custom_elements), function(v) {\r
8983                                                 var n;\r
8984 \r
8985                                                 if (v.indexOf('~') === 0) {\r
8986                                                         v = v.substring(1);\r
8987                                                         n = 'span';\r
8988                                                 } else\r
8989                                                         n = 'div';\r
8990 \r
8991                                                 o.content = o.content.replace(new RegExp('<(' + v + ')([^>]*)>', 'g'), '<' + n + ' mce_name="$1"$2>');\r
8992                                                 o.content = o.content.replace(new RegExp('</(' + v + ')>', 'g'), '</' + n + '>');\r
8993                                         });\r
8994                                 };\r
8995 \r
8996                                 t.onBeforeSetContent.add(handleCustom);\r
8997                                 t.onPostProcess.add(function(ed, o) {\r
8998                                         if (o.set)\r
8999                                                 handleCustom(ed, o)\r
9000                                 });\r
9001                         }\r
9002 \r
9003                         if (s.handle_node_change_callback) {\r
9004                                 t.onNodeChange.add(function(ed, cm, n) {\r
9005                                         t.execCallback('handle_node_change_callback', t.id, n, -1, -1, true, t.selection.isCollapsed());\r
9006                                 });\r
9007                         }\r
9008 \r
9009                         if (s.save_callback) {\r
9010                                 t.onSaveContent.add(function(ed, o) {\r
9011                                         var h = t.execCallback('save_callback', t.id, o.content, t.getBody());\r
9012 \r
9013                                         if (h)\r
9014                                                 o.content = h;\r
9015                                 });\r
9016                         }\r
9017 \r
9018                         if (s.onchange_callback) {\r
9019                                 t.onChange.add(function(ed, l) {\r
9020                                         t.execCallback('onchange_callback', t, l);\r
9021                                 });\r
9022                         }\r
9023 \r
9024                         if (s.convert_newlines_to_brs) {\r
9025                                 t.onBeforeSetContent.add(function(ed, o) {\r
9026                                         if (o.initial)\r
9027                                                 o.content = o.content.replace(/\r?\n/g, '<br />');\r
9028                                 });\r
9029                         }\r
9030 \r
9031                         if (s.fix_nesting && isIE) {\r
9032                                 t.onBeforeSetContent.add(function(ed, o) {\r
9033                                         o.content = t._fixNesting(o.content);\r
9034                                 });\r
9035                         }\r
9036 \r
9037                         if (s.preformatted) {\r
9038                                 t.onPostProcess.add(function(ed, o) {\r
9039                                         o.content = o.content.replace(/^\s*<pre.*?>/, '');\r
9040                                         o.content = o.content.replace(/<\/pre>\s*$/, '');\r
9041 \r
9042                                         if (o.set)\r
9043                                                 o.content = '<pre class="mceItemHidden">' + o.content + '</pre>';\r
9044                                 });\r
9045                         }\r
9046 \r
9047                         if (s.verify_css_classes) {\r
9048                                 t.serializer.attribValueFilter = function(n, v) {\r
9049                                         var s, cl;\r
9050 \r
9051                                         if (n == 'class') {\r
9052                                                 // Build regexp for classes\r
9053                                                 if (!t.classesRE) {\r
9054                                                         cl = t.dom.getClasses();\r
9055 \r
9056                                                         if (cl.length > 0) {\r
9057                                                                 s = '';\r
9058 \r
9059                                                                 each (cl, function(o) {\r
9060                                                                         s += (s ? '|' : '') + o['class'];\r
9061                                                                 });\r
9062 \r
9063                                                                 t.classesRE = new RegExp('(' + s + ')', 'gi');\r
9064                                                         }\r
9065                                                 }\r
9066 \r
9067                                                 return !t.classesRE || /(\bmceItem\w+\b|\bmceTemp\w+\b)/g.test(v) || t.classesRE.test(v) ? v : '';\r
9068                                         }\r
9069 \r
9070                                         return v;\r
9071                                 };\r
9072                         }\r
9073 \r
9074                         if (s.convert_fonts_to_spans)\r
9075                                 t._convertFonts();\r
9076 \r
9077                         if (s.inline_styles)\r
9078                                 t._convertInlineElements();\r
9079 \r
9080                         if (s.cleanup_callback) {\r
9081                                 t.onBeforeSetContent.add(function(ed, o) {\r
9082                                         o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);\r
9083                                 });\r
9084 \r
9085                                 t.onPreProcess.add(function(ed, o) {\r
9086                                         if (o.set)\r
9087                                                 t.execCallback('cleanup_callback', 'insert_to_editor_dom', o.node, o);\r
9088 \r
9089                                         if (o.get)\r
9090                                                 t.execCallback('cleanup_callback', 'get_from_editor_dom', o.node, o);\r
9091                                 });\r
9092 \r
9093                                 t.onPostProcess.add(function(ed, o) {\r
9094                                         if (o.set)\r
9095                                                 o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);\r
9096 \r
9097                                         if (o.get)                                              \r
9098                                                 o.content = t.execCallback('cleanup_callback', 'get_from_editor', o.content, o);\r
9099                                 });\r
9100                         }\r
9101 \r
9102                         if (s.save_callback) {\r
9103                                 t.onGetContent.add(function(ed, o) {\r
9104                                         if (o.save)\r
9105                                                 o.content = t.execCallback('save_callback', t.id, o.content, t.getBody());\r
9106                                 });\r
9107                         }\r
9108 \r
9109                         if (s.handle_event_callback) {\r
9110                                 t.onEvent.add(function(ed, e, o) {\r
9111                                         if (t.execCallback('handle_event_callback', e, ed, o) === false)\r
9112                                                 Event.cancel(e);\r
9113                                 });\r
9114                         }\r
9115 \r
9116                         // Add visual aids when new contents is added\r
9117                         t.onSetContent.add(function() {\r
9118                                 t.addVisual(t.getBody());\r
9119                         });\r
9120 \r
9121                         // Remove empty contents\r
9122                         if (s.padd_empty_editor) {\r
9123                                 t.onPostProcess.add(function(ed, o) {\r
9124                                         o.content = o.content.replace(/^(<p[^>]*>(&nbsp;|&#160;|\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/, '');\r
9125                                 });\r
9126                         }\r
9127 \r
9128                         if (isGecko) {\r
9129                                 // Fix gecko link bug, when a link is placed at the end of block elements there is\r
9130                                 // no way to move the caret behind the link. This fix adds a bogus br element after the link\r
9131                                 function fixLinks(ed, o) {\r
9132                                         each(ed.dom.select('a'), function(n) {\r
9133                                                 var pn = n.parentNode;\r
9134 \r
9135                                                 if (ed.dom.isBlock(pn) && pn.lastChild === n)\r
9136                                                         ed.dom.add(pn, 'br', {'mce_bogus' : 1});\r
9137                                         });\r
9138                                 };\r
9139 \r
9140                                 t.onExecCommand.add(function(ed, cmd) {\r
9141                                         if (cmd === 'CreateLink')\r
9142                                                 fixLinks(ed);\r
9143                                 });\r
9144 \r
9145                                 t.onSetContent.add(t.selection.onSetContent.add(fixLinks));\r
9146 \r
9147                                 if (!s.readonly) {\r
9148                                         try {\r
9149                                                 // Design mode must be set here once again to fix a bug where\r
9150                                                 // Ctrl+A/Delete/Backspace didn't work if the editor was added using mceAddControl then removed then added again\r
9151                                                 d.designMode = 'Off';\r
9152                                                 d.designMode = 'On';\r
9153                                         } catch (ex) {\r
9154                                                 // Will fail on Gecko if the editor is placed in an hidden container element\r
9155                                                 // The design mode will be set ones the editor is focused\r
9156                                         }\r
9157                                 }\r
9158                         }\r
9159 \r
9160                         // A small timeout was needed since firefox will remove. Bug: #1838304\r
9161                         setTimeout(function () {\r
9162                                 if (t.removed)\r
9163                                         return;\r
9164 \r
9165                                 t.load({initial : true, format : (s.cleanup_on_startup ? 'html' : 'raw')});\r
9166                                 t.startContent = t.getContent({format : 'raw'});\r
9167                                 t.undoManager.add({initial : true});\r
9168                                 t.initialized = true;\r
9169 \r
9170                                 t.onInit.dispatch(t);\r
9171                                 t.execCallback('setupcontent_callback', t.id, t.getBody(), t.getDoc());\r
9172                                 t.execCallback('init_instance_callback', t);\r
9173                                 t.focus(true);\r
9174                                 t.nodeChanged({initial : 1});\r
9175 \r
9176                                 // Load specified content CSS last\r
9177                                 if (s.content_css) {\r
9178                                         tinymce.each(explode(s.content_css), function(u) {\r
9179                                                 t.dom.loadCSS(t.documentBaseURI.toAbsolute(u));\r
9180                                         });\r
9181                                 }\r
9182 \r
9183                                 // Handle auto focus\r
9184                                 if (s.auto_focus) {\r
9185                                         setTimeout(function () {\r
9186                                                 var ed = EditorManager.get(s.auto_focus);\r
9187 \r
9188                                                 ed.selection.select(ed.getBody(), 1);\r
9189                                                 ed.selection.collapse(1);\r
9190                                                 ed.getWin().focus();\r
9191                                         }, 100);\r
9192                                 }\r
9193                         }, 1);\r
9194         \r
9195                         e = null;\r
9196                 },\r
9197 \r
9198 \r
9199                 focus : function(sf) {\r
9200                         var oed, t = this, ce = t.settings.content_editable;\r
9201 \r
9202                         if (!sf) {\r
9203                                 // Is not content editable or the selection is outside the area in IE\r
9204                                 // the IE statement is needed to avoid bluring if element selections inside layers since\r
9205                                 // the layer is like it's own document in IE\r
9206                                 if (!ce && (!isIE || t.selection.getNode().ownerDocument != t.getDoc()))\r
9207                                         t.getWin().focus();\r
9208 \r
9209                         }\r
9210 \r
9211                         if (EditorManager.activeEditor != t) {\r
9212                                 if ((oed = EditorManager.activeEditor) != null)\r
9213                                         oed.onDeactivate.dispatch(oed, t);\r
9214 \r
9215                                 t.onActivate.dispatch(t, oed);\r
9216                         }\r
9217 \r
9218                         EditorManager._setActive(t);\r
9219                 },\r
9220 \r
9221                 execCallback : function(n) {\r
9222                         var t = this, f = t.settings[n], s;\r
9223 \r
9224                         if (!f)\r
9225                                 return;\r
9226 \r
9227                         // Look through lookup\r
9228                         if (t.callbackLookup && (s = t.callbackLookup[n])) {\r
9229                                 f = s.func;\r
9230                                 s = s.scope;\r
9231                         }\r
9232 \r
9233                         if (is(f, 'string')) {\r
9234                                 s = f.replace(/\.\w+$/, '');\r
9235                                 s = s ? tinymce.resolve(s) : 0;\r
9236                                 f = tinymce.resolve(f);\r
9237                                 t.callbackLookup = t.callbackLookup || {};\r
9238                                 t.callbackLookup[n] = {func : f, scope : s};\r
9239                         }\r
9240 \r
9241                         return f.apply(s || t, Array.prototype.slice.call(arguments, 1));\r
9242                 },\r
9243 \r
9244                 translate : function(s) {\r
9245                         var c = this.settings.language || 'en', i18n = EditorManager.i18n;\r
9246 \r
9247                         if (!s)\r
9248                                 return '';\r
9249 \r
9250                         return i18n[c + '.' + s] || s.replace(/{\#([^}]+)\}/g, function(a, b) {\r
9251                                 return i18n[c + '.' + b] || '{#' + b + '}';\r
9252                         });\r
9253                 },\r
9254 \r
9255                 getLang : function(n, dv) {\r
9256                         return EditorManager.i18n[(this.settings.language || 'en') + '.' + n] || (is(dv) ? dv : '{#' + n + '}');\r
9257                 },\r
9258 \r
9259                 getParam : function(n, dv, ty) {\r
9260                         var tr = tinymce.trim, v = is(this.settings[n]) ? this.settings[n] : dv, o;\r
9261 \r
9262                         if (ty === 'hash') {\r
9263                                 o = {};\r
9264 \r
9265                                 if (is(v, 'string')) {\r
9266                                         each(v.indexOf('=') > 0 ? v.split(/[;,](?![^=;,]*(?:[;,]|$))/) : v.split(','), function(v) {\r
9267                                                 v = v.split('=');\r
9268 \r
9269                                                 if (v.length > 1)\r
9270                                                         o[tr(v[0])] = tr(v[1]);\r
9271                                                 else\r
9272                                                         o[tr(v[0])] = tr(v);\r
9273                                         });\r
9274                                 } else\r
9275                                         o = v;\r
9276 \r
9277                                 return o;\r
9278                         }\r
9279 \r
9280                         return v;\r
9281                 },\r
9282 \r
9283                 nodeChanged : function(o) {\r
9284                         var t = this, s = t.selection, n = s.getNode() || t.getBody();\r
9285 \r
9286                         // Fix for bug #1896577 it seems that this can not be fired while the editor is loading\r
9287                         if (t.initialized) {\r
9288                                 t.onNodeChange.dispatch(\r
9289                                         t,\r
9290                                         o ? o.controlManager || t.controlManager : t.controlManager,\r
9291                                         isIE && n.ownerDocument != t.getDoc() ? t.getBody() : n, // Fix for IE initial state\r
9292                                         s.isCollapsed(),\r
9293                                         o\r
9294                                 );\r
9295                         }\r
9296                 },\r
9297 \r
9298                 addButton : function(n, s) {\r
9299                         var t = this;\r
9300 \r
9301                         t.buttons = t.buttons || {};\r
9302                         t.buttons[n] = s;\r
9303                 },\r
9304 \r
9305                 addCommand : function(n, f, s) {\r
9306                         this.execCommands[n] = {func : f, scope : s || this};\r
9307                 },\r
9308 \r
9309                 addQueryStateHandler : function(n, f, s) {\r
9310                         this.queryStateCommands[n] = {func : f, scope : s || this};\r
9311                 },\r
9312 \r
9313                 addQueryValueHandler : function(n, f, s) {\r
9314                         this.queryValueCommands[n] = {func : f, scope : s || this};\r
9315                 },\r
9316 \r
9317                 addShortcut : function(pa, desc, cmd_func, sc) {\r
9318                         var t = this, c;\r
9319 \r
9320                         if (!t.settings.custom_shortcuts)\r
9321                                 return false;\r
9322 \r
9323                         t.shortcuts = t.shortcuts || {};\r
9324 \r
9325                         if (is(cmd_func, 'string')) {\r
9326                                 c = cmd_func;\r
9327 \r
9328                                 cmd_func = function() {\r
9329                                         t.execCommand(c, false, null);\r
9330                                 };\r
9331                         }\r
9332 \r
9333                         if (is(cmd_func, 'object')) {\r
9334                                 c = cmd_func;\r
9335 \r
9336                                 cmd_func = function() {\r
9337                                         t.execCommand(c[0], c[1], c[2]);\r
9338                                 };\r
9339                         }\r
9340 \r
9341                         each(explode(pa), function(pa) {\r
9342                                 var o = {\r
9343                                         func : cmd_func,\r
9344                                         scope : sc || this,\r
9345                                         desc : desc,\r
9346                                         alt : false,\r
9347                                         ctrl : false,\r
9348                                         shift : false\r
9349                                 };\r
9350 \r
9351                                 each(explode(pa, '+'), function(v) {\r
9352                                         switch (v) {\r
9353                                                 case 'alt':\r
9354                                                 case 'ctrl':\r
9355                                                 case 'shift':\r
9356                                                         o[v] = true;\r
9357                                                         break;\r
9358 \r
9359                                                 default:\r
9360                                                         o.charCode = v.charCodeAt(0);\r
9361                                                         o.keyCode = v.toUpperCase().charCodeAt(0);\r
9362                                         }\r
9363                                 });\r
9364 \r
9365                                 t.shortcuts[(o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode] = o;\r
9366                         });\r
9367 \r
9368                         return true;\r
9369                 },\r
9370 \r
9371                 execCommand : function(cmd, ui, val, a) {\r
9372                         var t = this, s = 0, o, st;\r
9373 \r
9374                         if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(cmd) && (!a || !a.skip_focus))\r
9375                                 t.focus();\r
9376 \r
9377                         o = {};\r
9378                         t.onBeforeExecCommand.dispatch(t, cmd, ui, val, o);\r
9379                         if (o.terminate)\r
9380                                 return false;\r
9381 \r
9382                         // Command callback\r
9383                         if (t.execCallback('execcommand_callback', t.id, t.selection.getNode(), cmd, ui, val)) {\r
9384                                 t.onExecCommand.dispatch(t, cmd, ui, val, a);\r
9385                                 return true;\r
9386                         }\r
9387 \r
9388                         // Registred commands\r
9389                         if (o = t.execCommands[cmd]) {\r
9390                                 st = o.func.call(o.scope, ui, val);\r
9391 \r
9392                                 // Fall through on true\r
9393                                 if (st !== true) {\r
9394                                         t.onExecCommand.dispatch(t, cmd, ui, val, a);\r
9395                                         return st;\r
9396                                 }\r
9397                         }\r
9398 \r
9399                         // Plugin commands\r
9400                         each(t.plugins, function(p) {\r
9401                                 if (p.execCommand && p.execCommand(cmd, ui, val)) {\r
9402                                         t.onExecCommand.dispatch(t, cmd, ui, val, a);\r
9403                                         s = 1;\r
9404                                         return false;\r
9405                                 }\r
9406                         });\r
9407 \r
9408                         if (s)\r
9409                                 return true;\r
9410 \r
9411                         // Theme commands\r
9412                         if (t.theme && t.theme.execCommand && t.theme.execCommand(cmd, ui, val)) {\r
9413                                 t.onExecCommand.dispatch(t, cmd, ui, val, a);\r
9414                                 return true;\r
9415                         }\r
9416 \r
9417                         // Execute global commands\r
9418                         if (tinymce.GlobalCommands.execCommand(t, cmd, ui, val)) {\r
9419                                 t.onExecCommand.dispatch(t, cmd, ui, val, a);\r
9420                                 return true;\r
9421                         }\r
9422 \r
9423                         // Editor commands\r
9424                         if (t.editorCommands.execCommand(cmd, ui, val)) {\r
9425                                 t.onExecCommand.dispatch(t, cmd, ui, val, a);\r
9426                                 return true;\r
9427                         }\r
9428 \r
9429                         // Browser commands\r
9430                         t.getDoc().execCommand(cmd, ui, val);\r
9431                         t.onExecCommand.dispatch(t, cmd, ui, val, a);\r
9432                 },\r
9433 \r
9434                 queryCommandState : function(c) {\r
9435                         var t = this, o, s;\r
9436 \r
9437                         // Is hidden then return undefined\r
9438                         if (t._isHidden())\r
9439                                 return;\r
9440 \r
9441                         // Registred commands\r
9442                         if (o = t.queryStateCommands[c]) {\r
9443                                 s = o.func.call(o.scope);\r
9444 \r
9445                                 // Fall though on true\r
9446                                 if (s !== true)\r
9447                                         return s;\r
9448                         }\r
9449 \r
9450                         // Registred commands\r
9451                         o = t.editorCommands.queryCommandState(c);\r
9452                         if (o !== -1)\r
9453                                 return o;\r
9454 \r
9455                         // Browser commands\r
9456                         try {\r
9457                                 return this.getDoc().queryCommandState(c);\r
9458                         } catch (ex) {\r
9459                                 // Fails sometimes see bug: 1896577\r
9460                         }\r
9461                 },\r
9462 \r
9463                 queryCommandValue : function(c) {\r
9464                         var t = this, o, s;\r
9465 \r
9466                         // Is hidden then return undefined\r
9467                         if (t._isHidden())\r
9468                                 return;\r
9469 \r
9470                         // Registred commands\r
9471                         if (o = t.queryValueCommands[c]) {\r
9472                                 s = o.func.call(o.scope);\r
9473 \r
9474                                 // Fall though on true\r
9475                                 if (s !== true)\r
9476                                         return s;\r
9477                         }\r
9478 \r
9479                         // Registred commands\r
9480                         o = t.editorCommands.queryCommandValue(c);\r
9481                         if (is(o))\r
9482                                 return o;\r
9483 \r
9484                         // Browser commands\r
9485                         try {\r
9486                                 return this.getDoc().queryCommandValue(c);\r
9487                         } catch (ex) {\r
9488                                 // Fails sometimes see bug: 1896577\r
9489                         }\r
9490                 },\r
9491 \r
9492                 show : function() {\r
9493                         var t = this;\r
9494 \r
9495                         DOM.show(t.getContainer());\r
9496                         DOM.hide(t.id);\r
9497                         t.load();\r
9498                 },\r
9499 \r
9500                 hide : function() {\r
9501                         var t = this, d = t.getDoc();\r
9502 \r
9503                         // Fixed bug where IE has a blinking cursor left from the editor\r
9504                         if (isIE && d)\r
9505                                 d.execCommand('SelectAll');\r
9506 \r
9507                         // We must save before we hide so Safari doesn't crash\r
9508                         t.save();\r
9509                         DOM.hide(t.getContainer());\r
9510                         DOM.setStyle(t.id, 'display', t.orgDisplay);\r
9511                 },\r
9512 \r
9513                 isHidden : function() {\r
9514                         return !DOM.isHidden(this.id);\r
9515                 },\r
9516 \r
9517                 setProgressState : function(b, ti, o) {\r
9518                         this.onSetProgressState.dispatch(this, b, ti, o);\r
9519 \r
9520                         return b;\r
9521                 },\r
9522 \r
9523                 resizeToContent : function() {\r
9524                         var t = this;\r
9525 \r
9526                         DOM.setStyle(t.id + "_ifr", 'height', t.getBody().scrollHeight);\r
9527                 },\r
9528 \r
9529                 load : function(o) {\r
9530                         var t = this, e = t.getElement(), h;\r
9531 \r
9532                         if (e) {\r
9533                                 o = o || {};\r
9534                                 o.load = true;\r
9535 \r
9536                                 // Double encode existing entities in the value\r
9537                                 h = t.setContent(is(e.value) ? e.value : e.innerHTML, o);\r
9538                                 o.element = e;\r
9539 \r
9540                                 if (!o.no_events)\r
9541                                         t.onLoadContent.dispatch(t, o);\r
9542 \r
9543                                 o.element = e = null;\r
9544 \r
9545                                 return h;\r
9546                         }\r
9547                 },\r
9548 \r
9549                 save : function(o) {\r
9550                         var t = this, e = t.getElement(), h, f;\r
9551 \r
9552                         if (!e || !t.initialized)\r
9553                                 return;\r
9554 \r
9555                         o = o || {};\r
9556                         o.save = true;\r
9557 \r
9558                         // Add undo level will trigger onchange event\r
9559                         if (!o.no_events) {\r
9560                                 t.undoManager.typing = 0;\r
9561                                 t.undoManager.add();\r
9562                         }\r
9563 \r
9564                         o.element = e;\r
9565                         h = o.content = t.getContent(o);\r
9566 \r
9567                         if (!o.no_events)\r
9568                                 t.onSaveContent.dispatch(t, o);\r
9569 \r
9570                         h = o.content;\r
9571 \r
9572                         if (!/TEXTAREA|INPUT/i.test(e.nodeName)) {\r
9573                                 e.innerHTML = h;\r
9574 \r
9575                                 // Update hidden form element\r
9576                                 if (f = DOM.getParent(t.id, 'form')) {\r
9577                                         each(f.elements, function(e) {\r
9578                                                 if (e.name == t.id) {\r
9579                                                         e.value = h;\r
9580                                                         return false;\r
9581                                                 }\r
9582                                         });\r
9583                                 }\r
9584                         } else\r
9585                                 e.value = h;\r
9586 \r
9587                         o.element = e = null;\r
9588 \r
9589                         return h;\r
9590                 },\r
9591 \r
9592                 setContent : function(h, o) {\r
9593                         var t = this;\r
9594 \r
9595                         o = o || {};\r
9596                         o.format = o.format || 'html';\r
9597                         o.set = true;\r
9598                         o.content = h;\r
9599 \r
9600                         if (!o.no_events)\r
9601                                 t.onBeforeSetContent.dispatch(t, o);\r
9602 \r
9603                         // Padd empty content in Gecko and Safari. Commands will otherwise fail on the content\r
9604                         // It will also be impossible to place the caret in the editor unless there is a BR element present\r
9605                         if (!tinymce.isIE && (h.length === 0 || /^\s+$/.test(h))) {\r
9606                                 o.content = t.dom.setHTML(t.getBody(), '<br mce_bogus="1" />');\r
9607                                 o.format = 'raw';\r
9608                         }\r
9609 \r
9610                         o.content = t.dom.setHTML(t.getBody(), tinymce.trim(o.content));\r
9611 \r
9612                         if (o.format != 'raw' && t.settings.cleanup) {\r
9613                                 o.getInner = true;\r
9614                                 o.content = t.dom.setHTML(t.getBody(), t.serializer.serialize(t.getBody(), o));\r
9615                         }\r
9616 \r
9617                         if (!o.no_events)\r
9618                                 t.onSetContent.dispatch(t, o);\r
9619 \r
9620                         return o.content;\r
9621                 },\r
9622 \r
9623                 getContent : function(o) {\r
9624                         var t = this, h;\r
9625 \r
9626                         o = o || {};\r
9627                         o.format = o.format || 'html';\r
9628                         o.get = true;\r
9629 \r
9630                         if (!o.no_events)\r
9631                                 t.onBeforeGetContent.dispatch(t, o);\r
9632 \r
9633                         if (o.format != 'raw' && t.settings.cleanup) {\r
9634                                 o.getInner = true;\r
9635                                 h = t.serializer.serialize(t.getBody(), o);\r
9636                         } else\r
9637                                 h = t.getBody().innerHTML;\r
9638 \r
9639                         h = h.replace(/^\s*|\s*$/g, '');\r
9640                         o.content = h;\r
9641 \r
9642                         if (!o.no_events)\r
9643                                 t.onGetContent.dispatch(t, o);\r
9644 \r
9645                         return o.content;\r
9646                 },\r
9647 \r
9648                 isDirty : function() {\r
9649                         var t = this;\r
9650 \r
9651                         return tinymce.trim(t.startContent) != tinymce.trim(t.getContent({format : 'raw', no_events : 1})) && !t.isNotDirty;\r
9652                 },\r
9653 \r
9654                 getContainer : function() {\r
9655                         var t = this;\r
9656 \r
9657                         if (!t.container)\r
9658                                 t.container = DOM.get(t.editorContainer || t.id + '_parent');\r
9659 \r
9660                         return t.container;\r
9661                 },\r
9662 \r
9663                 getContentAreaContainer : function() {\r
9664                         return this.contentAreaContainer;\r
9665                 },\r
9666 \r
9667                 getElement : function() {\r
9668                         return DOM.get(this.settings.content_element || this.id);\r
9669                 },\r
9670 \r
9671                 getWin : function() {\r
9672                         var t = this, e;\r
9673 \r
9674                         if (!t.contentWindow) {\r
9675                                 e = DOM.get(t.id + "_ifr");\r
9676 \r
9677                                 if (e)\r
9678                                         t.contentWindow = e.contentWindow;\r
9679                         }\r
9680 \r
9681                         return t.contentWindow;\r
9682                 },\r
9683 \r
9684                 getDoc : function() {\r
9685                         var t = this, w;\r
9686 \r
9687                         if (!t.contentDocument) {\r
9688                                 w = t.getWin();\r
9689 \r
9690                                 if (w)\r
9691                                         t.contentDocument = w.document;\r
9692                         }\r
9693 \r
9694                         return t.contentDocument;\r
9695                 },\r
9696 \r
9697                 getBody : function() {\r
9698                         return this.bodyElement || this.getDoc().body;\r
9699                 },\r
9700 \r
9701                 convertURL : function(u, n, e) {\r
9702                         var t = this, s = t.settings;\r
9703 \r
9704                         // Use callback instead\r
9705                         if (s.urlconverter_callback)\r
9706                                 return t.execCallback('urlconverter_callback', u, e, true, n);\r
9707 \r
9708                         // Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs\r
9709                         if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0)\r
9710                                 return u;\r
9711 \r
9712                         // Convert to relative\r
9713                         if (s.relative_urls)\r
9714                                 return t.documentBaseURI.toRelative(u);\r
9715 \r
9716                         // Convert to absolute\r
9717                         u = t.documentBaseURI.toAbsolute(u, s.remove_script_host);\r
9718 \r
9719                         return u;\r
9720                 },\r
9721 \r
9722                 addVisual : function(e) {\r
9723                         var t = this, s = t.settings;\r
9724 \r
9725                         e = e || t.getBody();\r
9726 \r
9727                         if (!is(t.hasVisual))\r
9728                                 t.hasVisual = s.visual;\r
9729 \r
9730                         each(t.dom.select('table,a', e), function(e) {\r
9731                                 var v;\r
9732 \r
9733                                 switch (e.nodeName) {\r
9734                                         case 'TABLE':\r
9735                                                 v = t.dom.getAttrib(e, 'border');\r
9736 \r
9737                                                 if (!v || v == '0') {\r
9738                                                         if (t.hasVisual)\r
9739                                                                 t.dom.addClass(e, s.visual_table_class);\r
9740                                                         else\r
9741                                                                 t.dom.removeClass(e, s.visual_table_class);\r
9742                                                 }\r
9743 \r
9744                                                 return;\r
9745 \r
9746                                         case 'A':\r
9747                                                 v = t.dom.getAttrib(e, 'name');\r
9748 \r
9749                                                 if (v) {\r
9750                                                         if (t.hasVisual)\r
9751                                                                 t.dom.addClass(e, 'mceItemAnchor');\r
9752                                                         else\r
9753                                                                 t.dom.removeClass(e, 'mceItemAnchor');\r
9754                                                 }\r
9755 \r
9756                                                 return;\r
9757                                 }\r
9758                         });\r
9759 \r
9760                         t.onVisualAid.dispatch(t, e, t.hasVisual);\r
9761                 },\r
9762 \r
9763                 remove : function() {\r
9764                         var t = this, e = t.getContainer();\r
9765 \r
9766                         t.removed = 1; // Cancels post remove event execution\r
9767                         t.hide();\r
9768 \r
9769                         t.execCallback('remove_instance_callback', t);\r
9770                         t.onRemove.dispatch(t);\r
9771 \r
9772                         // Clear all execCommand listeners this is required to avoid errors if the editor was removed inside another command\r
9773                         t.onExecCommand.listeners = [];\r
9774 \r
9775                         EditorManager.remove(t);\r
9776                         DOM.remove(e);\r
9777                 },\r
9778 \r
9779                 destroy : function(s) {\r
9780                         var t = this;\r
9781 \r
9782                         // One time is enough\r
9783                         if (t.destroyed)\r
9784                                 return;\r
9785 \r
9786                         if (!s) {\r
9787                                 tinymce.removeUnload(t.destroy);\r
9788                                 tinyMCE.onBeforeUnload.remove(t._beforeUnload);\r
9789 \r
9790                                 // Manual destroy\r
9791                                 if (t.theme && t.theme.destroy)\r
9792                                         t.theme.destroy();\r
9793 \r
9794                                 // Destroy controls, selection and dom\r
9795                                 t.controlManager.destroy();\r
9796                                 t.selection.destroy();\r
9797                                 t.dom.destroy();\r
9798 \r
9799                                 // Remove all events\r
9800 \r
9801                                 // Don't clear the window or document if content editable\r
9802                                 // is enabled since other instances might still be present\r
9803                                 if (!t.settings.content_editable) {\r
9804                                         Event.clear(t.getWin());\r
9805                                         Event.clear(t.getDoc());\r
9806                                 }\r
9807 \r
9808                                 Event.clear(t.getBody());\r
9809                                 Event.clear(t.formElement);\r
9810                         }\r
9811 \r
9812                         if (t.formElement) {\r
9813                                 t.formElement.submit = t.formElement._mceOldSubmit;\r
9814                                 t.formElement._mceOldSubmit = null;\r
9815                         }\r
9816 \r
9817                         t.contentAreaContainer = t.formElement = t.container = t.settings.content_element = t.bodyElement = t.contentDocument = t.contentWindow = null;\r
9818 \r
9819                         if (t.selection)\r
9820                                 t.selection = t.selection.win = t.selection.dom = t.selection.dom.doc = null;\r
9821 \r
9822                         t.destroyed = 1;\r
9823                 },\r
9824 \r
9825                 // Internal functions\r
9826 \r
9827                 _addEvents : function() {\r
9828                         // 'focus', 'blur', 'dblclick', 'beforedeactivate', submit, reset\r
9829                         var t = this, i, s = t.settings, lo = {\r
9830                                 mouseup : 'onMouseUp',\r
9831                                 mousedown : 'onMouseDown',\r
9832                                 click : 'onClick',\r
9833                                 keyup : 'onKeyUp',\r
9834                                 keydown : 'onKeyDown',\r
9835                                 keypress : 'onKeyPress',\r
9836                                 submit : 'onSubmit',\r
9837                                 reset : 'onReset',\r
9838                                 contextmenu : 'onContextMenu',\r
9839                                 dblclick : 'onDblClick',\r
9840                                 paste : 'onPaste' // Doesn't work in all browsers yet\r
9841                         };\r
9842 \r
9843                         function eventHandler(e, o) {\r
9844                                 var ty = e.type;\r
9845 \r
9846                                 // Don't fire events when it's removed\r
9847                                 if (t.removed)\r
9848                                         return;\r
9849 \r
9850                                 // Generic event handler\r
9851                                 if (t.onEvent.dispatch(t, e, o) !== false) {\r
9852                                         // Specific event handler\r
9853                                         t[lo[e.fakeType || e.type]].dispatch(t, e, o);\r
9854                                 }\r
9855                         };\r
9856 \r
9857                         // Add DOM events\r
9858                         each(lo, function(v, k) {\r
9859                                 switch (k) {\r
9860                                         case 'contextmenu':\r
9861                                                 if (tinymce.isOpera) {\r
9862                                                         // Fake contextmenu on Opera\r
9863                                                         Event.add(t.getBody(), 'mousedown', function(e) {\r
9864                                                                 if (e.ctrlKey) {\r
9865                                                                         e.fakeType = 'contextmenu';\r
9866                                                                         eventHandler(e);\r
9867                                                                 }\r
9868                                                         });\r
9869                                                 } else\r
9870                                                         Event.add(t.getBody(), k, eventHandler);\r
9871                                                 break;\r
9872 \r
9873                                         case 'paste':\r
9874                                                 Event.add(t.getBody(), k, function(e) {\r
9875                                                         eventHandler(e);\r
9876                                                 });\r
9877                                                 break;\r
9878 \r
9879                                         case 'submit':\r
9880                                         case 'reset':\r
9881                                                 Event.add(t.getElement().form || DOM.getParent(t.id, 'form'), k, eventHandler);\r
9882                                                 break;\r
9883 \r
9884                                         default:\r
9885                                                 Event.add(s.content_editable ? t.getBody() : t.getDoc(), k, eventHandler);\r
9886                                 }\r
9887                         });\r
9888 \r
9889                         Event.add(s.content_editable ? t.getBody() : (isGecko ? t.getDoc() : t.getWin()), 'focus', function(e) {\r
9890                                 t.focus(true);\r
9891                         });\r
9892 \r
9893 \r
9894                         // Fixes bug where a specified document_base_uri could result in broken images\r
9895                         // This will also fix drag drop of images in Gecko\r
9896                         if (tinymce.isGecko) {\r
9897                                 // Convert all images to absolute URLs\r
9898 /*                              t.onSetContent.add(function(ed, o) {\r
9899                                         each(ed.dom.select('img'), function(e) {\r
9900                                                 var v;\r
9901 \r
9902                                                 if (v = e.getAttribute('mce_src'))\r
9903                                                         e.src = t.documentBaseURI.toAbsolute(v);\r
9904                                         })\r
9905                                 });*/\r
9906 \r
9907                                 Event.add(t.getDoc(), 'DOMNodeInserted', function(e) {\r
9908                                         var v;\r
9909 \r
9910                                         e = e.target;\r
9911 \r
9912                                         if (e.nodeType === 1 && e.nodeName === 'IMG' && (v = e.getAttribute('mce_src')))\r
9913                                                 e.src = t.documentBaseURI.toAbsolute(v);\r
9914                                 });\r
9915                         }\r
9916 \r
9917                         // Set various midas options in Gecko\r
9918                         if (isGecko) {\r
9919                                 function setOpts() {\r
9920                                         var t = this, d = t.getDoc(), s = t.settings;\r
9921 \r
9922                                         if (isGecko && !s.readonly) {\r
9923                                                 if (t._isHidden()) {\r
9924                                                         try {\r
9925                                                                 if (!s.content_editable)\r
9926                                                                         d.designMode = 'On';\r
9927                                                         } catch (ex) {\r
9928                                                                 // Fails if it's hidden\r
9929                                                         }\r
9930                                                 }\r
9931 \r
9932                                                 try {\r
9933                                                         // Try new Gecko method\r
9934                                                         d.execCommand("styleWithCSS", 0, false);\r
9935                                                 } catch (ex) {\r
9936                                                         // Use old method\r
9937                                                         if (!t._isHidden())\r
9938                                                                 try {d.execCommand("useCSS", 0, true);} catch (ex) {}\r
9939                                                 }\r
9940 \r
9941                                                 if (!s.table_inline_editing)\r
9942                                                         try {d.execCommand('enableInlineTableEditing', false, false);} catch (ex) {}\r
9943 \r
9944                                                 if (!s.object_resizing)\r
9945                                                         try {d.execCommand('enableObjectResizing', false, false);} catch (ex) {}\r
9946                                         }\r
9947                                 };\r
9948 \r
9949                                 t.onBeforeExecCommand.add(setOpts);\r
9950                                 t.onMouseDown.add(setOpts);\r
9951                         }\r
9952 \r
9953                         // Add node change handlers\r
9954                         t.onMouseUp.add(t.nodeChanged);\r
9955                         t.onClick.add(t.nodeChanged);\r
9956                         t.onKeyUp.add(function(ed, e) {\r
9957                                 var c = e.keyCode;\r
9958 \r
9959                                 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)\r
9960                                         t.nodeChanged();\r
9961                         });\r
9962 \r
9963                         // Add reset handler\r
9964                         t.onReset.add(function() {\r
9965                                 t.setContent(t.startContent, {format : 'raw'});\r
9966                         });\r
9967 \r
9968                         // Add shortcuts\r
9969                         if (s.custom_shortcuts) {\r
9970                                 if (s.custom_undo_redo_keyboard_shortcuts) {\r
9971                                         t.addShortcut('ctrl+z', t.getLang('undo_desc'), 'Undo');\r
9972                                         t.addShortcut('ctrl+y', t.getLang('redo_desc'), 'Redo');\r
9973                                 }\r
9974 \r
9975                                 // Add default shortcuts for gecko\r
9976                                 if (isGecko) {\r
9977                                         t.addShortcut('ctrl+b', t.getLang('bold_desc'), 'Bold');\r
9978                                         t.addShortcut('ctrl+i', t.getLang('italic_desc'), 'Italic');\r
9979                                         t.addShortcut('ctrl+u', t.getLang('underline_desc'), 'Underline');\r
9980                                 }\r
9981 \r
9982                                 // BlockFormat shortcuts keys\r
9983                                 for (i=1; i<=6; i++)\r
9984                                         t.addShortcut('ctrl+' + i, '', ['FormatBlock', false, '<h' + i + '>']);\r
9985 \r
9986                                 t.addShortcut('ctrl+7', '', ['FormatBlock', false, '<p>']);\r
9987                                 t.addShortcut('ctrl+8', '', ['FormatBlock', false, '<div>']);\r
9988                                 t.addShortcut('ctrl+9', '', ['FormatBlock', false, '<address>']);\r
9989 \r
9990                                 function find(e) {\r
9991                                         var v = null;\r
9992 \r
9993                                         if (!e.altKey && !e.ctrlKey && !e.metaKey)\r
9994                                                 return v;\r
9995 \r
9996                                         each(t.shortcuts, function(o) {\r
9997                                                 if (tinymce.isMac && o.ctrl != e.metaKey)\r
9998                                                         return;\r
9999                                                 else if (!tinymce.isMac && o.ctrl != e.ctrlKey)\r
10000                                                         return;\r
10001 \r
10002                                                 if (o.alt != e.altKey)\r
10003                                                         return;\r
10004 \r
10005                                                 if (o.shift != e.shiftKey)\r
10006                                                         return;\r
10007 \r
10008                                                 if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) {\r
10009                                                         v = o;\r
10010                                                         return false;\r
10011                                                 }\r
10012                                         });\r
10013 \r
10014                                         return v;\r
10015                                 };\r
10016 \r
10017                                 t.onKeyUp.add(function(ed, e) {\r
10018                                         var o = find(e);\r
10019 \r
10020                                         if (o)\r
10021                                                 return Event.cancel(e);\r
10022                                 });\r
10023 \r
10024                                 t.onKeyPress.add(function(ed, e) {\r
10025                                         var o = find(e);\r
10026 \r
10027                                         if (o)\r
10028                                                 return Event.cancel(e);\r
10029                                 });\r
10030 \r
10031                                 t.onKeyDown.add(function(ed, e) {\r
10032                                         var o = find(e);\r
10033 \r
10034                                         if (o) {\r
10035                                                 o.func.call(o.scope);\r
10036                                                 return Event.cancel(e);\r
10037                                         }\r
10038                                 });\r
10039                         }\r
10040 \r
10041                         if (tinymce.isIE) {\r
10042                                 // Fix so resize will only update the width and height attributes not the styles of an image\r
10043                                 // It will also block mceItemNoResize items\r
10044                                 Event.add(t.getDoc(), 'controlselect', function(e) {\r
10045                                         var re = t.resizeInfo, cb;\r
10046 \r
10047                                         e = e.target;\r
10048 \r
10049                                         // Don't do this action for non image elements\r
10050                                         if (e.nodeName !== 'IMG')\r
10051                                                 return;\r
10052 \r
10053                                         if (re)\r
10054                                                 Event.remove(re.node, re.ev, re.cb);\r
10055 \r
10056                                         if (!t.dom.hasClass(e, 'mceItemNoResize')) {\r
10057                                                 ev = 'resizeend';\r
10058                                                 cb = Event.add(e, ev, function(e) {\r
10059                                                         var v;\r
10060 \r
10061                                                         e = e.target;\r
10062 \r
10063                                                         if (v = t.dom.getStyle(e, 'width')) {\r
10064                                                                 t.dom.setAttrib(e, 'width', v.replace(/[^0-9%]+/g, ''));\r
10065                                                                 t.dom.setStyle(e, 'width', '');\r
10066                                                         }\r
10067 \r
10068                                                         if (v = t.dom.getStyle(e, 'height')) {\r
10069                                                                 t.dom.setAttrib(e, 'height', v.replace(/[^0-9%]+/g, ''));\r
10070                                                                 t.dom.setStyle(e, 'height', '');\r
10071                                                         }\r
10072                                                 });\r
10073                                         } else {\r
10074                                                 ev = 'resizestart';\r
10075                                                 cb = Event.add(e, 'resizestart', Event.cancel, Event);\r
10076                                         }\r
10077 \r
10078                                         re = t.resizeInfo = {\r
10079                                                 node : e,\r
10080                                                 ev : ev,\r
10081                                                 cb : cb\r
10082                                         };\r
10083                                 });\r
10084 \r
10085                                 t.onKeyDown.add(function(ed, e) {\r
10086                                         switch (e.keyCode) {\r
10087                                                 case 8:\r
10088                                                         // Fix IE control + backspace browser bug\r
10089                                                         if (t.selection.getRng().item) {\r
10090                                                                 t.selection.getRng().item(0).removeNode();\r
10091                                                                 return Event.cancel(e);\r
10092                                                         }\r
10093                                         }\r
10094                                 });\r
10095 \r
10096                                 /*if (t.dom.boxModel) {\r
10097                                         t.getBody().style.height = '100%';\r
10098 \r
10099                                         Event.add(t.getWin(), 'resize', function(e) {\r
10100                                                 var docElm = t.getDoc().documentElement;\r
10101 \r
10102                                                 docElm.style.height = (docElm.offsetHeight - 10) + 'px';\r
10103                                         });\r
10104                                 }*/\r
10105                         }\r
10106 \r
10107                         if (tinymce.isOpera) {\r
10108                                 t.onClick.add(function(ed, e) {\r
10109                                         Event.prevent(e);\r
10110                                 });\r
10111                         }\r
10112 \r
10113                         // Add custom undo/redo handlers\r
10114                         if (s.custom_undo_redo) {\r
10115                                 function addUndo() {\r
10116                                         t.undoManager.typing = 0;\r
10117                                         t.undoManager.add();\r
10118                                 };\r
10119 \r
10120                                 // Add undo level on editor blur\r
10121                                 if (tinymce.isIE) {\r
10122                                         Event.add(t.getWin(), 'blur', function(e) {\r
10123                                                 var n;\r
10124 \r
10125                                                 // Check added for fullscreen bug\r
10126                                                 if (t.selection) {\r
10127                                                         n = t.selection.getNode();\r
10128 \r
10129                                                         // Add undo level is selection was lost to another document\r
10130                                                         if (!t.removed && n.ownerDocument && n.ownerDocument != t.getDoc())\r
10131                                                                 addUndo();\r
10132                                                 }\r
10133                                         });\r
10134                                 } else {\r
10135                                         Event.add(t.getDoc(), 'blur', function() {\r
10136                                                 if (t.selection && !t.removed)\r
10137                                                         addUndo();\r
10138                                         });\r
10139                                 }\r
10140 \r
10141                                 t.onMouseDown.add(addUndo);\r
10142 \r
10143                                 t.onKeyUp.add(function(ed, e) {\r
10144                                         if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.ctrlKey) {\r
10145                                                 t.undoManager.typing = 0;\r
10146                                                 t.undoManager.add();\r
10147                                         }\r
10148                                 });\r
10149 \r
10150                                 t.onKeyDown.add(function(ed, e) {\r
10151                                         // Is caracter positon keys\r
10152                                         if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45) {\r
10153                                                 if (t.undoManager.typing) {\r
10154                                                         t.undoManager.add();\r
10155                                                         t.undoManager.typing = 0;\r
10156                                                 }\r
10157 \r
10158                                                 return;\r
10159                                         }\r
10160 \r
10161                                         if (!t.undoManager.typing) {\r
10162                                                 t.undoManager.add();\r
10163                                                 t.undoManager.typing = 1;\r
10164                                         }\r
10165                                 });\r
10166                         }\r
10167                 },\r
10168 \r
10169                 _convertInlineElements : function() {\r
10170                         var t = this, s = t.settings, dom = t.dom, v, e, na, st, sp;\r
10171 \r
10172                         function convert(ed, o) {\r
10173                                 if (!s.inline_styles)\r
10174                                         return;\r
10175 \r
10176                                 if (o.get) {\r
10177                                         each(t.dom.select('table,u,strike', o.node), function(n) {\r
10178                                                 switch (n.nodeName) {\r
10179                                                         case 'TABLE':\r
10180                                                                 if (v = dom.getAttrib(n, 'height')) {\r
10181                                                                         dom.setStyle(n, 'height', v);\r
10182                                                                         dom.setAttrib(n, 'height', '');\r
10183                                                                 }\r
10184                                                                 break;\r
10185 \r
10186                                                         case 'U':\r
10187                                                         case 'STRIKE':\r
10188                                                                 //sp = dom.create('span', {style : dom.getAttrib(n, 'style')});\r
10189                                                                 n.style.textDecoration = n.nodeName == 'U' ? 'underline' : 'line-through';\r
10190                                                                 dom.setAttrib(n, 'mce_style', '');\r
10191                                                                 dom.setAttrib(n, 'mce_name', 'span');\r
10192                                                                 break;\r
10193                                                 }\r
10194                                         });\r
10195                                 } else if (o.set) {\r
10196                                         each(t.dom.select('table,span', o.node).reverse(), function(n) {\r
10197                                                 if (n.nodeName == 'TABLE') {\r
10198                                                         if (v = dom.getStyle(n, 'height'))\r
10199                                                                 dom.setAttrib(n, 'height', v.replace(/[^0-9%]+/g, ''));\r
10200                                                 } else {\r
10201                                                         // Convert spans to elements\r
10202                                                         if (n.style.textDecoration == 'underline')\r
10203                                                                 na = 'u';\r
10204                                                         else if (n.style.textDecoration == 'line-through')\r
10205                                                                 na = 'strike';\r
10206                                                         else\r
10207                                                                 na = '';\r
10208 \r
10209                                                         if (na) {\r
10210                                                                 n.style.textDecoration = '';\r
10211                                                                 dom.setAttrib(n, 'mce_style', '');\r
10212 \r
10213                                                                 e = dom.create(na, {\r
10214                                                                         style : dom.getAttrib(n, 'style')\r
10215                                                                 });\r
10216 \r
10217                                                                 dom.replace(e, n, 1);\r
10218                                                         }\r
10219                                                 }\r
10220                                         });\r
10221                                 }\r
10222                         };\r
10223 \r
10224                         t.onPreProcess.add(convert);\r
10225 \r
10226                         if (!s.cleanup_on_startup) {\r
10227                                 t.onSetContent.add(function(ed, o) {\r
10228                                         if (o.initial)\r
10229                                                 convert(t, {node : t.getBody(), set : 1});\r
10230                                 });\r
10231                         }\r
10232                 },\r
10233 \r
10234                 _convertFonts : function() {\r
10235                         var t = this, s = t.settings, dom = t.dom, fz, fzn, sl, cl;\r
10236 \r
10237                         // No need\r
10238                         if (!s.inline_styles)\r
10239                                 return;\r
10240 \r
10241                         // Font pt values and font size names\r
10242                         fz = [8, 10, 12, 14, 18, 24, 36];\r
10243                         fzn = ['xx-small', 'x-small','small','medium','large','x-large', 'xx-large'];\r
10244 \r
10245                         if (sl = s.font_size_style_values)\r
10246                                 sl = explode(sl);\r
10247 \r
10248                         if (cl = s.font_size_classes)\r
10249                                 cl = explode(cl);\r
10250 \r
10251                         function process(no) {\r
10252                                 var n, sp, nl, x;\r
10253 \r
10254                                 // Keep unit tests happy\r
10255                                 if (!s.inline_styles)\r
10256                                         return;\r
10257 \r
10258                                 nl = t.dom.select('font', no);\r
10259                                 for (x = nl.length - 1; x >= 0; x--) {\r
10260                                         n = nl[x];\r
10261 \r
10262                                         sp = dom.create('span', {\r
10263                                                 style : dom.getAttrib(n, 'style'),\r
10264                                                 'class' : dom.getAttrib(n, 'class')\r
10265                                         });\r
10266 \r
10267                                         dom.setStyles(sp, {\r
10268                                                 fontFamily : dom.getAttrib(n, 'face'),\r
10269                                                 color : dom.getAttrib(n, 'color'),\r
10270                                                 backgroundColor : n.style.backgroundColor\r
10271                                         });\r
10272 \r
10273                                         if (n.size) {\r
10274                                                 if (sl)\r
10275                                                         dom.setStyle(sp, 'fontSize', sl[parseInt(n.size) - 1]);\r
10276                                                 else\r
10277                                                         dom.setAttrib(sp, 'class', cl[parseInt(n.size) - 1]);\r
10278                                         }\r
10279 \r
10280                                         dom.setAttrib(sp, 'mce_style', '');\r
10281                                         dom.replace(sp, n, 1);\r
10282                                 }\r
10283                         };\r
10284 \r
10285                         // Run on cleanup\r
10286                         t.onPreProcess.add(function(ed, o) {\r
10287                                 if (o.get)\r
10288                                         process(o.node);\r
10289                         });\r
10290 \r
10291                         t.onSetContent.add(function(ed, o) {\r
10292                                 if (o.initial)\r
10293                                         process(o.node);\r
10294                         });\r
10295                 },\r
10296 \r
10297                 _isHidden : function() {\r
10298                         var s;\r
10299 \r
10300                         if (!isGecko)\r
10301                                 return 0;\r
10302 \r
10303                         // Weird, wheres that cursor selection?\r
10304                         s = this.selection.getSel();\r
10305                         return (!s || !s.rangeCount || s.rangeCount == 0);\r
10306                 },\r
10307 \r
10308                 // Fix for bug #1867292\r
10309                 _fixNesting : function(s) {\r
10310                         var d = [], i;\r
10311 \r
10312                         s = s.replace(/<(\/)?([^\s>]+)[^>]*?>/g, function(a, b, c) {\r
10313                                 var e;\r
10314 \r
10315                                 // Handle end element\r
10316                                 if (b === '/') {\r
10317                                         if (!d.length)\r
10318                                                 return '';\r
10319 \r
10320                                         if (c !== d[d.length - 1].tag) {\r
10321                                                 for (i=d.length - 1; i>=0; i--) {\r
10322                                                         if (d[i].tag === c) {\r
10323                                                                 d[i].close = 1;\r
10324                                                                 break;\r
10325                                                         }\r
10326                                                 }\r
10327 \r
10328                                                 return '';\r
10329                                         } else {\r
10330                                                 d.pop();\r
10331 \r
10332                                                 if (d.length && d[d.length - 1].close) {\r
10333                                                         a = a + '</' + d[d.length - 1].tag + '>';\r
10334                                                         d.pop();\r
10335                                                 }\r
10336                                         }\r
10337                                 } else {\r
10338                                         // Ignore these\r
10339                                         if (/^(br|hr|input|meta|img|link|param)$/i.test(c))\r
10340                                                 return a;\r
10341 \r
10342                                         // Ignore closed ones\r
10343                                         if (/\/>$/.test(a))\r
10344                                                 return a;\r
10345 \r
10346                                         d.push({tag : c}); // Push start element\r
10347                                 }\r
10348 \r
10349                                 return a;\r
10350                         });\r
10351 \r
10352                         // End all open tags\r
10353                         for (i=d.length - 1; i>=0; i--)\r
10354                                 s += '</' + d[i].tag + '>';\r
10355 \r
10356                         return s;\r
10357                 }\r
10358 \r
10359                 });\r
10360 })(tinymce);\r
10361 (function(tinymce) {\r
10362         var each = tinymce.each, isIE = tinymce.isIE, isGecko = tinymce.isGecko, isOpera = tinymce.isOpera, isWebKit = tinymce.isWebKit;\r
10363 \r
10364         tinymce.create('tinymce.EditorCommands', {\r
10365                 EditorCommands : function(ed) {\r
10366                         this.editor = ed;\r
10367                 },\r
10368 \r
10369                 execCommand : function(cmd, ui, val) {\r
10370                         var t = this, ed = t.editor, f;\r
10371 \r
10372                         switch (cmd) {\r
10373                                 // Ignore these\r
10374                                 case 'mceResetDesignMode':\r
10375                                 case 'mceBeginUndoLevel':\r
10376                                         return true;\r
10377 \r
10378                                 // Ignore these\r
10379                                 case 'unlink':\r
10380                                         t.UnLink();\r
10381                                         return true;\r
10382 \r
10383                                 // Bundle these together\r
10384                                 case 'JustifyLeft':\r
10385                                 case 'JustifyCenter':\r
10386                                 case 'JustifyRight':\r
10387                                 case 'JustifyFull':\r
10388                                         t.mceJustify(cmd, cmd.substring(7).toLowerCase());\r
10389                                         return true;\r
10390 \r
10391                                 default:\r
10392                                         f = this[cmd];\r
10393 \r
10394                                         if (f) {\r
10395                                                 f.call(this, ui, val);\r
10396                                                 return true;\r
10397                                         }\r
10398                         }\r
10399 \r
10400                         return false;\r
10401                 },\r
10402 \r
10403                 Indent : function() {\r
10404                         var ed = this.editor, d = ed.dom, s = ed.selection, e, iv, iu;\r
10405 \r
10406                         // Setup indent level\r
10407                         iv = ed.settings.indentation;\r
10408                         iu = /[a-z%]+$/i.exec(iv);\r
10409                         iv = parseInt(iv);\r
10410 \r
10411                         if (ed.settings.inline_styles && (!this.queryStateInsertUnorderedList() && !this.queryStateInsertOrderedList())) {\r
10412                                 each(s.getSelectedBlocks(), function(e) {\r
10413                                         d.setStyle(e, 'paddingLeft', (parseInt(e.style.paddingLeft || 0) + iv) + iu);\r
10414                                 });\r
10415 \r
10416                                 return;\r
10417                         }\r
10418 \r
10419                         ed.getDoc().execCommand('Indent', false, null);\r
10420 \r
10421                         if (isIE) {\r
10422                                 d.getParent(s.getNode(), function(n) {\r
10423                                         if (n.nodeName == 'BLOCKQUOTE') {\r
10424                                                 n.dir = n.style.cssText = '';\r
10425                                         }\r
10426                                 });\r
10427                         }\r
10428                 },\r
10429 \r
10430                 Outdent : function() {\r
10431                         var ed = this.editor, d = ed.dom, s = ed.selection, e, v, iv, iu;\r
10432 \r
10433                         // Setup indent level\r
10434                         iv = ed.settings.indentation;\r
10435                         iu = /[a-z%]+$/i.exec(iv);\r
10436                         iv = parseInt(iv);\r
10437 \r
10438                         if (ed.settings.inline_styles && (!this.queryStateInsertUnorderedList() && !this.queryStateInsertOrderedList())) {\r
10439                                 each(s.getSelectedBlocks(), function(e) {\r
10440                                         v = Math.max(0, parseInt(e.style.paddingLeft || 0) - iv);\r
10441                                         d.setStyle(e, 'paddingLeft', v ? v + iu : '');\r
10442                                 });\r
10443 \r
10444                                 return;\r
10445                         }\r
10446 \r
10447                         ed.getDoc().execCommand('Outdent', false, null);\r
10448                 },\r
10449 \r
10450 /*\r
10451                 mceSetAttribute : function(u, v) {\r
10452                         var ed = this.editor, d = ed.dom, e;\r
10453 \r
10454                         if (e = d.getParent(ed.selection.getNode(), d.isBlock))\r
10455                                 d.setAttrib(e, v.name, v.value);\r
10456                 },\r
10457 */\r
10458                 mceSetContent : function(u, v) {\r
10459                         this.editor.setContent(v);\r
10460                 },\r
10461 \r
10462                 mceToggleVisualAid : function() {\r
10463                         var ed = this.editor;\r
10464 \r
10465                         ed.hasVisual = !ed.hasVisual;\r
10466                         ed.addVisual();\r
10467                 },\r
10468 \r
10469                 mceReplaceContent : function(u, v) {\r
10470                         var s = this.editor.selection;\r
10471 \r
10472                         s.setContent(v.replace(/\{\$selection\}/g, s.getContent({format : 'text'})));\r
10473                 },\r
10474 \r
10475                 mceInsertLink : function(u, v) {\r
10476                         var ed = this.editor, s = ed.selection, e = ed.dom.getParent(s.getNode(), 'a');\r
10477 \r
10478                         if (tinymce.is(v, 'string'))\r
10479                                 v = {href : v};\r
10480 \r
10481                         function set(e) {\r
10482                                 each(v, function(v, k) {\r
10483                                         ed.dom.setAttrib(e, k, v);\r
10484                                 });\r
10485                         };\r
10486 \r
10487                         if (!e) {\r
10488                                 ed.execCommand('CreateLink', false, 'javascript:mctmp(0);');\r
10489                                 each(ed.dom.select('a[href=javascript:mctmp(0);]'), function(e) {\r
10490                                         set(e);\r
10491                                 });\r
10492                         } else {\r
10493                                 if (v.href)\r
10494                                         set(e);\r
10495                                 else\r
10496                                         ed.dom.remove(e, 1);\r
10497                         }\r
10498                 },\r
10499 \r
10500                 UnLink : function() {\r
10501                         var ed = this.editor, s = ed.selection;\r
10502 \r
10503                         if (s.isCollapsed())\r
10504                                 s.select(s.getNode());\r
10505 \r
10506                         ed.getDoc().execCommand('unlink', false, null);\r
10507                         s.collapse(0);\r
10508                 },\r
10509 \r
10510                 FontName : function(u, v) {\r
10511                         var t = this, ed = t.editor, s = ed.selection, e;\r
10512 \r
10513                         if (!v) {\r
10514                                 if (s.isCollapsed())\r
10515                                         s.select(s.getNode());\r
10516                         } else {\r
10517                                 if (ed.settings.convert_fonts_to_spans)\r
10518                                         t._applyInlineStyle('span', {style : {fontFamily : v}});\r
10519                                 else\r
10520                                         ed.getDoc().execCommand('FontName', false, v);\r
10521                         }\r
10522                 },\r
10523 \r
10524                 FontSize : function(u, v) {\r
10525                         var ed = this.editor, s = ed.settings, fc, fs;\r
10526 \r
10527                         // Use style options instead\r
10528                         if (s.convert_fonts_to_spans && v >= 1 && v <= 7) {\r
10529                                 fs = tinymce.explode(s.font_size_style_values);\r
10530                                 fc = tinymce.explode(s.font_size_classes);\r
10531 \r
10532                                 if (fc)\r
10533                                         v = fc[v - 1] || v;\r
10534                                 else\r
10535                                         v = fs[v - 1] || v;\r
10536                         }\r
10537 \r
10538                         if (v >= 1 && v <= 7)\r
10539                                 ed.getDoc().execCommand('FontSize', false, v);\r
10540                         else\r
10541                                 this._applyInlineStyle('span', {style : {fontSize : v}});\r
10542                 },\r
10543 \r
10544                 queryCommandValue : function(c) {\r
10545                         var f = this['queryValue' + c];\r
10546 \r
10547                         if (f)\r
10548                                 return f.call(this, c);\r
10549 \r
10550                         return false;\r
10551                 },\r
10552 \r
10553                 queryCommandState : function(cmd) {\r
10554                         var f;\r
10555 \r
10556                         switch (cmd) {\r
10557                                 // Bundle these together\r
10558                                 case 'JustifyLeft':\r
10559                                 case 'JustifyCenter':\r
10560                                 case 'JustifyRight':\r
10561                                 case 'JustifyFull':\r
10562                                         return this.queryStateJustify(cmd, cmd.substring(7).toLowerCase());\r
10563 \r
10564                                 default:\r
10565                                         if (f = this['queryState' + cmd])\r
10566                                                 return f.call(this, cmd);\r
10567                         }\r
10568 \r
10569                         return -1;\r
10570                 },\r
10571 \r
10572                 _queryState : function(c) {\r
10573                         try {\r
10574                                 return this.editor.getDoc().queryCommandState(c);\r
10575                         } catch (ex) {\r
10576                                 // Ignore exception\r
10577                         }\r
10578                 },\r
10579 \r
10580                 _queryVal : function(c) {\r
10581                         try {\r
10582                                 return this.editor.getDoc().queryCommandValue(c);\r
10583                         } catch (ex) {\r
10584                                 // Ignore exception\r
10585                         }\r
10586                 },\r
10587 \r
10588                 queryValueFontSize : function() {\r
10589                         var ed = this.editor, v = 0, p;\r
10590 \r
10591                         if (p = ed.dom.getParent(ed.selection.getNode(), 'span'))\r
10592                                 v = p.style.fontSize;\r
10593 \r
10594                         if (!v && (isOpera || isWebKit)) {\r
10595                                 if (p = ed.dom.getParent(ed.selection.getNode(), 'font'))\r
10596                                         v = p.size;\r
10597 \r
10598                                 return v;\r
10599                         }\r
10600 \r
10601                         return v || this._queryVal('FontSize');\r
10602                 },\r
10603 \r
10604                 queryValueFontName : function() {\r
10605                         var ed = this.editor, v = 0, p;\r
10606 \r
10607                         if (p = ed.dom.getParent(ed.selection.getNode(), 'font'))\r
10608                                 v = p.face;\r
10609 \r
10610                         if (p = ed.dom.getParent(ed.selection.getNode(), 'span'))\r
10611                                 v = p.style.fontFamily.replace(/, /g, ',').replace(/[\'\"]/g, '').toLowerCase();\r
10612 \r
10613                         if (!v)\r
10614                                 v = this._queryVal('FontName');\r
10615 \r
10616                         return v;\r
10617                 },\r
10618 \r
10619                 mceJustify : function(c, v) {\r
10620                         var ed = this.editor, se = ed.selection, n = se.getNode(), nn = n.nodeName, bl, nb, dom = ed.dom, rm;\r
10621 \r
10622                         if (ed.settings.inline_styles && this.queryStateJustify(c, v))\r
10623                                 rm = 1;\r
10624 \r
10625                         bl = dom.getParent(n, ed.dom.isBlock);\r
10626 \r
10627                         if (nn == 'IMG') {\r
10628                                 if (v == 'full')\r
10629                                         return;\r
10630 \r
10631                                 if (rm) {\r
10632                                         if (v == 'center')\r
10633                                                 dom.setStyle(bl || n.parentNode, 'textAlign', '');\r
10634 \r
10635                                         dom.setStyle(n, 'float', '');\r
10636                                         this.mceRepaint();\r
10637                                         return;\r
10638                                 }\r
10639 \r
10640                                 if (v == 'center') {\r
10641                                         // Do not change table elements\r
10642                                         if (bl && /^(TD|TH)$/.test(bl.nodeName))\r
10643                                                 bl = 0;\r
10644 \r
10645                                         if (!bl || bl.childNodes.length > 1) {\r
10646                                                 nb = dom.create('p');\r
10647                                                 nb.appendChild(n.cloneNode(false));\r
10648 \r
10649                                                 if (bl)\r
10650                                                         dom.insertAfter(nb, bl);\r
10651                                                 else\r
10652                                                         dom.insertAfter(nb, n);\r
10653 \r
10654                                                 dom.remove(n);\r
10655                                                 n = nb.firstChild;\r
10656                                                 bl = nb;\r
10657                                         }\r
10658 \r
10659                                         dom.setStyle(bl, 'textAlign', v);\r
10660                                         dom.setStyle(n, 'float', '');\r
10661                                 } else {\r
10662                                         dom.setStyle(n, 'float', v);\r
10663                                         dom.setStyle(bl || n.parentNode, 'textAlign', '');\r
10664                                 }\r
10665 \r
10666                                 this.mceRepaint();\r
10667                                 return;\r
10668                         }\r
10669 \r
10670                         // Handle the alignment outselfs, less quirks in all browsers\r
10671                         if (ed.settings.inline_styles && ed.settings.forced_root_block) {\r
10672                                 if (rm)\r
10673                                         v = '';\r
10674 \r
10675                                 each(se.getSelectedBlocks(dom.getParent(se.getStart(), dom.isBlock), dom.getParent(se.getEnd(), dom.isBlock)), function(e) {\r
10676                                         dom.setAttrib(e, 'align', '');\r
10677                                         dom.setStyle(e, 'textAlign', v == 'full' ? 'justify' : v);\r
10678                                 });\r
10679 \r
10680                                 return;\r
10681                         } else if (!rm)\r
10682                                 ed.getDoc().execCommand(c, false, null);\r
10683 \r
10684                         if (ed.settings.inline_styles) {\r
10685                                 if (rm) {\r
10686                                         dom.getParent(ed.selection.getNode(), function(n) {\r
10687                                                 if (n.style && n.style.textAlign)\r
10688                                                         dom.setStyle(n, 'textAlign', '');\r
10689                                         });\r
10690 \r
10691                                         return;\r
10692                                 }\r
10693 \r
10694                                 each(dom.select('*'), function(n) {\r
10695                                         var v = n.align;\r
10696 \r
10697                                         if (v) {\r
10698                                                 if (v == 'full')\r
10699                                                         v = 'justify';\r
10700 \r
10701                                                 dom.setStyle(n, 'textAlign', v);\r
10702                                                 dom.setAttrib(n, 'align', '');\r
10703                                         }\r
10704                                 });\r
10705                         }\r
10706                 },\r
10707 \r
10708                 mceSetCSSClass : function(u, v) {\r
10709                         this.mceSetStyleInfo(0, {command : 'setattrib', name : 'class', value : v});\r
10710                 },\r
10711 \r
10712                 getSelectedElement : function() {\r
10713                         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;\r
10714 \r
10715                         if (se.isCollapsed() || r.item)\r
10716                                 return se.getNode();\r
10717 \r
10718                         // Setup regexp\r
10719                         re = ed.settings.merge_styles_invalid_parents;\r
10720                         if (tinymce.is(re, 'string'))\r
10721                                 re = new RegExp(re, 'i');\r
10722 \r
10723                         if (isIE) {\r
10724                                 r1 = r.duplicate();\r
10725                                 r1.collapse(true);\r
10726                                 sc = r1.parentElement();\r
10727 \r
10728                                 r2 = r.duplicate();\r
10729                                 r2.collapse(false);\r
10730                                 ec = r2.parentElement();\r
10731 \r
10732                                 if (sc != ec) {\r
10733                                         r1.move('character', 1);\r
10734                                         sc = r1.parentElement();\r
10735                                 }\r
10736 \r
10737                                 if (sc == ec) {\r
10738                                         r1 = r.duplicate();\r
10739                                         r1.moveToElementText(sc);\r
10740 \r
10741                                         if (r1.compareEndPoints('StartToStart', r) == 0 && r1.compareEndPoints('EndToEnd', r) == 0)\r
10742                                                 return re && re.test(sc.nodeName) ? null : sc;\r
10743                                 }\r
10744                         } else {\r
10745                                 function getParent(n) {\r
10746                                         return dom.getParent(n, '*');\r
10747                                 };\r
10748 \r
10749                                 sc = r.startContainer;\r
10750                                 ec = r.endContainer;\r
10751                                 so = r.startOffset;\r
10752                                 eo = r.endOffset;\r
10753 \r
10754                                 if (!r.collapsed) {\r
10755                                         if (sc == ec) {\r
10756                                                 if (so - eo < 2) {\r
10757                                                         if (sc.hasChildNodes()) {\r
10758                                                                 sp = sc.childNodes[so];\r
10759                                                                 return re && re.test(sp.nodeName) ? null : sp;\r
10760                                                         }\r
10761                                                 }\r
10762                                         }\r
10763                                 }\r
10764 \r
10765                                 if (sc.nodeType != 3 || ec.nodeType != 3)\r
10766                                         return null;\r
10767 \r
10768                                 if (so == 0) {\r
10769                                         sp = getParent(sc);\r
10770 \r
10771                                         if (sp && sp.firstChild != sc)\r
10772                                                 sp = null;\r
10773                                 }\r
10774 \r
10775                                 if (so == sc.nodeValue.length) {\r
10776                                         e = sc.nextSibling;\r
10777 \r
10778                                         if (e && e.nodeType == 1)\r
10779                                                 sp = sc.nextSibling;\r
10780                                 }\r
10781 \r
10782                                 if (eo == 0) {\r
10783                                         e = ec.previousSibling;\r
10784 \r
10785                                         if (e && e.nodeType == 1)\r
10786                                                 ep = e;\r
10787                                 }\r
10788 \r
10789                                 if (eo == ec.nodeValue.length) {\r
10790                                         ep = getParent(ec);\r
10791 \r
10792                                         if (ep && ep.lastChild != ec)\r
10793                                                 ep = null;\r
10794                                 }\r
10795 \r
10796                                 // Same element\r
10797                                 if (sp == ep)\r
10798                                         return re && sp && re.test(sp.nodeName) ? null : sp;\r
10799                         }\r
10800 \r
10801                         return null;\r
10802                 },\r
10803 \r
10804                 mceSetStyleInfo : function(u, v) {\r
10805                         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;\r
10806 \r
10807                         function set(n, e) {\r
10808                                 if (n.nodeType == 1) {\r
10809                                         switch (v.command) {\r
10810                                                 case 'setattrib':\r
10811                                                         return dom.setAttrib(n, v.name, v.value);\r
10812 \r
10813                                                 case 'setstyle':\r
10814                                                         return dom.setStyle(n, v.name, v.value);\r
10815 \r
10816                                                 case 'removeformat':\r
10817                                                         return dom.setAttrib(n, 'class', '');\r
10818                                         }\r
10819                                 }\r
10820                         };\r
10821 \r
10822                         // Setup regexp\r
10823                         re = ed.settings.merge_styles_invalid_parents;\r
10824                         if (tinymce.is(re, 'string'))\r
10825                                 re = new RegExp(re, 'i');\r
10826 \r
10827                         // Set style info on selected element\r
10828                         if ((e = t.getSelectedElement()) && !ed.settings.force_span_wrappers)\r
10829                                 set(e, 1);\r
10830                         else {\r
10831                                 // Generate wrappers and set styles on them\r
10832                                 d.execCommand('FontName', false, '__');\r
10833                                 each(dom.select('span,font'), function(n) {\r
10834                                         var sp, e;\r
10835 \r
10836                                         if (dom.getAttrib(n, 'face') == '__' || n.style.fontFamily === '__') {\r
10837                                                 sp = dom.create(nn, {mce_new : '1'});\r
10838 \r
10839                                                 set(sp);\r
10840 \r
10841                                                 each (n.childNodes, function(n) {\r
10842                                                         sp.appendChild(n.cloneNode(true));\r
10843                                                 });\r
10844 \r
10845                                                 dom.replace(sp, n);\r
10846                                         }\r
10847                                 });\r
10848                         }\r
10849 \r
10850                         // Remove wrappers inside new ones\r
10851                         each(dom.select(nn).reverse(), function(n) {\r
10852                                 var p = n.parentNode;\r
10853 \r
10854                                 // Check if it's an old span in a new wrapper\r
10855                                 if (!dom.getAttrib(n, 'mce_new')) {\r
10856                                         // Find new wrapper\r
10857                                         p = dom.getParent(n, '*[mce_new]');\r
10858 \r
10859                                         if (p)\r
10860                                                 dom.remove(n, 1);\r
10861                                 }\r
10862                         });\r
10863 \r
10864                         // Merge wrappers with parent wrappers\r
10865                         each(dom.select(nn).reverse(), function(n) {\r
10866                                 var p = n.parentNode;\r
10867 \r
10868                                 if (!p || !dom.getAttrib(n, 'mce_new'))\r
10869                                         return;\r
10870 \r
10871                                 if (ed.settings.force_span_wrappers && p.nodeName != 'SPAN')\r
10872                                         return;\r
10873 \r
10874                                 // Has parent of the same type and only child\r
10875                                 if (p.nodeName == nn.toUpperCase() && p.childNodes.length == 1)\r
10876                                         return dom.remove(p, 1);\r
10877 \r
10878                                 // Has parent that is more suitable to have the class and only child\r
10879                                 if (n.nodeType == 1 && (!re || !re.test(p.nodeName)) && p.childNodes.length == 1) {\r
10880                                         set(p); // Set style info on parent instead\r
10881                                         dom.setAttrib(n, 'class', '');\r
10882                                 }\r
10883                         });\r
10884 \r
10885                         // Remove empty wrappers\r
10886                         each(dom.select(nn).reverse(), function(n) {\r
10887                                 if (dom.getAttrib(n, 'mce_new') || (dom.getAttribs(n).length <= 1 && n.className === '')) {\r
10888                                         if (!dom.getAttrib(n, 'class') && !dom.getAttrib(n, 'style'))\r
10889                                                 return dom.remove(n, 1);\r
10890 \r
10891                                         dom.setAttrib(n, 'mce_new', ''); // Remove mce_new marker\r
10892                                 }\r
10893                         });\r
10894 \r
10895                         s.moveToBookmark(b);\r
10896                 },\r
10897 \r
10898                 queryStateJustify : function(c, v) {\r
10899                         var ed = this.editor, n = ed.selection.getNode(), dom = ed.dom;\r
10900 \r
10901                         if (n && n.nodeName == 'IMG') {\r
10902                                 if (dom.getStyle(n, 'float') == v)\r
10903                                         return 1;\r
10904 \r
10905                                 return n.parentNode.style.textAlign == v;\r
10906                         }\r
10907 \r
10908                         n = dom.getParent(ed.selection.getStart(), function(n) {\r
10909                                 return n.nodeType == 1 && n.style.textAlign;\r
10910                         });\r
10911 \r
10912                         if (v == 'full')\r
10913                                 v = 'justify';\r
10914 \r
10915                         if (ed.settings.inline_styles)\r
10916                                 return (n && n.style.textAlign == v);\r
10917 \r
10918                         return this._queryState(c);\r
10919                 },\r
10920 \r
10921                 ForeColor : function(ui, v) {\r
10922                         var ed = this.editor;\r
10923 \r
10924                         if (ed.settings.convert_fonts_to_spans) {\r
10925                                 this._applyInlineStyle('span', {style : {color : v}});\r
10926                                 return;\r
10927                         } else\r
10928                                 ed.getDoc().execCommand('ForeColor', false, v);\r
10929                 },\r
10930 \r
10931                 HiliteColor : function(ui, val) {\r
10932                         var t = this, ed = t.editor, d = ed.getDoc();\r
10933 \r
10934                         if (ed.settings.convert_fonts_to_spans) {\r
10935                                 this._applyInlineStyle('span', {style : {backgroundColor : val}});\r
10936                                 return;\r
10937                         }\r
10938 \r
10939                         function set(s) {\r
10940                                 if (!isGecko)\r
10941                                         return;\r
10942 \r
10943                                 try {\r
10944                                         // Try new Gecko method\r
10945                                         d.execCommand("styleWithCSS", 0, s);\r
10946                                 } catch (ex) {\r
10947                                         // Use old\r
10948                                         d.execCommand("useCSS", 0, !s);\r
10949                                 }\r
10950                         };\r
10951 \r
10952                         if (isGecko || isOpera) {\r
10953                                 set(true);\r
10954                                 d.execCommand('hilitecolor', false, val);\r
10955                                 set(false);\r
10956                         } else\r
10957                                 d.execCommand('BackColor', false, val);\r
10958                 },\r
10959 \r
10960                 FormatBlock : function(ui, val) {\r
10961                         var t = this, ed = t.editor, s = ed.selection, dom = ed.dom, bl, nb, b;\r
10962 \r
10963                         function isBlock(n) {\r
10964                                 return /^(P|DIV|H[1-6]|ADDRESS|BLOCKQUOTE|PRE)$/.test(n.nodeName);\r
10965                         };\r
10966 \r
10967                         bl = dom.getParent(s.getNode(), function(n) {\r
10968                                 return isBlock(n);\r
10969                         });\r
10970 \r
10971                         // IE has an issue where it removes the parent div if you change format on the paragrah in <div><p>Content</p></div>\r
10972                         // FF and Opera doesn't change parent DIV elements if you switch format\r
10973                         if (bl) {\r
10974                                 if ((isIE && isBlock(bl.parentNode)) || bl.nodeName == 'DIV') {\r
10975                                         // Rename block element\r
10976                                         nb = ed.dom.create(val);\r
10977 \r
10978                                         each(dom.getAttribs(bl), function(v) {\r
10979                                                 dom.setAttrib(nb, v.nodeName, dom.getAttrib(bl, v.nodeName));\r
10980                                         });\r
10981 \r
10982                                         b = s.getBookmark();\r
10983                                         dom.replace(nb, bl, 1);\r
10984                                         s.moveToBookmark(b);\r
10985                                         ed.nodeChanged();\r
10986                                         return;\r
10987                                 }\r
10988                         }\r
10989 \r
10990                         val = ed.settings.forced_root_block ? (val || '<p>') : val;\r
10991 \r
10992                         if (val.indexOf('<') == -1)\r
10993                                 val = '<' + val + '>';\r
10994 \r
10995                         if (tinymce.isGecko)\r
10996                                 val = val.replace(/<(div|blockquote|code|dt|dd|dl|samp)>/gi, '$1');\r
10997 \r
10998                         ed.getDoc().execCommand('FormatBlock', false, val);\r
10999                 },\r
11000 \r
11001                 mceCleanup : function() {\r
11002                         var ed = this.editor, s = ed.selection, b = s.getBookmark();\r
11003                         ed.setContent(ed.getContent());\r
11004                         s.moveToBookmark(b);\r
11005                 },\r
11006 \r
11007                 mceRemoveNode : function(ui, val) {\r
11008                         var ed = this.editor, s = ed.selection, b, n = val || s.getNode();\r
11009 \r
11010                         // Make sure that the body node isn't removed\r
11011                         if (n == ed.getBody())\r
11012                                 return;\r
11013 \r
11014                         b = s.getBookmark();\r
11015                         ed.dom.remove(n, 1);\r
11016                         s.moveToBookmark(b);\r
11017                         ed.nodeChanged();\r
11018                 },\r
11019 \r
11020                 mceSelectNodeDepth : function(ui, val) {\r
11021                         var ed = this.editor, s = ed.selection, c = 0;\r
11022 \r
11023                         ed.dom.getParent(s.getNode(), function(n) {\r
11024                                 if (n.nodeType == 1 && c++ == val) {\r
11025                                         s.select(n);\r
11026                                         ed.nodeChanged();\r
11027                                         return false;\r
11028                                 }\r
11029                         }, ed.getBody());\r
11030                 },\r
11031 \r
11032                 mceSelectNode : function(u, v) {\r
11033                         this.editor.selection.select(v);\r
11034                 },\r
11035 \r
11036                 mceInsertContent : function(ui, val) {\r
11037                         this.editor.selection.setContent(val);\r
11038                 },\r
11039 \r
11040                 mceInsertRawHTML : function(ui, val) {\r
11041                         var ed = this.editor;\r
11042 \r
11043                         ed.selection.setContent('tiny_mce_marker');\r
11044                         ed.setContent(ed.getContent().replace(/tiny_mce_marker/g, val));\r
11045                 },\r
11046 \r
11047                 mceRepaint : function() {\r
11048                         var s, b, e = this.editor;\r
11049 \r
11050                         if (tinymce.isGecko) {\r
11051                                 try {\r
11052                                         s = e.selection;\r
11053                                         b = s.getBookmark(true);\r
11054 \r
11055                                         if (s.getSel())\r
11056                                                 s.getSel().selectAllChildren(e.getBody());\r
11057 \r
11058                                         s.collapse(true);\r
11059                                         s.moveToBookmark(b);\r
11060                                 } catch (ex) {\r
11061                                         // Ignore\r
11062                                 }\r
11063                         }\r
11064                 },\r
11065 \r
11066                 queryStateUnderline : function() {\r
11067                         var ed = this.editor, n = ed.selection.getNode();\r
11068 \r
11069                         if (n && n.nodeName == 'A')\r
11070                                 return false;\r
11071 \r
11072                         return this._queryState('Underline');\r
11073                 },\r
11074 \r
11075                 queryStateOutdent : function() {\r
11076                         var ed = this.editor, n;\r
11077 \r
11078                         if (ed.settings.inline_styles) {\r
11079                                 if ((n = ed.dom.getParent(ed.selection.getStart(), ed.dom.isBlock)) && parseInt(n.style.paddingLeft) > 0)\r
11080                                         return true;\r
11081 \r
11082                                 if ((n = ed.dom.getParent(ed.selection.getEnd(), ed.dom.isBlock)) && parseInt(n.style.paddingLeft) > 0)\r
11083                                         return true;\r
11084                         }\r
11085 \r
11086                         return this.queryStateInsertUnorderedList() || this.queryStateInsertOrderedList() || (!ed.settings.inline_styles && !!ed.dom.getParent(ed.selection.getNode(), 'BLOCKQUOTE'));\r
11087                 },\r
11088 \r
11089                 queryStateInsertUnorderedList : function() {\r
11090                         return this.editor.dom.getParent(this.editor.selection.getNode(), 'UL');\r
11091                 },\r
11092 \r
11093                 queryStateInsertOrderedList : function() {\r
11094                         return this.editor.dom.getParent(this.editor.selection.getNode(), 'OL');\r
11095                 },\r
11096 \r
11097                 queryStatemceBlockQuote : function() {\r
11098                         return !!this.editor.dom.getParent(this.editor.selection.getStart(), function(n) {return n.nodeName === 'BLOCKQUOTE';});\r
11099                 },\r
11100 \r
11101                 _applyInlineStyle : function(na, at, op) {\r
11102                         var t = this, ed = t.editor, dom = ed.dom, bm, lo = {}, kh, found;\r
11103 \r
11104                         na = na.toUpperCase();\r
11105 \r
11106                         if (op && op.check_classes && at['class'])\r
11107                                 op.check_classes.push(at['class']);\r
11108 \r
11109                         function removeEmpty() {\r
11110                                 each(dom.select(na).reverse(), function(n) {\r
11111                                         var c = 0;\r
11112 \r
11113                                         // Check if there is any attributes\r
11114                                         each(dom.getAttribs(n), function(an) {\r
11115                                                 if (an.nodeName.substring(0, 1) != '_' && dom.getAttrib(n, an.nodeName) != '') {\r
11116                                                         //console.log(dom.getOuterHTML(n), dom.getAttrib(n, an.nodeName));\r
11117                                                         c++;\r
11118                                                 }\r
11119                                         });\r
11120 \r
11121                                         // No attributes then remove the element and keep the children\r
11122                                         if (c == 0)\r
11123                                                 dom.remove(n, 1);\r
11124                                 });\r
11125                         };\r
11126 \r
11127                         function replaceFonts() {\r
11128                                 var bm;\r
11129 \r
11130                                 each(dom.select('span,font'), function(n) {\r
11131                                         if (n.style.fontFamily == 'mceinline' || n.face == 'mceinline') {\r
11132                                                 if (!bm)\r
11133                                                         bm = ed.selection.getBookmark();\r
11134 \r
11135                                                 at._mce_new = '1';\r
11136                                                 dom.replace(dom.create(na, at), n, 1);\r
11137                                         }\r
11138                                 });\r
11139 \r
11140                                 // Remove redundant elements\r
11141                                 each(dom.select(na + '[_mce_new]'), function(n) {\r
11142                                         function removeStyle(n) {\r
11143                                                 if (n.nodeType == 1) {\r
11144                                                         each(at.style, function(v, k) {\r
11145                                                                 dom.setStyle(n, k, '');\r
11146                                                         });\r
11147 \r
11148                                                         // Remove spans with the same class or marked classes\r
11149                                                         if (at['class'] && n.className && op) {\r
11150                                                                 each(op.check_classes, function(c) {\r
11151                                                                         if (dom.hasClass(n, c))\r
11152                                                                                 dom.removeClass(n, c);\r
11153                                                                 });\r
11154                                                         }\r
11155                                                 }\r
11156                                         };\r
11157 \r
11158                                         // Remove specified style information from child elements\r
11159                                         each(dom.select(na, n), removeStyle);\r
11160 \r
11161                                         // Remove the specified style information on parent if current node is only child (IE)\r
11162                                         if (n.parentNode && n.parentNode.nodeType == 1 && n.parentNode.childNodes.length == 1)\r
11163                                                 removeStyle(n.parentNode);\r
11164 \r
11165                                         // Remove the child elements style info if a parent already has it\r
11166                                         dom.getParent(n.parentNode, function(pn) {\r
11167                                                 if (pn.nodeType == 1) {\r
11168                                                         if (at.style) {\r
11169                                                                 each(at.style, function(v, k) {\r
11170                                                                         var sv;\r
11171 \r
11172                                                                         if (!lo[k] && (sv = dom.getStyle(pn, k))) {\r
11173                                                                                 if (sv === v)\r
11174                                                                                         dom.setStyle(n, k, '');\r
11175 \r
11176                                                                                 lo[k] = 1;\r
11177                                                                         }\r
11178                                                                 });\r
11179                                                         }\r
11180 \r
11181                                                         // Remove spans with the same class or marked classes\r
11182                                                         if (at['class'] && pn.className && op) {\r
11183                                                                 each(op.check_classes, function(c) {\r
11184                                                                         if (dom.hasClass(pn, c))\r
11185                                                                                 dom.removeClass(n, c);\r
11186                                                                 });\r
11187                                                         }\r
11188                                                 }\r
11189 \r
11190                                                 return false;\r
11191                                         });\r
11192 \r
11193                                         n.removeAttribute('_mce_new');\r
11194                                 });\r
11195 \r
11196                                 removeEmpty();\r
11197                                 ed.selection.moveToBookmark(bm);\r
11198 \r
11199                                 return !!bm;\r
11200                         };\r
11201 \r
11202                         // Create inline elements\r
11203                         ed.focus();\r
11204                         ed.getDoc().execCommand('FontName', false, 'mceinline');\r
11205                         replaceFonts();\r
11206 \r
11207                         if (kh = t._applyInlineStyle.keyhandler) {\r
11208                                 ed.onKeyUp.remove(kh);\r
11209                                 ed.onKeyPress.remove(kh);\r
11210                                 ed.onKeyDown.remove(kh);\r
11211                                 ed.onSetContent.remove(t._applyInlineStyle.chandler);\r
11212                         }\r
11213 \r
11214                         if (ed.selection.isCollapsed()) {\r
11215                                 // IE will format the current word so this code can't be executed on that browser\r
11216                                 if (!isIE) {\r
11217                                         each(dom.getParents(ed.selection.getNode(), 'span'), function(n) {\r
11218                                                 each(at.style, function(v, k) {\r
11219                                                         var kv;\r
11220 \r
11221                                                         if (kv = dom.getStyle(n, k)) {\r
11222                                                                 if (kv == v) {\r
11223                                                                         dom.setStyle(n, k, '');\r
11224                                                                         found = 2;\r
11225                                                                         return false;\r
11226                                                                 }\r
11227 \r
11228                                                                 found = 1;\r
11229                                                                 return false;\r
11230                                                         }\r
11231                                                 });\r
11232 \r
11233                                                 if (found)\r
11234                                                         return false;\r
11235                                         });\r
11236 \r
11237                                         if (found == 2) {\r
11238                                                 bm = ed.selection.getBookmark();\r
11239 \r
11240                                                 removeEmpty();\r
11241 \r
11242                                                 ed.selection.moveToBookmark(bm);\r
11243 \r
11244                                                 // Node change needs to be detached since the onselect event\r
11245                                                 // for the select box will run the onclick handler after onselect call. Todo: Add a nicer fix!\r
11246                                                 window.setTimeout(function() {\r
11247                                                         ed.nodeChanged();\r
11248                                                 }, 1);\r
11249 \r
11250                                                 return;\r
11251                                         }\r
11252                                 }\r
11253 \r
11254                                 // Start collecting styles\r
11255                                 t._pendingStyles = tinymce.extend(t._pendingStyles || {}, at.style);\r
11256 \r
11257                                 t._applyInlineStyle.chandler = ed.onSetContent.add(function() {\r
11258                                         delete t._pendingStyles;\r
11259                                 });\r
11260 \r
11261                                 t._applyInlineStyle.keyhandler = kh = function(e) {\r
11262                                         // Use pending styles\r
11263                                         if (t._pendingStyles) {\r
11264                                                 at.style = t._pendingStyles;\r
11265                                                 delete t._pendingStyles;\r
11266                                         }\r
11267 \r
11268                                         if (replaceFonts()) {\r
11269                                                 ed.onKeyDown.remove(t._applyInlineStyle.keyhandler);\r
11270                                                 ed.onKeyPress.remove(t._applyInlineStyle.keyhandler);\r
11271                                         }\r
11272 \r
11273                                         if (e.type == 'keyup')\r
11274                                                 ed.onKeyUp.remove(t._applyInlineStyle.keyhandler);\r
11275                                 };\r
11276 \r
11277                                 ed.onKeyDown.add(kh);\r
11278                                 ed.onKeyPress.add(kh);\r
11279                                 ed.onKeyUp.add(kh);\r
11280                         } else\r
11281                                 t._pendingStyles = 0;\r
11282                 }\r
11283         });\r
11284 })(tinymce);(function(tinymce) {\r
11285         tinymce.create('tinymce.UndoManager', {\r
11286                 index : 0,\r
11287                 data : null,\r
11288                 typing : 0,\r
11289 \r
11290                 UndoManager : function(ed) {\r
11291                         var t = this, Dispatcher = tinymce.util.Dispatcher;\r
11292 \r
11293                         t.editor = ed;\r
11294                         t.data = [];\r
11295                         t.onAdd = new Dispatcher(this);\r
11296                         t.onUndo = new Dispatcher(this);\r
11297                         t.onRedo = new Dispatcher(this);\r
11298                 },\r
11299 \r
11300                 add : function(l) {\r
11301                         var t = this, i, ed = t.editor, b, s = ed.settings, la;\r
11302 \r
11303                         l = l || {};\r
11304                         l.content = l.content || ed.getContent({format : 'raw', no_events : 1});\r
11305 \r
11306                         // Add undo level if needed\r
11307                         l.content = l.content.replace(/^\s*|\s*$/g, '');\r
11308                         la = t.data[t.index > 0 && (t.index == 0 || t.index == t.data.length) ? t.index - 1 : t.index];\r
11309                         if (!l.initial && la && l.content == la.content)\r
11310                                 return null;\r
11311 \r
11312                         // Time to compress\r
11313                         if (s.custom_undo_redo_levels) {\r
11314                                 if (t.data.length > s.custom_undo_redo_levels) {\r
11315                                         for (i = 0; i < t.data.length - 1; i++)\r
11316                                                 t.data[i] = t.data[i + 1];\r
11317 \r
11318                                         t.data.length--;\r
11319                                         t.index = t.data.length;\r
11320                                 }\r
11321                         }\r
11322 \r
11323                         if (s.custom_undo_redo_restore_selection && !l.initial)\r
11324                                 l.bookmark = b = l.bookmark || ed.selection.getBookmark();\r
11325 \r
11326                         if (t.index < t.data.length)\r
11327                                 t.index++;\r
11328 \r
11329                         // Only initial marked undo levels should be allowed as first item\r
11330                         // This to workaround a bug with Firefox and the blur event\r
11331                         if (t.data.length === 0 && !l.initial)\r
11332                                 return null;\r
11333 \r
11334                         // Add level\r
11335                         t.data.length = t.index + 1;\r
11336                         t.data[t.index++] = l;\r
11337 \r
11338                         if (l.initial)\r
11339                                 t.index = 0;\r
11340 \r
11341                         // Set initial bookmark use first real undo level\r
11342                         if (t.data.length == 2 && t.data[0].initial)\r
11343                                 t.data[0].bookmark = b;\r
11344 \r
11345                         t.onAdd.dispatch(t, l);\r
11346                         ed.isNotDirty = 0;\r
11347 \r
11348                         //console.dir(t.data);\r
11349 \r
11350                         return l;\r
11351                 },\r
11352 \r
11353                 undo : function() {\r
11354                         var t = this, ed = t.editor, l = l, i;\r
11355 \r
11356                         if (t.typing) {\r
11357                                 t.add();\r
11358                                 t.typing = 0;\r
11359                         }\r
11360 \r
11361                         if (t.index > 0) {\r
11362                                 // If undo on last index then take snapshot\r
11363                                 if (t.index == t.data.length && t.index > 1) {\r
11364                                         i = t.index;\r
11365                                         t.typing = 0;\r
11366 \r
11367                                         if (!t.add())\r
11368                                                 t.index = i;\r
11369 \r
11370                                         --t.index;\r
11371                                 }\r
11372 \r
11373                                 l = t.data[--t.index];\r
11374                                 ed.setContent(l.content, {format : 'raw'});\r
11375                                 ed.selection.moveToBookmark(l.bookmark);\r
11376 \r
11377                                 t.onUndo.dispatch(t, l);\r
11378                         }\r
11379 \r
11380                         return l;\r
11381                 },\r
11382 \r
11383                 redo : function() {\r
11384                         var t = this, ed = t.editor, l = null;\r
11385 \r
11386                         if (t.index < t.data.length - 1) {\r
11387                                 l = t.data[++t.index];\r
11388                                 ed.setContent(l.content, {format : 'raw'});\r
11389                                 ed.selection.moveToBookmark(l.bookmark);\r
11390 \r
11391                                 t.onRedo.dispatch(t, l);\r
11392                         }\r
11393 \r
11394                         return l;\r
11395                 },\r
11396 \r
11397                 clear : function() {\r
11398                         var t = this;\r
11399 \r
11400                         t.data = [];\r
11401                         t.index = 0;\r
11402                         t.typing = 0;\r
11403                         t.add({initial : true});\r
11404                 },\r
11405 \r
11406                 hasUndo : function() {\r
11407                         return this.index != 0 || this.typing;\r
11408                 },\r
11409 \r
11410                 hasRedo : function() {\r
11411                         return this.index < this.data.length - 1;\r
11412                 }\r
11413 \r
11414                 });\r
11415 })(tinymce);\r
11416 (function(tinymce) {\r
11417         // Shorten names\r
11418         var Event, isIE, isGecko, isOpera, each, extend;\r
11419 \r
11420         Event = tinymce.dom.Event;\r
11421         isIE = tinymce.isIE;\r
11422         isGecko = tinymce.isGecko;\r
11423         isOpera = tinymce.isOpera;\r
11424         each = tinymce.each;\r
11425         extend = tinymce.extend;\r
11426 \r
11427         function isEmpty(n) {\r
11428                 n = n.innerHTML;\r
11429                 n = n.replace(/<\w+ .*?mce_\w+\"?=.*?>/gi, '-'); // Keep tags with mce_ attribs\r
11430                 n = n.replace(/<(img|hr|table)/gi, '-'); // Keep these convert them to - chars\r
11431                 n = n.replace(/<[^>]+>/g, ''); // Remove all tags\r
11432 \r
11433                 return n.replace(/[ \t\r\n]+/g, '') == '';\r
11434         };\r
11435 \r
11436         tinymce.create('tinymce.ForceBlocks', {\r
11437                 ForceBlocks : function(ed) {\r
11438                         var t = this, s = ed.settings, elm;\r
11439 \r
11440                         t.editor = ed;\r
11441                         t.dom = ed.dom;\r
11442                         elm = (s.forced_root_block || 'p').toLowerCase();\r
11443                         s.element = elm.toUpperCase();\r
11444 \r
11445                         ed.onPreInit.add(t.setup, t);\r
11446 \r
11447                         t.reOpera = new RegExp('(\\u00a0|&#160;|&nbsp;)<\/' + elm + '>', 'gi');\r
11448                         t.rePadd = new RegExp('<p( )([^>]+)><\\\/p>|<p( )([^>]+)\\\/>|<p( )([^>]+)>\\s+<\\\/p>|<p><\\\/p>|<p\\\/>|<p>\\s+<\\\/p>'.replace(/p/g, elm), 'gi');\r
11449                         t.reNbsp2BR1 = new RegExp('<p( )([^>]+)>[\\s\\u00a0]+<\\\/p>|<p>[\\s\\u00a0]+<\\\/p>'.replace(/p/g, elm), 'gi');\r
11450                         t.reNbsp2BR2 = new RegExp('<%p()([^>]+)>(&nbsp;|&#160;)<\\\/%p>|<%p>(&nbsp;|&#160;)<\\\/%p>'.replace(/%p/g, elm), 'gi');\r
11451                         t.reBR2Nbsp = new RegExp('<p( )([^>]+)>\\s*<br \\\/>\\s*<\\\/p>|<p>\\s*<br \\\/>\\s*<\\\/p>'.replace(/p/g, elm), 'gi');\r
11452 \r
11453                         function padd(ed, o) {\r
11454                                 if (isOpera)\r
11455                                         o.content = o.content.replace(t.reOpera, '</' + elm + '>');\r
11456 \r
11457                                 o.content = o.content.replace(t.rePadd, '<' + elm + '$1$2$3$4$5$6>\u00a0</' + elm + '>');\r
11458 \r
11459                                 if (!isIE && !isOpera && o.set) {\r
11460                                         // Use &nbsp; instead of BR in padded paragraphs\r
11461                                         o.content = o.content.replace(t.reNbsp2BR1, '<' + elm + '$1$2><br /></' + elm + '>');\r
11462                                         o.content = o.content.replace(t.reNbsp2BR2, '<' + elm + '$1$2><br /></' + elm + '>');\r
11463                                 } else\r
11464                                         o.content = o.content.replace(t.reBR2Nbsp, '<' + elm + '$1$2>\u00a0</' + elm + '>');\r
11465                         };\r
11466 \r
11467                         ed.onBeforeSetContent.add(padd);\r
11468                         ed.onPostProcess.add(padd);\r
11469 \r
11470                         if (s.forced_root_block) {\r
11471                                 ed.onInit.add(t.forceRoots, t);\r
11472                                 ed.onSetContent.add(t.forceRoots, t);\r
11473                                 ed.onBeforeGetContent.add(t.forceRoots, t);\r
11474                         }\r
11475                 },\r
11476 \r
11477                 setup : function() {\r
11478                         var t = this, ed = t.editor, s = ed.settings;\r
11479 \r
11480                         // Force root blocks when typing and when getting output\r
11481                         if (s.forced_root_block) {\r
11482                                 ed.onKeyUp.add(t.forceRoots, t);\r
11483                                 ed.onPreProcess.add(t.forceRoots, t);\r
11484                         }\r
11485 \r
11486                         if (s.force_br_newlines) {\r
11487                                 // Force IE to produce BRs on enter\r
11488                                 if (isIE) {\r
11489                                         ed.onKeyPress.add(function(ed, e) {\r
11490                                                 var n, s = ed.selection;\r
11491 \r
11492                                                 if (e.keyCode == 13 && s.getNode().nodeName != 'LI') {\r
11493                                                         s.setContent('<br id="__" /> ', {format : 'raw'});\r
11494                                                         n = ed.dom.get('__');\r
11495                                                         n.removeAttribute('id');\r
11496                                                         s.select(n);\r
11497                                                         s.collapse();\r
11498                                                         return Event.cancel(e);\r
11499                                                 }\r
11500                                         });\r
11501                                 }\r
11502 \r
11503                                 return;\r
11504                         }\r
11505 \r
11506                         if (!isIE && s.force_p_newlines) {\r
11507 /*                              ed.onPreProcess.add(function(ed, o) {\r
11508                                         each(ed.dom.select('br', o.node), function(n) {\r
11509                                                 var p = n.parentNode;\r
11510 \r
11511                                                 // Replace <p><br /></p> with <p>&nbsp;</p>\r
11512                                                 if (p && p.nodeName == 'p' && (p.childNodes.length == 1 || p.lastChild == n)) {\r
11513                                                         p.replaceChild(ed.getDoc().createTextNode('\u00a0'), n);\r
11514                                                 }\r
11515                                         });\r
11516                                 });*/\r
11517 \r
11518                                 ed.onKeyPress.add(function(ed, e) {\r
11519                                         if (e.keyCode == 13 && !e.shiftKey) {\r
11520                                                 if (!t.insertPara(e))\r
11521                                                         Event.cancel(e);\r
11522                                         }\r
11523                                 });\r
11524 \r
11525                                 if (isGecko) {\r
11526                                         ed.onKeyDown.add(function(ed, e) {\r
11527                                                 if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey)\r
11528                                                         t.backspaceDelete(e, e.keyCode == 8);\r
11529                                         });\r
11530                                 }\r
11531                         }\r
11532 \r
11533                         function ren(rn, na) {\r
11534                                 var ne = ed.dom.create(na);\r
11535 \r
11536                                 each(rn.attributes, function(a) {\r
11537                                         if (a.specified && a.nodeValue)\r
11538                                                 ne.setAttribute(a.nodeName.toLowerCase(), a.nodeValue);\r
11539                                 });\r
11540 \r
11541                                 each(rn.childNodes, function(n) {\r
11542                                         ne.appendChild(n.cloneNode(true));\r
11543                                 });\r
11544 \r
11545                                 rn.parentNode.replaceChild(ne, rn);\r
11546 \r
11547                                 return ne;\r
11548                         };\r
11549 \r
11550                         // IE specific fixes\r
11551                         if (isIE) {\r
11552                                 // Remove empty inline elements within block elements\r
11553                                 // For example: <p><strong><em></em></strong></p>\r
11554                                 ed.onPreProcess.add(function(ed, o) {\r
11555                                         each(ed.dom.select('p,h1,h2,h3,h4,h5,h6,div', o.node), function(p) {\r
11556                                                 if (isEmpty(p))\r
11557                                                         p.innerHTML = '';\r
11558                                         });\r
11559                                 });\r
11560 \r
11561                                 // Replaces IE:s auto generated paragraphs with the specified element name\r
11562                                 if (s.element != 'P') {\r
11563                                         ed.onKeyPress.add(function(ed, e) {\r
11564                                                 t.lastElm = ed.selection.getNode().nodeName;\r
11565                                         });\r
11566 \r
11567                                         ed.onKeyUp.add(function(ed, e) {\r
11568                                                 var bl, sel = ed.selection, n = sel.getNode(), b = ed.getBody();\r
11569 \r
11570                                                 if (b.childNodes.length === 1 && n.nodeName == 'P') {\r
11571                                                         n = ren(n, s.element);\r
11572                                                         sel.select(n);\r
11573                                                         sel.collapse();\r
11574                                                         ed.nodeChanged();\r
11575                                                 } else if (e.keyCode == 13 && !e.shiftKey && t.lastElm != 'P') {\r
11576                                                         bl = ed.dom.getParent(n, 'p');\r
11577 \r
11578                                                         if (bl) {\r
11579                                                                 ren(bl, s.element);\r
11580                                                                 ed.nodeChanged();\r
11581                                                         }\r
11582                                                 }\r
11583                                         });\r
11584                                 }\r
11585                         }\r
11586                 },\r
11587 \r
11588                 find : function(n, t, s) {\r
11589                         var ed = this.editor, w = ed.getDoc().createTreeWalker(n, 4, null, false), c = -1;\r
11590 \r
11591                         while (n = w.nextNode()) {\r
11592                                 c++;\r
11593 \r
11594                                 // Index by node\r
11595                                 if (t == 0 && n == s)\r
11596                                         return c;\r
11597 \r
11598                                 // Node by index\r
11599                                 if (t == 1 && c == s)\r
11600                                         return n;\r
11601                         }\r
11602 \r
11603                         return -1;\r
11604                 },\r
11605 \r
11606                 forceRoots : function(ed, e) {\r
11607                         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;\r
11608                         var nx, bl, bp, sp, le, nl = b.childNodes, i, n, eid;\r
11609 \r
11610                         // Fix for bug #1863847\r
11611                         //if (e && e.keyCode == 13)\r
11612                         //      return true;\r
11613 \r
11614                         // Wrap non blocks into blocks\r
11615                         for (i = nl.length - 1; i >= 0; i--) {\r
11616                                 nx = nl[i];\r
11617 \r
11618                                 // Is text or non block element\r
11619                                 if (nx.nodeType == 3 || (!t.dom.isBlock(nx) && nx.nodeType != 8)) {\r
11620                                         if (!bl) {\r
11621                                                 // Create new block but ignore whitespace\r
11622                                                 if (nx.nodeType != 3 || /[^\s]/g.test(nx.nodeValue)) {\r
11623                                                         // Store selection\r
11624                                                         if (si == -2 && r) {\r
11625                                                                 if (!isIE) {\r
11626                                                                         // If selection is element then mark it\r
11627                                                                         if (r.startContainer.nodeType == 1 && (n = r.startContainer.childNodes[r.startOffset]) && n.nodeType == 1) {\r
11628                                                                                 // Save the id of the selected element\r
11629                                                                                 eid = n.getAttribute("id");\r
11630                                                                                 n.setAttribute("id", "__mce");\r
11631                                                                         } else {\r
11632                                                                                 // If element is inside body, might not be the case in contentEdiable mode\r
11633                                                                                 if (ed.dom.getParent(r.startContainer, function(e) {return e === b;})) {\r
11634                                                                                         so = r.startOffset;\r
11635                                                                                         eo = r.endOffset;\r
11636                                                                                         si = t.find(b, 0, r.startContainer);\r
11637                                                                                         ei = t.find(b, 0, r.endContainer);\r
11638                                                                                 }\r
11639                                                                         }\r
11640                                                                 } else {\r
11641                                                                         tr = d.body.createTextRange();\r
11642                                                                         tr.moveToElementText(b);\r
11643                                                                         tr.collapse(1);\r
11644                                                                         bp = tr.move('character', c) * -1;\r
11645 \r
11646                                                                         tr = r.duplicate();\r
11647                                                                         tr.collapse(1);\r
11648                                                                         sp = tr.move('character', c) * -1;\r
11649 \r
11650                                                                         tr = r.duplicate();\r
11651                                                                         tr.collapse(0);\r
11652                                                                         le = (tr.move('character', c) * -1) - sp;\r
11653 \r
11654                                                                         si = sp - bp;\r
11655                                                                         ei = le;\r
11656                                                                 }\r
11657                                                         }\r
11658 \r
11659                                                         bl = ed.dom.create(ed.settings.forced_root_block);\r
11660                                                         bl.appendChild(nx.cloneNode(1));\r
11661                                                         nx.parentNode.replaceChild(bl, nx);\r
11662                                                 }\r
11663                                         } else {\r
11664                                                 if (bl.hasChildNodes())\r
11665                                                         bl.insertBefore(nx, bl.firstChild);\r
11666                                                 else\r
11667                                                         bl.appendChild(nx);\r
11668                                         }\r
11669                                 } else\r
11670                                         bl = null; // Time to create new block\r
11671                         }\r
11672 \r
11673                         // Restore selection\r
11674                         if (si != -2) {\r
11675                                 if (!isIE) {\r
11676                                         bl = b.getElementsByTagName(ed.settings.element)[0];\r
11677                                         r = d.createRange();\r
11678 \r
11679                                         // Select last location or generated block\r
11680                                         if (si != -1)\r
11681                                                 r.setStart(t.find(b, 1, si), so);\r
11682                                         else\r
11683                                                 r.setStart(bl, 0);\r
11684 \r
11685                                         // Select last location or generated block\r
11686                                         if (ei != -1)\r
11687                                                 r.setEnd(t.find(b, 1, ei), eo);\r
11688                                         else\r
11689                                                 r.setEnd(bl, 0);\r
11690 \r
11691                                         if (s) {\r
11692                                                 s.removeAllRanges();\r
11693                                                 s.addRange(r);\r
11694                                         }\r
11695                                 } else {\r
11696                                         try {\r
11697                                                 r = s.createRange();\r
11698                                                 r.moveToElementText(b);\r
11699                                                 r.collapse(1);\r
11700                                                 r.moveStart('character', si);\r
11701                                                 r.moveEnd('character', ei);\r
11702                                                 r.select();\r
11703                                         } catch (ex) {\r
11704                                                 // Ignore\r
11705                                         }\r
11706                                 }\r
11707                         } else if (!isIE && (n = ed.dom.get('__mce'))) {\r
11708                                 // Restore the id of the selected element\r
11709                                 if (eid)\r
11710                                         n.setAttribute('id', eid);\r
11711                                 else\r
11712                                         n.removeAttribute('id');\r
11713 \r
11714                                 // Move caret before selected element\r
11715                                 r = d.createRange();\r
11716                                 r.setStartBefore(n);\r
11717                                 r.setEndBefore(n);\r
11718                                 se.setRng(r);\r
11719                         }\r
11720                 },\r
11721 \r
11722                 getParentBlock : function(n) {\r
11723                         var d = this.dom;\r
11724 \r
11725                         return d.getParent(n, d.isBlock);\r
11726                 },\r
11727 \r
11728                 insertPara : function(e) {\r
11729                         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;\r
11730                         var rb, ra, dir, sn, so, en, eo, sb, eb, bn, bef, aft, sc, ec, n, vp = dom.getViewPort(ed.getWin()), y, ch, car;\r
11731 \r
11732                         // If root blocks are forced then use Operas default behavior since it's really good\r
11733 // Removed due to bug: #1853816\r
11734 //                      if (se.forced_root_block && isOpera)\r
11735 //                              return true;\r
11736 \r
11737                         // Setup before range\r
11738                         rb = d.createRange();\r
11739 \r
11740                         // If is before the first block element and in body, then move it into first block element\r
11741                         rb.setStart(s.anchorNode, s.anchorOffset);\r
11742                         rb.collapse(true);\r
11743 \r
11744                         // Setup after range\r
11745                         ra = d.createRange();\r
11746 \r
11747                         // If is before the first block element and in body, then move it into first block element\r
11748                         ra.setStart(s.focusNode, s.focusOffset);\r
11749                         ra.collapse(true);\r
11750 \r
11751                         // Setup start/end points\r
11752                         dir = rb.compareBoundaryPoints(rb.START_TO_END, ra) < 0;\r
11753                         sn = dir ? s.anchorNode : s.focusNode;\r
11754                         so = dir ? s.anchorOffset : s.focusOffset;\r
11755                         en = dir ? s.focusNode : s.anchorNode;\r
11756                         eo = dir ? s.focusOffset : s.anchorOffset;\r
11757 \r
11758                         // If selection is in empty table cell\r
11759                         if (sn === en && /^(TD|TH)$/.test(sn.nodeName)) {\r
11760                                 dom.remove(sn.firstChild); // Remove BR\r
11761 \r
11762                                 // Create two new block elements\r
11763                                 ed.dom.add(sn, se.element, null, '<br />');\r
11764                                 aft = ed.dom.add(sn, se.element, null, '<br />');\r
11765 \r
11766                                 // Move caret into the last one\r
11767                                 r = d.createRange();\r
11768                                 r.selectNodeContents(aft);\r
11769                                 r.collapse(1);\r
11770                                 ed.selection.setRng(r);\r
11771 \r
11772                                 return false;\r
11773                         }\r
11774 \r
11775                         // If the caret is in an invalid location in FF we need to move it into the first block\r
11776                         if (sn == b && en == b && b.firstChild && ed.dom.isBlock(b.firstChild)) {\r
11777                                 sn = en = sn.firstChild;\r
11778                                 so = eo = 0;\r
11779                                 rb = d.createRange();\r
11780                                 rb.setStart(sn, 0);\r
11781                                 ra = d.createRange();\r
11782                                 ra.setStart(en, 0);\r
11783                         }\r
11784 \r
11785                         // Never use body as start or end node\r
11786                         sn = sn.nodeName == "HTML" ? d.body : sn; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes\r
11787                         sn = sn.nodeName == "BODY" ? sn.firstChild : sn;\r
11788                         en = en.nodeName == "HTML" ? d.body : en; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes\r
11789                         en = en.nodeName == "BODY" ? en.firstChild : en;\r
11790 \r
11791                         // Get start and end blocks\r
11792                         sb = t.getParentBlock(sn);\r
11793                         eb = t.getParentBlock(en);\r
11794                         bn = sb ? sb.nodeName : se.element; // Get block name to create\r
11795 \r
11796                         // Return inside list use default browser behavior\r
11797                         if (t.dom.getParent(sb, 'ol,ul,pre'))\r
11798                                 return true;\r
11799 \r
11800                         // If caption or absolute layers then always generate new blocks within\r
11801                         if (sb && (sb.nodeName == 'CAPTION' || /absolute|relative|fixed/gi.test(dom.getStyle(sb, 'position', 1)))) {\r
11802                                 bn = se.element;\r
11803                                 sb = null;\r
11804                         }\r
11805 \r
11806                         // If caption or absolute layers then always generate new blocks within\r
11807                         if (eb && (eb.nodeName == 'CAPTION' || /absolute|relative|fixed/gi.test(dom.getStyle(sb, 'position', 1)))) {\r
11808                                 bn = se.element;\r
11809                                 eb = null;\r
11810                         }\r
11811 \r
11812                         // Use P instead\r
11813                         if (/(TD|TABLE|TH|CAPTION)/.test(bn) || (sb && bn == "DIV" && /left|right/gi.test(dom.getStyle(sb, 'float', 1)))) {\r
11814                                 bn = se.element;\r
11815                                 sb = eb = null;\r
11816                         }\r
11817 \r
11818                         // Setup new before and after blocks\r
11819                         bef = (sb && sb.nodeName == bn) ? sb.cloneNode(0) : ed.dom.create(bn);\r
11820                         aft = (eb && eb.nodeName == bn) ? eb.cloneNode(0) : ed.dom.create(bn);\r
11821 \r
11822                         // Remove id from after clone\r
11823                         aft.removeAttribute('id');\r
11824 \r
11825                         // Is header and cursor is at the end, then force paragraph under\r
11826                         if (/^(H[1-6])$/.test(bn) && sn.nodeValue && so == sn.nodeValue.length)\r
11827                                 aft = ed.dom.create(se.element);\r
11828 \r
11829                         // Find start chop node\r
11830                         n = sc = sn;\r
11831                         do {\r
11832                                 if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))\r
11833                                         break;\r
11834 \r
11835                                 sc = n;\r
11836                         } while ((n = n.previousSibling ? n.previousSibling : n.parentNode));\r
11837 \r
11838                         // Find end chop node\r
11839                         n = ec = en;\r
11840                         do {\r
11841                                 if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))\r
11842                                         break;\r
11843 \r
11844                                 ec = n;\r
11845                         } while ((n = n.nextSibling ? n.nextSibling : n.parentNode));\r
11846 \r
11847                         // Place first chop part into before block element\r
11848                         if (sc.nodeName == bn)\r
11849                                 rb.setStart(sc, 0);\r
11850                         else\r
11851                                 rb.setStartBefore(sc);\r
11852 \r
11853                         rb.setEnd(sn, so);\r
11854                         bef.appendChild(rb.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari\r
11855 \r
11856                         // Place secnd chop part within new block element\r
11857                         try {\r
11858                                 ra.setEndAfter(ec);\r
11859                         } catch(ex) {\r
11860                                 //console.debug(s.focusNode, s.focusOffset);\r
11861                         }\r
11862 \r
11863                         ra.setStart(en, eo);\r
11864                         aft.appendChild(ra.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari\r
11865 \r
11866                         // Create range around everything\r
11867                         r = d.createRange();\r
11868                         if (!sc.previousSibling && sc.parentNode.nodeName == bn) {\r
11869                                 r.setStartBefore(sc.parentNode);\r
11870                         } else {\r
11871                                 if (rb.startContainer.nodeName == bn && rb.startOffset == 0)\r
11872                                         r.setStartBefore(rb.startContainer);\r
11873                                 else\r
11874                                         r.setStart(rb.startContainer, rb.startOffset);\r
11875                         }\r
11876 \r
11877                         if (!ec.nextSibling && ec.parentNode.nodeName == bn)\r
11878                                 r.setEndAfter(ec.parentNode);\r
11879                         else\r
11880                                 r.setEnd(ra.endContainer, ra.endOffset);\r
11881 \r
11882                         // Delete and replace it with new block elements\r
11883                         r.deleteContents();\r
11884 \r
11885                         if (isOpera)\r
11886                                 ed.getWin().scrollTo(0, vp.y);\r
11887 \r
11888                         // Never wrap blocks in blocks\r
11889                         if (bef.firstChild && bef.firstChild.nodeName == bn)\r
11890                                 bef.innerHTML = bef.firstChild.innerHTML;\r
11891 \r
11892                         if (aft.firstChild && aft.firstChild.nodeName == bn)\r
11893                                 aft.innerHTML = aft.firstChild.innerHTML;\r
11894 \r
11895                         // Padd empty blocks\r
11896                         if (isEmpty(bef))\r
11897                                 bef.innerHTML = '<br />';\r
11898 \r
11899                         function appendStyles(e, en) {\r
11900                                 var nl = [], nn, n, i;\r
11901 \r
11902                                 e.innerHTML = '';\r
11903 \r
11904                                 // Make clones of style elements\r
11905                                 if (se.keep_styles) {\r
11906                                         n = en;\r
11907                                         do {\r
11908                                                 // We only want style specific elements\r
11909                                                 if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(n.nodeName)) {\r
11910                                                         nn = n.cloneNode(false);\r
11911                                                         dom.setAttrib(nn, 'id', ''); // Remove ID since it needs to be unique\r
11912                                                         nl.push(nn);\r
11913                                                 }\r
11914                                         } while (n = n.parentNode);\r
11915                                 }\r
11916 \r
11917                                 // Append style elements to aft\r
11918                                 if (nl.length > 0) {\r
11919                                         for (i = nl.length - 1, nn = e; i >= 0; i--)\r
11920                                                 nn = nn.appendChild(nl[i]);\r
11921 \r
11922                                         // Padd most inner style element\r
11923                                         nl[0].innerHTML = isOpera ? '&nbsp;' : '<br />'; // Extra space for Opera so that the caret can move there\r
11924                                         return nl[0]; // Move caret to most inner element\r
11925                                 } else\r
11926                                         e.innerHTML = isOpera ? '&nbsp;' : '<br />'; // Extra space for Opera so that the caret can move there\r
11927                         };\r
11928 \r
11929                         // Fill empty afterblook with current style\r
11930                         if (isEmpty(aft))\r
11931                                 car = appendStyles(aft, en);\r
11932 \r
11933                         // Opera needs this one backwards for older versions\r
11934                         if (isOpera && parseFloat(opera.version()) < 9.5) {\r
11935                                 r.insertNode(bef);\r
11936                                 r.insertNode(aft);\r
11937                         } else {\r
11938                                 r.insertNode(aft);\r
11939                                 r.insertNode(bef);\r
11940                         }\r
11941 \r
11942                         // Normalize\r
11943                         aft.normalize();\r
11944                         bef.normalize();\r
11945 \r
11946                         function first(n) {\r
11947                                 return d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false).nextNode() || n;\r
11948                         };\r
11949 \r
11950                         // Move cursor and scroll into view\r
11951                         r = d.createRange();\r
11952                         r.selectNodeContents(isGecko ? first(car || aft) : car || aft);\r
11953                         r.collapse(1);\r
11954                         s.removeAllRanges();\r
11955                         s.addRange(r);\r
11956 \r
11957                         // 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\r
11958                         y = ed.dom.getPos(aft).y;\r
11959                         ch = aft.clientHeight;\r
11960 \r
11961                         // Is element within viewport\r
11962                         if (y < vp.y || y + ch > vp.y + vp.h) {\r
11963                                 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\r
11964                                 //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));\r
11965                         }\r
11966 \r
11967                         return false;\r
11968                 },\r
11969 \r
11970                 backspaceDelete : function(e, bs) {\r
11971                         var t = this, ed = t.editor, b = ed.getBody(), n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn;\r
11972 \r
11973                         // The caret sometimes gets stuck in Gecko if you delete empty paragraphs\r
11974                         // This workaround removes the element by hand and moves the caret to the previous element\r
11975                         if (sc && ed.dom.isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) {\r
11976                                 if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) {\r
11977                                         // Find previous block element\r
11978                                         n = sc;\r
11979                                         while ((n = n.previousSibling) && !ed.dom.isBlock(n)) ;\r
11980 \r
11981                                         if (n) {\r
11982                                                 if (sc != b.firstChild) {\r
11983                                                         // Find last text node\r
11984                                                         w = ed.dom.doc.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);\r
11985                                                         while (tn = w.nextNode())\r
11986                                                                 n = tn;\r
11987 \r
11988                                                         // Place caret at the end of last text node\r
11989                                                         r = ed.getDoc().createRange();\r
11990                                                         r.setStart(n, n.nodeValue ? n.nodeValue.length : 0);\r
11991                                                         r.setEnd(n, n.nodeValue ? n.nodeValue.length : 0);\r
11992                                                         se.setRng(r);\r
11993 \r
11994                                                         // Remove the target container\r
11995                                                         ed.dom.remove(sc);\r
11996                                                 }\r
11997 \r
11998                                                 return Event.cancel(e);\r
11999                                         }\r
12000                                 }\r
12001                         }\r
12002 \r
12003                         // Gecko generates BR elements here and there, we don't like those so lets remove them\r
12004                         function handler(e) {\r
12005                                 var pr;\r
12006 \r
12007                                 e = e.target;\r
12008 \r
12009                                 // A new BR was created in a block element, remove it\r
12010                                 if (e && e.parentNode && e.nodeName == 'BR' && (n = t.getParentBlock(e))) {\r
12011                                         pr = e.previousSibling;\r
12012 \r
12013                                         Event.remove(b, 'DOMNodeInserted', handler);\r
12014 \r
12015                                         // Is there whitespace at the end of the node before then we might need the pesky BR\r
12016                                         // to place the caret at a correct location see bug: #2013943\r
12017                                         if (pr && pr.nodeType == 3 && /\s+$/.test(pr.nodeValue))\r
12018                                                 return;\r
12019 \r
12020                                         // Only remove BR elements that got inserted in the middle of the text\r
12021                                         if (e.previousSibling || e.nextSibling)\r
12022                                                 ed.dom.remove(e);\r
12023                                 }\r
12024                         };\r
12025 \r
12026                         // Listen for new nodes\r
12027                         Event._add(b, 'DOMNodeInserted', handler);\r
12028 \r
12029                         // Remove listener\r
12030                         window.setTimeout(function() {\r
12031                                 Event._remove(b, 'DOMNodeInserted', handler);\r
12032                         }, 1);\r
12033                 }\r
12034         });\r
12035 })(tinymce);\r
12036 (function(tinymce) {\r
12037         // Shorten names\r
12038         var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, extend = tinymce.extend;\r
12039 \r
12040         tinymce.create('tinymce.ControlManager', {\r
12041                 ControlManager : function(ed, s) {\r
12042                         var t = this, i;\r
12043 \r
12044                         s = s || {};\r
12045                         t.editor = ed;\r
12046                         t.controls = {};\r
12047                         t.onAdd = new tinymce.util.Dispatcher(t);\r
12048                         t.onPostRender = new tinymce.util.Dispatcher(t);\r
12049                         t.prefix = s.prefix || ed.id + '_';\r
12050                         t._cls = {};\r
12051 \r
12052                         t.onPostRender.add(function() {\r
12053                                 each(t.controls, function(c) {\r
12054                                         c.postRender();\r
12055                                 });\r
12056                         });\r
12057                 },\r
12058 \r
12059                 get : function(id) {\r
12060                         return this.controls[this.prefix + id] || this.controls[id];\r
12061                 },\r
12062 \r
12063                 setActive : function(id, s) {\r
12064                         var c = null;\r
12065 \r
12066                         if (c = this.get(id))\r
12067                                 c.setActive(s);\r
12068 \r
12069                         return c;\r
12070                 },\r
12071 \r
12072                 setDisabled : function(id, s) {\r
12073                         var c = null;\r
12074 \r
12075                         if (c = this.get(id))\r
12076                                 c.setDisabled(s);\r
12077 \r
12078                         return c;\r
12079                 },\r
12080 \r
12081                 add : function(c) {\r
12082                         var t = this;\r
12083 \r
12084                         if (c) {\r
12085                                 t.controls[c.id] = c;\r
12086                                 t.onAdd.dispatch(c, t);\r
12087                         }\r
12088 \r
12089                         return c;\r
12090                 },\r
12091 \r
12092                 createControl : function(n) {\r
12093                         var c, t = this, ed = t.editor;\r
12094 \r
12095                         each(ed.plugins, function(p) {\r
12096                                 if (p.createControl) {\r
12097                                         c = p.createControl(n, t);\r
12098 \r
12099                                         if (c)\r
12100                                                 return false;\r
12101                                 }\r
12102                         });\r
12103 \r
12104                         switch (n) {\r
12105                                 case "|":\r
12106                                 case "separator":\r
12107                                         return t.createSeparator();\r
12108                         }\r
12109 \r
12110                         if (!c && ed.buttons && (c = ed.buttons[n]))\r
12111                                 return t.createButton(n, c);\r
12112 \r
12113                         return t.add(c);\r
12114                 },\r
12115 \r
12116                 createDropMenu : function(id, s, cc) {\r
12117                         var t = this, ed = t.editor, c, bm, v, cls;\r
12118 \r
12119                         s = extend({\r
12120                                 'class' : 'mceDropDown',\r
12121                                 constrain : ed.settings.constrain_menus\r
12122                         }, s);\r
12123 \r
12124                         s['class'] = s['class'] + ' ' + ed.getParam('skin') + 'Skin';\r
12125                         if (v = ed.getParam('skin_variant'))\r
12126                                 s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1);\r
12127 \r
12128                         id = t.prefix + id;\r
12129                         cls = cc || t._cls.dropmenu || tinymce.ui.DropMenu;\r
12130                         c = t.controls[id] = new cls(id, s);\r
12131                         c.onAddItem.add(function(c, o) {\r
12132                                 var s = o.settings;\r
12133 \r
12134                                 s.title = ed.getLang(s.title, s.title);\r
12135 \r
12136                                 if (!s.onclick) {\r
12137                                         s.onclick = function(v) {\r
12138                                                 ed.execCommand(s.cmd, s.ui || false, s.value);\r
12139                                         };\r
12140                                 }\r
12141                         });\r
12142 \r
12143                         ed.onRemove.add(function() {\r
12144                                 c.destroy();\r
12145                         });\r
12146 \r
12147                         // Fix for bug #1897785, #1898007\r
12148                         if (tinymce.isIE) {\r
12149                                 c.onShowMenu.add(function() {\r
12150                                         // IE 8 needs focus in order to store away a range with the current collapsed caret location\r
12151                                         ed.focus();\r
12152 \r
12153                                         bm = ed.selection.getBookmark(1);\r
12154                                 });\r
12155 \r
12156                                 c.onHideMenu.add(function() {\r
12157                                         if (bm) {\r
12158                                                 ed.selection.moveToBookmark(bm);\r
12159                                                 bm = 0;\r
12160                                         }\r
12161                                 });\r
12162                         }\r
12163 \r
12164                         return t.add(c);\r
12165                 },\r
12166 \r
12167                 createListBox : function(id, s, cc) {\r
12168                         var t = this, ed = t.editor, cmd, c, cls;\r
12169 \r
12170                         if (t.get(id))\r
12171                                 return null;\r
12172 \r
12173                         s.title = ed.translate(s.title);\r
12174                         s.scope = s.scope || ed;\r
12175 \r
12176                         if (!s.onselect) {\r
12177                                 s.onselect = function(v) {\r
12178                                         ed.execCommand(s.cmd, s.ui || false, v || s.value);\r
12179                                 };\r
12180                         }\r
12181 \r
12182                         s = extend({\r
12183                                 title : s.title,\r
12184                                 'class' : 'mce_' + id,\r
12185                                 scope : s.scope,\r
12186                                 control_manager : t\r
12187                         }, s);\r
12188 \r
12189                         id = t.prefix + id;\r
12190 \r
12191                         if (ed.settings.use_native_selects)\r
12192                                 c = new tinymce.ui.NativeListBox(id, s);\r
12193                         else {\r
12194                                 cls = cc || t._cls.listbox || tinymce.ui.ListBox;\r
12195                                 c = new cls(id, s);\r
12196                         }\r
12197 \r
12198                         t.controls[id] = c;\r
12199 \r
12200                         // Fix focus problem in Safari\r
12201                         if (tinymce.isWebKit) {\r
12202                                 c.onPostRender.add(function(c, n) {\r
12203                                         // Store bookmark on mousedown\r
12204                                         Event.add(n, 'mousedown', function() {\r
12205                                                 ed.bookmark = ed.selection.getBookmark('simple');\r
12206                                         });\r
12207 \r
12208                                         // Restore on focus, since it might be lost\r
12209                                         Event.add(n, 'focus', function() {\r
12210                                                 ed.selection.moveToBookmark(ed.bookmark);\r
12211                                                 ed.bookmark = null;\r
12212                                         });\r
12213                                 });\r
12214                         }\r
12215 \r
12216                         if (c.hideMenu)\r
12217                                 ed.onMouseDown.add(c.hideMenu, c);\r
12218 \r
12219                         return t.add(c);\r
12220                 },\r
12221 \r
12222                 createButton : function(id, s, cc) {\r
12223                         var t = this, ed = t.editor, o, c, cls;\r
12224 \r
12225                         if (t.get(id))\r
12226                                 return null;\r
12227 \r
12228                         s.title = ed.translate(s.title);\r
12229                         s.label = ed.translate(s.label);\r
12230                         s.scope = s.scope || ed;\r
12231 \r
12232                         if (!s.onclick && !s.menu_button) {\r
12233                                 s.onclick = function() {\r
12234                                         ed.execCommand(s.cmd, s.ui || false, s.value);\r
12235                                 };\r
12236                         }\r
12237 \r
12238                         s = extend({\r
12239                                 title : s.title,\r
12240                                 'class' : 'mce_' + id,\r
12241                                 unavailable_prefix : ed.getLang('unavailable', ''),\r
12242                                 scope : s.scope,\r
12243                                 control_manager : t\r
12244                         }, s);\r
12245 \r
12246                         id = t.prefix + id;\r
12247 \r
12248                         if (s.menu_button) {\r
12249                                 cls = cc || t._cls.menubutton || tinymce.ui.MenuButton;\r
12250                                 c = new cls(id, s);\r
12251                                 ed.onMouseDown.add(c.hideMenu, c);\r
12252                         } else {\r
12253                                 cls = t._cls.button || tinymce.ui.Button;\r
12254                                 c = new cls(id, s);\r
12255                         }\r
12256 \r
12257                         return t.add(c);\r
12258                 },\r
12259 \r
12260                 createMenuButton : function(id, s, cc) {\r
12261                         s = s || {};\r
12262                         s.menu_button = 1;\r
12263 \r
12264                         return this.createButton(id, s, cc);\r
12265                 },\r
12266 \r
12267                 createSplitButton : function(id, s, cc) {\r
12268                         var t = this, ed = t.editor, cmd, c, cls;\r
12269 \r
12270                         if (t.get(id))\r
12271                                 return null;\r
12272 \r
12273                         s.title = ed.translate(s.title);\r
12274                         s.scope = s.scope || ed;\r
12275 \r
12276                         if (!s.onclick) {\r
12277                                 s.onclick = function(v) {\r
12278                                         ed.execCommand(s.cmd, s.ui || false, v || s.value);\r
12279                                 };\r
12280                         }\r
12281 \r
12282                         if (!s.onselect) {\r
12283                                 s.onselect = function(v) {\r
12284                                         ed.execCommand(s.cmd, s.ui || false, v || s.value);\r
12285                                 };\r
12286                         }\r
12287 \r
12288                         s = extend({\r
12289                                 title : s.title,\r
12290                                 'class' : 'mce_' + id,\r
12291                                 scope : s.scope,\r
12292                                 control_manager : t\r
12293                         }, s);\r
12294 \r
12295                         id = t.prefix + id;\r
12296                         cls = cc || t._cls.splitbutton || tinymce.ui.SplitButton;\r
12297                         c = t.add(new cls(id, s));\r
12298                         ed.onMouseDown.add(c.hideMenu, c);\r
12299 \r
12300                         return c;\r
12301                 },\r
12302 \r
12303                 createColorSplitButton : function(id, s, cc) {\r
12304                         var t = this, ed = t.editor, cmd, c, cls, bm;\r
12305 \r
12306                         if (t.get(id))\r
12307                                 return null;\r
12308 \r
12309                         s.title = ed.translate(s.title);\r
12310                         s.scope = s.scope || ed;\r
12311 \r
12312                         if (!s.onclick) {\r
12313                                 s.onclick = function(v) {\r
12314                                         if (tinymce.isIE)\r
12315                                                 bm = ed.selection.getBookmark(1);\r
12316         \r
12317                                         ed.execCommand(s.cmd, s.ui || false, v || s.value);\r
12318                                 };\r
12319                         }\r
12320 \r
12321                         if (!s.onselect) {\r
12322                                 s.onselect = function(v) {\r
12323                                         ed.execCommand(s.cmd, s.ui || false, v || s.value);\r
12324                                 };\r
12325                         }\r
12326 \r
12327                         s = extend({\r
12328                                 title : s.title,\r
12329                                 'class' : 'mce_' + id,\r
12330                                 'menu_class' : ed.getParam('skin') + 'Skin',\r
12331                                 scope : s.scope,\r
12332                                 more_colors_title : ed.getLang('more_colors')\r
12333                         }, s);\r
12334 \r
12335                         id = t.prefix + id;\r
12336                         cls = cc || t._cls.colorsplitbutton || tinymce.ui.ColorSplitButton;\r
12337                         c = new cls(id, s);\r
12338                         ed.onMouseDown.add(c.hideMenu, c);\r
12339 \r
12340                         // Remove the menu element when the editor is removed\r
12341                         ed.onRemove.add(function() {\r
12342                                 c.destroy();\r
12343                         });\r
12344 \r
12345                         // Fix for bug #1897785, #1898007\r
12346                         if (tinymce.isIE) {\r
12347                                 c.onHideMenu.add(function() {\r
12348                                         if (bm) {\r
12349                                                 ed.selection.moveToBookmark(bm);\r
12350                                                 bm = 0;\r
12351                                         }\r
12352                                 });\r
12353                         }\r
12354 \r
12355                         return t.add(c);\r
12356                 },\r
12357 \r
12358                 createToolbar : function(id, s, cc) {\r
12359                         var c, t = this, cls;\r
12360 \r
12361                         id = t.prefix + id;\r
12362                         cls = cc || t._cls.toolbar || tinymce.ui.Toolbar;\r
12363                         c = new cls(id, s);\r
12364 \r
12365                         if (t.get(id))\r
12366                                 return null;\r
12367 \r
12368                         return t.add(c);\r
12369                 },\r
12370 \r
12371                 createSeparator : function(cc) {\r
12372                         var cls = cc || this._cls.separator || tinymce.ui.Separator;\r
12373 \r
12374                         return new cls();\r
12375                 },\r
12376 \r
12377                 setControlType : function(n, c) {\r
12378                         return this._cls[n.toLowerCase()] = c;\r
12379                 },\r
12380 \r
12381                 destroy : function() {\r
12382                         each(this.controls, function(c) {\r
12383                                 c.destroy();\r
12384                         });\r
12385 \r
12386                         this.controls = null;\r
12387                 }\r
12388 \r
12389                 });\r
12390 })(tinymce);\r
12391 (function(tinymce) {\r
12392         var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isIE = tinymce.isIE, isOpera = tinymce.isOpera;\r
12393 \r
12394         tinymce.create('tinymce.WindowManager', {\r
12395                 WindowManager : function(ed) {\r
12396                         var t = this;\r
12397 \r
12398                         t.editor = ed;\r
12399                         t.onOpen = new Dispatcher(t);\r
12400                         t.onClose = new Dispatcher(t);\r
12401                         t.params = {};\r
12402                         t.features = {};\r
12403                 },\r
12404 \r
12405                 open : function(s, p) {\r
12406                         var t = this, f = '', x, y, mo = t.editor.settings.dialog_type == 'modal', w, sw, sh, vp = tinymce.DOM.getViewPort(), u;\r
12407 \r
12408                         // Default some options\r
12409                         s = s || {};\r
12410                         p = p || {};\r
12411                         sw = isOpera ? vp.w : screen.width; // Opera uses windows inside the Opera window\r
12412                         sh = isOpera ? vp.h : screen.height;\r
12413                         s.name = s.name || 'mc_' + new Date().getTime();\r
12414                         s.width = parseInt(s.width || 320);\r
12415                         s.height = parseInt(s.height || 240);\r
12416                         s.resizable = true;\r
12417                         s.left = s.left || parseInt(sw / 2.0) - (s.width / 2.0);\r
12418                         s.top = s.top || parseInt(sh / 2.0) - (s.height / 2.0);\r
12419                         p.inline = false;\r
12420                         p.mce_width = s.width;\r
12421                         p.mce_height = s.height;\r
12422                         p.mce_auto_focus = s.auto_focus;\r
12423 \r
12424                         if (mo) {\r
12425                                 if (isIE) {\r
12426                                         s.center = true;\r
12427                                         s.help = false;\r
12428                                         s.dialogWidth = s.width + 'px';\r
12429                                         s.dialogHeight = s.height + 'px';\r
12430                                         s.scroll = s.scrollbars || false;\r
12431                                 }\r
12432                         }\r
12433 \r
12434                         // Build features string\r
12435                         each(s, function(v, k) {\r
12436                                 if (tinymce.is(v, 'boolean'))\r
12437                                         v = v ? 'yes' : 'no';\r
12438 \r
12439                                 if (!/^(name|url)$/.test(k)) {\r
12440                                         if (isIE && mo)\r
12441                                                 f += (f ? ';' : '') + k + ':' + v;\r
12442                                         else\r
12443                                                 f += (f ? ',' : '') + k + '=' + v;\r
12444                                 }\r
12445                         });\r
12446 \r
12447                         t.features = s;\r
12448                         t.params = p;\r
12449                         t.onOpen.dispatch(t, s, p);\r
12450 \r
12451                         u = s.url || s.file;\r
12452                         u = tinymce._addVer(u);\r
12453 \r
12454                         try {\r
12455                                 if (isIE && mo) {\r
12456                                         w = 1;\r
12457                                         window.showModalDialog(u, window, f);\r
12458                                 } else\r
12459                                         w = window.open(u, s.name, f);\r
12460                         } catch (ex) {\r
12461                                 // Ignore\r
12462                         }\r
12463 \r
12464                         if (!w)\r
12465                                 alert(t.editor.getLang('popup_blocked'));\r
12466                 },\r
12467 \r
12468                 close : function(w) {\r
12469                         w.close();\r
12470                         this.onClose.dispatch(this);\r
12471                 },\r
12472 \r
12473                 createInstance : function(cl, a, b, c, d, e) {\r
12474                         var f = tinymce.resolve(cl);\r
12475 \r
12476                         return new f(a, b, c, d, e);\r
12477                 },\r
12478 \r
12479                 confirm : function(t, cb, s, w) {\r
12480                         w = w || window;\r
12481 \r
12482                         cb.call(s || this, w.confirm(this._decode(this.editor.getLang(t, t))));\r
12483                 },\r
12484 \r
12485                 alert : function(tx, cb, s, w) {\r
12486                         var t = this;\r
12487 \r
12488                         w = w || window;\r
12489                         w.alert(t._decode(t.editor.getLang(tx, tx)));\r
12490 \r
12491                         if (cb)\r
12492                                 cb.call(s || t);\r
12493                 },\r
12494 \r
12495                 // Internal functions\r
12496 \r
12497                 _decode : function(s) {\r
12498                         return tinymce.DOM.decode(s).replace(/\\n/g, '\n');\r
12499                 }\r
12500 \r
12501                 });\r
12502 }(tinymce));(function(tinymce) {\r
12503         tinymce.CommandManager = function() {\r
12504                 var execCommands = {}, queryStateCommands = {}, queryValueCommands = {};\r
12505 \r
12506                 function add(collection, cmd, func, scope) {\r
12507                         if (typeof(cmd) == 'string')\r
12508                                 cmd = [cmd];\r
12509 \r
12510                         tinymce.each(cmd, function(cmd) {\r
12511                                 collection[cmd.toLowerCase()] = {func : func, scope : scope};\r
12512                         });\r
12513                 };\r
12514 \r
12515                 tinymce.extend(this, {\r
12516                         add : function(cmd, func, scope) {\r
12517                                 add(execCommands, cmd, func, scope);\r
12518                         },\r
12519 \r
12520                         addQueryStateHandler : function(cmd, func, scope) {\r
12521                                 add(queryStateCommands, cmd, func, scope);\r
12522                         },\r
12523 \r
12524                         addQueryValueHandler : function(cmd, func, scope) {\r
12525                                 add(queryValueCommands, cmd, func, scope);\r
12526                         },\r
12527 \r
12528                         execCommand : function(scope, cmd, ui, value, args) {\r
12529                                 if (cmd = execCommands[cmd.toLowerCase()]) {\r
12530                                         if (cmd.func.call(scope || cmd.scope, ui, value, args) !== false)\r
12531                                                 return true;\r
12532                                 }\r
12533                         },\r
12534 \r
12535                         queryCommandValue : function() {\r
12536                                 if (cmd = queryValueCommands[cmd.toLowerCase()])\r
12537                                         return cmd.func.call(scope || cmd.scope, ui, value, args);\r
12538                         },\r
12539 \r
12540                         queryCommandState : function() {\r
12541                                 if (cmd = queryStateCommands[cmd.toLowerCase()])\r
12542                                         return cmd.func.call(scope || cmd.scope, ui, value, args);\r
12543                         }\r
12544                 });\r
12545         };\r
12546 \r
12547         tinymce.GlobalCommands = new tinymce.CommandManager();\r
12548 })(tinymce);(function(tinymce) {\r
12549         function processRange(dom, start, end, callback) {\r
12550                 var ancestor, n, startPoint, endPoint, sib;\r
12551 \r
12552                 function findEndPoint(n, c) {\r
12553                         do {\r
12554                                 if (n.parentNode == c)\r
12555                                         return n;\r
12556 \r
12557                                 n = n.parentNode;\r
12558                         } while(n);\r
12559                 };\r
12560 \r
12561                 function process(n) {\r
12562                         callback(n);\r
12563                         tinymce.walk(n, callback, 'childNodes');\r
12564                 };\r
12565 \r
12566                 // Find common ancestor and end points\r
12567                 ancestor = dom.findCommonAncestor(start, end);\r
12568                 startPoint = findEndPoint(start, ancestor) || start;\r
12569                 endPoint = findEndPoint(end, ancestor) || end;\r
12570 \r
12571                 // Process left leaf\r
12572                 for (n = start; n && n != startPoint; n = n.parentNode) {\r
12573                         for (sib = n.nextSibling; sib; sib = sib.nextSibling)\r
12574                                 process(sib);\r
12575                 }\r
12576 \r
12577                 // Process middle from start to end point\r
12578                 if (startPoint != endPoint) {\r
12579                         for (n = startPoint.nextSibling; n && n != endPoint; n = n.nextSibling)\r
12580                                 process(n);\r
12581                 } else\r
12582                         process(startPoint);\r
12583 \r
12584                 // Process right leaf\r
12585                 for (n = end; n && n != endPoint; n = n.parentNode) {\r
12586                         for (sib = n.previousSibling; sib; sib = sib.previousSibling)\r
12587                                 process(sib);\r
12588                 }\r
12589         };\r
12590 \r
12591         tinymce.GlobalCommands.add('RemoveFormat', function() {\r
12592                 var ed = this, dom = ed.dom, s = ed.selection, r = s.getRng(1), nodes = [], bm, start, end, sc, so, ec, eo, n;\r
12593 \r
12594                 function findFormatRoot(n) {\r
12595                         var sp;\r
12596 \r
12597                         dom.getParent(n, function(n) {\r
12598                                 if (dom.is(n, ed.getParam('removeformat_selector')))\r
12599                                         sp = n;\r
12600 \r
12601                                 return dom.isBlock(n);\r
12602                         }, ed.getBody());\r
12603 \r
12604                         return sp;\r
12605                 };\r
12606 \r
12607                 function collect(n) {\r
12608                         if (dom.is(n, ed.getParam('removeformat_selector')))\r
12609                                 nodes.push(n);\r
12610                 };\r
12611 \r
12612                 function walk(n) {\r
12613                         collect(n);\r
12614                         tinymce.walk(n, collect, 'childNodes');\r
12615                 };\r
12616 \r
12617                 bm = s.getBookmark();\r
12618                 sc = r.startContainer;\r
12619                 ec = r.endContainer;\r
12620                 so = r.startOffset;\r
12621                 eo = r.endOffset;\r
12622                 sc = sc.nodeType == 1 ? sc.childNodes[Math.min(so, sc.childNodes.length - 1)] : sc;\r
12623                 ec = ec.nodeType == 1 ? ec.childNodes[Math.min(so == eo ? eo : eo - 1, ec.childNodes.length - 1)] : ec;\r
12624 \r
12625                 // Same container\r
12626                 if (sc == ec) { // TEXT_NODE\r
12627                         start = findFormatRoot(sc);\r
12628 \r
12629                         // Handle single text node\r
12630                         if (sc.nodeType == 3) {\r
12631                                 if (start && start.nodeType == 1) { // ELEMENT\r
12632                                         n = sc.splitText(so);\r
12633                                         n.splitText(eo - so);\r
12634                                         dom.split(start, n);\r
12635 \r
12636                                         s.moveToBookmark(bm);\r
12637                                 }\r
12638 \r
12639                                 return;\r
12640                         }\r
12641 \r
12642                         // Handle single element\r
12643                         walk(dom.split(start, sc) || sc);\r
12644                 } else {\r
12645                         // Find start/end format root\r
12646                         start = findFormatRoot(sc);\r
12647                         end = findFormatRoot(ec);\r
12648 \r
12649                         // Split start text node\r
12650                         if (start) {\r
12651                                 if (sc.nodeType == 3) { // TEXT\r
12652                                         // Since IE doesn't support white space nodes in the DOM we need to\r
12653                                         // add this invisible character so that the splitText function can split the contents\r
12654                                         if (so == sc.nodeValue.length)\r
12655                                                 sc.nodeValue += '\uFEFF'; // Yet another pesky IE fix\r
12656 \r
12657                                         sc = sc.splitText(so);\r
12658                                 }\r
12659                         }\r
12660 \r
12661                         // Split end text node\r
12662                         if (end) {\r
12663                                 if (ec.nodeType == 3) // TEXT\r
12664                                         ec.splitText(eo);\r
12665                         }\r
12666 \r
12667                         // If the start and end format root is the same then we need to wrap\r
12668                         // the end node in a span since the split calls might change the reference\r
12669                         // Example: <p><b><em>x[yz<span>---</span>12]3</em></b></p>\r
12670                         if (start && start == end)\r
12671                                 dom.replace(dom.create('span', {id : '__end'}, ec.cloneNode(true)), ec);\r
12672 \r
12673                         // Split all start containers down to the format root\r
12674                         if (start)\r
12675                                 start = dom.split(start, sc);\r
12676                         else\r
12677                                 start = sc;\r
12678 \r
12679                         // If there is a span wrapper use that one instead\r
12680                         if (n = dom.get('__end')) {\r
12681                                 ec = n;\r
12682                                 end = findFormatRoot(ec);\r
12683                         }\r
12684 \r
12685                         // Split all end containers down to the format root\r
12686                         if (end)\r
12687                                 end = dom.split(end, ec);\r
12688                         else\r
12689                                 end = ec;\r
12690 \r
12691                         // Collect nodes in between\r
12692                         processRange(dom, start, end, collect);\r
12693 \r
12694                         // Remove invisible character for IE workaround if we find it\r
12695                         if (sc.nodeValue == '\uFEFF')\r
12696                                 sc.nodeValue = '';\r
12697 \r
12698                         // Process start/end container elements\r
12699                         walk(ec);\r
12700                         walk(sc);\r
12701                 }\r
12702 \r
12703                 // Remove all collected nodes\r
12704                 tinymce.each(nodes, function(n) {\r
12705                         dom.remove(n, 1);\r
12706                 });\r
12707 \r
12708                 // Remove leftover wrapper\r
12709                 dom.remove('__end', 1);\r
12710 \r
12711                 s.moveToBookmark(bm);\r
12712         });\r
12713 })(tinymce);\r
12714 (function(tinymce) {\r
12715         tinymce.GlobalCommands.add('mceBlockQuote', function() {\r
12716                 var ed = this, s = ed.selection, dom = ed.dom, sb, eb, n, bm, bq, r, bq2, i, nl;\r
12717 \r
12718                 function getBQ(e) {\r
12719                         return dom.getParent(e, function(n) {return n.nodeName === 'BLOCKQUOTE';});\r
12720                 };\r
12721 \r
12722                 // Get start/end block\r
12723                 sb = dom.getParent(s.getStart(), dom.isBlock);\r
12724                 eb = dom.getParent(s.getEnd(), dom.isBlock);\r
12725 \r
12726                 // Remove blockquote(s)\r
12727                 if (bq = getBQ(sb)) {\r
12728                         if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR'))\r
12729                                 bm = s.getBookmark();\r
12730 \r
12731                         // Move all elements after the end block into new bq\r
12732                         if (getBQ(eb)) {\r
12733                                 bq2 = bq.cloneNode(false);\r
12734 \r
12735                                 while (n = eb.nextSibling)\r
12736                                         bq2.appendChild(n.parentNode.removeChild(n));\r
12737                         }\r
12738 \r
12739                         // Add new bq after\r
12740                         if (bq2)\r
12741                                 dom.insertAfter(bq2, bq);\r
12742 \r
12743                         // Move all selected blocks after the current bq\r
12744                         nl = s.getSelectedBlocks(sb, eb);\r
12745                         for (i = nl.length - 1; i >= 0; i--) {\r
12746                                 dom.insertAfter(nl[i], bq);\r
12747                         }\r
12748 \r
12749                         // Empty bq, then remove it\r
12750                         if (/^\s*$/.test(bq.innerHTML))\r
12751                                 dom.remove(bq, 1); // Keep children so boomark restoration works correctly\r
12752 \r
12753                         // Empty bq, then remote it\r
12754                         if (bq2 && /^\s*$/.test(bq2.innerHTML))\r
12755                                 dom.remove(bq2, 1); // Keep children so boomark restoration works correctly\r
12756 \r
12757                         if (!bm) {\r
12758                                 // Move caret inside empty block element\r
12759                                 if (!tinymce.isIE) {\r
12760                                         r = ed.getDoc().createRange();\r
12761                                         r.setStart(sb, 0);\r
12762                                         r.setEnd(sb, 0);\r
12763                                         s.setRng(r);\r
12764                                 } else {\r
12765                                         s.select(sb);\r
12766                                         s.collapse(0);\r
12767 \r
12768                                         // IE misses the empty block some times element so we must move back the caret\r
12769                                         if (dom.getParent(s.getStart(), dom.isBlock) != sb) {\r
12770                                                 r = s.getRng();\r
12771                                                 r.move('character', -1);\r
12772                                                 r.select();\r
12773                                         }\r
12774                                 }\r
12775                         } else\r
12776                                 ed.selection.moveToBookmark(bm);\r
12777 \r
12778                         return;\r
12779                 }\r
12780 \r
12781                 // Since IE can start with a totally empty document we need to add the first bq and paragraph\r
12782                 if (tinymce.isIE && !sb && !eb) {\r
12783                         ed.getDoc().execCommand('Indent');\r
12784                         n = getBQ(s.getNode());\r
12785                         n.style.margin = n.dir = ''; // IE adds margin and dir to bq\r
12786                         return;\r
12787                 }\r
12788 \r
12789                 if (!sb || !eb)\r
12790                         return;\r
12791 \r
12792                 // If empty paragraph node then do not use bookmark\r
12793                 if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR'))\r
12794                         bm = s.getBookmark();\r
12795 \r
12796                 // Move selected block elements into a bq\r
12797                 tinymce.each(s.getSelectedBlocks(getBQ(s.getStart()), getBQ(s.getEnd())), function(e) {\r
12798                         // Found existing BQ add to this one\r
12799                         if (e.nodeName == 'BLOCKQUOTE' && !bq) {\r
12800                                 bq = e;\r
12801                                 return;\r
12802                         }\r
12803 \r
12804                         // No BQ found, create one\r
12805                         if (!bq) {\r
12806                                 bq = dom.create('blockquote');\r
12807                                 e.parentNode.insertBefore(bq, e);\r
12808                         }\r
12809 \r
12810                         // Add children from existing BQ\r
12811                         if (e.nodeName == 'BLOCKQUOTE' && bq) {\r
12812                                 n = e.firstChild;\r
12813 \r
12814                                 while (n) {\r
12815                                         bq.appendChild(n.cloneNode(true));\r
12816                                         n = n.nextSibling;\r
12817                                 }\r
12818 \r
12819                                 dom.remove(e);\r
12820                                 return;\r
12821                         }\r
12822 \r
12823                         // Add non BQ element to BQ\r
12824                         bq.appendChild(dom.remove(e));\r
12825                 });\r
12826 \r
12827                 if (!bm) {\r
12828                         // Move caret inside empty block element\r
12829                         if (!tinymce.isIE) {\r
12830                                 r = ed.getDoc().createRange();\r
12831                                 r.setStart(sb, 0);\r
12832                                 r.setEnd(sb, 0);\r
12833                                 s.setRng(r);\r
12834                         } else {\r
12835                                 s.select(sb);\r
12836                                 s.collapse(1);\r
12837                         }\r
12838                 } else\r
12839                         s.moveToBookmark(bm);\r
12840         });\r
12841 })(tinymce);\r
12842 (function(tinymce) {\r
12843         tinymce.each(['Cut', 'Copy', 'Paste'], function(cmd) {\r
12844                 tinymce.GlobalCommands.add(cmd, function() {\r
12845                         var ed = this, doc = ed.getDoc();\r
12846 \r
12847                         try {\r
12848                                 doc.execCommand(cmd, false, null);\r
12849 \r
12850                                 // On WebKit the command will just be ignored if it's not enabled\r
12851                                 if (!doc.queryCommandSupported(cmd))\r
12852                                         throw 'Error';\r
12853                         } catch (ex) {\r
12854                                 ed.windowManager.alert(ed.getLang('clipboard_no_support'));\r
12855                         }\r
12856                 });\r
12857         });\r
12858 })(tinymce);\r
12859 (function(tinymce) {\r
12860         tinymce.GlobalCommands.add('InsertHorizontalRule', function() {\r
12861                 if (tinymce.isOpera)\r
12862                         return this.getDoc().execCommand('InsertHorizontalRule', false, '');\r
12863 \r
12864                 this.selection.setContent('<hr />');\r
12865         });\r
12866 })(tinymce);\r
12867 (function() {\r
12868         var cmds = tinymce.GlobalCommands;\r
12869 \r
12870         cmds.add(['mceEndUndoLevel', 'mceAddUndoLevel'], function() {\r
12871                 this.undoManager.add();\r
12872         });\r
12873 \r
12874         cmds.add('Undo', function() {\r
12875                 var ed = this;\r
12876 \r
12877                 if (ed.settings.custom_undo_redo) {\r
12878                         ed.undoManager.undo();\r
12879                         ed.nodeChanged();\r
12880                         return true;\r
12881                 }\r
12882 \r
12883                 return false; // Run browser command\r
12884         });\r
12885 \r
12886         cmds.add('Redo', function() {\r
12887                 var ed = this;\r
12888 \r
12889                 if (ed.settings.custom_undo_redo) {\r
12890                         ed.undoManager.redo();\r
12891                         ed.nodeChanged();\r
12892                         return true;\r
12893                 }\r
12894 \r
12895                 return false; // Run browser command\r
12896         });\r
12897 })();\r