commit | author | age
|
69d05c
|
1 |
(function(win) {
|
A |
2 |
var whiteSpaceRe = /^\s*|\s*$/g,
|
a9251b
|
3 |
undefined, isRegExpBroken = 'B'.replace(/A(.)|B/, '$1') === '$1';
|
d9344f
|
4 |
|
69d05c
|
5 |
var tinymce = {
|
A |
6 |
majorVersion : '3',
|
d9344f
|
7 |
|
a9251b
|
8 |
minorVersion : '4.2',
|
58fb65
|
9 |
|
a9251b
|
10 |
releaseDate : '2011-04-07',
|
58fb65
|
11 |
|
69d05c
|
12 |
_init : function() {
|
A |
13 |
var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
|
58fb65
|
14 |
|
69d05c
|
15 |
t.isOpera = win.opera && opera.buildNumber;
|
58fb65
|
16 |
|
69d05c
|
17 |
t.isWebKit = /WebKit/.test(ua);
|
58fb65
|
18 |
|
69d05c
|
19 |
t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName);
|
58fb65
|
20 |
|
69d05c
|
21 |
t.isIE6 = t.isIE && /MSIE [56]/.test(ua);
|
d9344f
|
22 |
|
69d05c
|
23 |
t.isGecko = !t.isWebKit && /Gecko/.test(ua);
|
d9344f
|
24 |
|
69d05c
|
25 |
t.isMac = ua.indexOf('Mac') != -1;
|
d9344f
|
26 |
|
69d05c
|
27 |
t.isAir = /adobeair/i.test(ua);
|
2011be
|
28 |
|
A |
29 |
t.isIDevice = /(iPad|iPhone)/.test(ua);
|
18240a
|
30 |
|
69d05c
|
31 |
// TinyMCE .NET webcontrol might be setting the values for TinyMCE
|
A |
32 |
if (win.tinyMCEPreInit) {
|
|
33 |
t.suffix = tinyMCEPreInit.suffix;
|
|
34 |
t.baseURL = tinyMCEPreInit.base;
|
|
35 |
t.query = tinyMCEPreInit.query;
|
d9344f
|
36 |
return;
|
69d05c
|
37 |
}
|
d9344f
|
38 |
|
69d05c
|
39 |
// Get suffix and base
|
A |
40 |
t.suffix = '';
|
|
41 |
|
|
42 |
// If base element found, add that infront of baseURL
|
|
43 |
nl = d.getElementsByTagName('base');
|
|
44 |
for (i=0; i<nl.length; i++) {
|
|
45 |
if (v = nl[i].href) {
|
|
46 |
// Host only value like http://site.com or http://site.com:8008
|
|
47 |
if (/^https?:\/\/[^\/]+$/.test(v))
|
|
48 |
v += '/';
|
|
49 |
|
|
50 |
base = v ? v.match(/.*\//)[0] : ''; // Get only directory
|
|
51 |
}
|
|
52 |
}
|
|
53 |
|
|
54 |
function getBase(n) {
|
a9251b
|
55 |
if (n.src && /tiny_mce(|_gzip|_jquery|_prototype|_full)(_dev|_src)?.js/.test(n.src)) {
|
69d05c
|
56 |
if (/_(src|dev)\.js/g.test(n.src))
|
A |
57 |
t.suffix = '_src';
|
|
58 |
|
|
59 |
if ((p = n.src.indexOf('?')) != -1)
|
|
60 |
t.query = n.src.substring(p + 1);
|
|
61 |
|
|
62 |
t.baseURL = n.src.substring(0, n.src.lastIndexOf('/'));
|
|
63 |
|
|
64 |
// If path to script is relative and a base href was found add that one infront
|
|
65 |
// the src property will always be an absolute one on non IE browsers and IE 8
|
|
66 |
// so this logic will basically only be executed on older IE versions
|
|
67 |
if (base && t.baseURL.indexOf('://') == -1 && t.baseURL.indexOf('/') !== 0)
|
|
68 |
t.baseURL = base + t.baseURL;
|
|
69 |
|
|
70 |
return t.baseURL;
|
|
71 |
}
|
|
72 |
|
|
73 |
return null;
|
|
74 |
};
|
|
75 |
|
|
76 |
// Check document
|
|
77 |
nl = d.getElementsByTagName('script');
|
d9344f
|
78 |
for (i=0; i<nl.length; i++) {
|
S |
79 |
if (getBase(nl[i]))
|
|
80 |
return;
|
|
81 |
}
|
|
82 |
|
69d05c
|
83 |
// Check head
|
A |
84 |
n = d.getElementsByTagName('head')[0];
|
|
85 |
if (n) {
|
|
86 |
nl = n.getElementsByTagName('script');
|
|
87 |
for (i=0; i<nl.length; i++) {
|
|
88 |
if (getBase(nl[i]))
|
|
89 |
return;
|
|
90 |
}
|
d9344f
|
91 |
}
|
69d05c
|
92 |
|
A |
93 |
return;
|
|
94 |
},
|
|
95 |
|
|
96 |
is : function(o, t) {
|
|
97 |
if (!t)
|
|
98 |
return o !== undefined;
|
|
99 |
|
|
100 |
if (t == 'array' && (o.hasOwnProperty && o instanceof Array))
|
|
101 |
return true;
|
|
102 |
|
|
103 |
return typeof(o) == t;
|
a9251b
|
104 |
},
|
T |
105 |
|
|
106 |
makeMap : function(items, delim, map) {
|
|
107 |
var i;
|
|
108 |
|
|
109 |
items = items || [];
|
|
110 |
delim = delim || ',';
|
|
111 |
|
|
112 |
if (typeof(items) == "string")
|
|
113 |
items = items.split(delim);
|
|
114 |
|
|
115 |
map = map || {};
|
|
116 |
|
|
117 |
i = items.length;
|
|
118 |
while (i--)
|
|
119 |
map[items[i]] = {};
|
|
120 |
|
|
121 |
return map;
|
69d05c
|
122 |
},
|
A |
123 |
|
|
124 |
each : function(o, cb, s) {
|
|
125 |
var n, l;
|
|
126 |
|
|
127 |
if (!o)
|
|
128 |
return 0;
|
|
129 |
|
|
130 |
s = s || o;
|
|
131 |
|
|
132 |
if (o.length !== undefined) {
|
|
133 |
// Indexed arrays, needed for Safari
|
|
134 |
for (n=0, l = o.length; n < l; n++) {
|
d9344f
|
135 |
if (cb.call(s, o[n], n, o) === false)
|
S |
136 |
return 0;
|
|
137 |
}
|
|
138 |
} else {
|
69d05c
|
139 |
// Hashtables
|
A |
140 |
for (n in o) {
|
|
141 |
if (o.hasOwnProperty(n)) {
|
|
142 |
if (cb.call(s, o[n], n, o) === false)
|
|
143 |
return 0;
|
|
144 |
}
|
|
145 |
}
|
d9344f
|
146 |
}
|
S |
147 |
|
69d05c
|
148 |
return 1;
|
A |
149 |
},
|
|
150 |
|
|
151 |
|
|
152 |
map : function(a, f) {
|
|
153 |
var o = [];
|
|
154 |
|
|
155 |
tinymce.each(a, function(v) {
|
|
156 |
o.push(f(v));
|
d9344f
|
157 |
});
|
S |
158 |
|
69d05c
|
159 |
return o;
|
A |
160 |
},
|
|
161 |
|
|
162 |
grep : function(a, f) {
|
|
163 |
var o = [];
|
|
164 |
|
|
165 |
tinymce.each(a, function(v) {
|
|
166 |
if (!f || f(v))
|
|
167 |
o.push(v);
|
|
168 |
});
|
|
169 |
|
|
170 |
return o;
|
|
171 |
},
|
|
172 |
|
|
173 |
inArray : function(a, v) {
|
|
174 |
var i, l;
|
|
175 |
|
|
176 |
if (a) {
|
|
177 |
for (i = 0, l = a.length; i < l; i++) {
|
|
178 |
if (a[i] === v)
|
|
179 |
return i;
|
|
180 |
}
|
|
181 |
}
|
|
182 |
|
|
183 |
return -1;
|
|
184 |
},
|
|
185 |
|
|
186 |
extend : function(o, e) {
|
|
187 |
var i, l, a = arguments;
|
|
188 |
|
|
189 |
for (i = 1, l = a.length; i < l; i++) {
|
|
190 |
e = a[i];
|
|
191 |
|
|
192 |
tinymce.each(e, function(v, n) {
|
|
193 |
if (v !== undefined)
|
|
194 |
o[n] = v;
|
|
195 |
});
|
|
196 |
}
|
|
197 |
|
|
198 |
return o;
|
|
199 |
},
|
|
200 |
|
|
201 |
|
|
202 |
trim : function(s) {
|
|
203 |
return (s ? '' + s : '').replace(whiteSpaceRe, '');
|
|
204 |
},
|
|
205 |
|
a9251b
|
206 |
create : function(s, p, root) {
|
69d05c
|
207 |
var t = this, sp, ns, cn, scn, c, de = 0;
|
A |
208 |
|
|
209 |
// Parse : <prefix> <class>:<super class>
|
|
210 |
s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
|
|
211 |
cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name
|
|
212 |
|
|
213 |
// Create namespace for new class
|
a9251b
|
214 |
ns = t.createNS(s[3].replace(/\.\w+$/, ''), root);
|
69d05c
|
215 |
|
A |
216 |
// Class already exists
|
|
217 |
if (ns[cn])
|
|
218 |
return;
|
|
219 |
|
|
220 |
// Make pure static class
|
|
221 |
if (s[2] == 'static') {
|
|
222 |
ns[cn] = p;
|
|
223 |
|
|
224 |
if (this.onCreate)
|
|
225 |
this.onCreate(s[2], s[3], ns[cn]);
|
|
226 |
|
|
227 |
return;
|
|
228 |
}
|
|
229 |
|
|
230 |
// Create default constructor
|
|
231 |
if (!p[cn]) {
|
|
232 |
p[cn] = function() {};
|
|
233 |
de = 1;
|
|
234 |
}
|
|
235 |
|
|
236 |
// Add constructor and methods
|
|
237 |
ns[cn] = p[cn];
|
|
238 |
t.extend(ns[cn].prototype, p);
|
|
239 |
|
|
240 |
// Extend
|
|
241 |
if (s[5]) {
|
|
242 |
sp = t.resolve(s[5]).prototype;
|
|
243 |
scn = s[5].match(/\.(\w+)$/i)[1]; // Class name
|
|
244 |
|
|
245 |
// Extend constructor
|
|
246 |
c = ns[cn];
|
|
247 |
if (de) {
|
|
248 |
// Add passthrough constructor
|
|
249 |
ns[cn] = function() {
|
|
250 |
return sp[scn].apply(this, arguments);
|
d9344f
|
251 |
};
|
S |
252 |
} else {
|
69d05c
|
253 |
// Add inherit constructor
|
A |
254 |
ns[cn] = function() {
|
|
255 |
this.parent = sp[scn];
|
|
256 |
return c.apply(this, arguments);
|
18240a
|
257 |
};
|
A |
258 |
}
|
69d05c
|
259 |
ns[cn].prototype[cn] = ns[cn];
|
d9344f
|
260 |
|
69d05c
|
261 |
// Add super methods
|
A |
262 |
t.each(sp, function(f, n) {
|
|
263 |
ns[cn].prototype[n] = sp[n];
|
|
264 |
});
|
d9344f
|
265 |
|
69d05c
|
266 |
// Add overridden methods
|
A |
267 |
t.each(p, function(f, n) {
|
|
268 |
// Extend methods if needed
|
|
269 |
if (sp[n]) {
|
|
270 |
ns[cn].prototype[n] = function() {
|
|
271 |
this.parent = sp[n];
|
|
272 |
return f.apply(this, arguments);
|
|
273 |
};
|
|
274 |
} else {
|
|
275 |
if (n != cn)
|
|
276 |
ns[cn].prototype[n] = f;
|
|
277 |
}
|
|
278 |
});
|
d9344f
|
279 |
}
|
S |
280 |
|
69d05c
|
281 |
// Add static methods
|
A |
282 |
t.each(p['static'], function(f, n) {
|
|
283 |
ns[cn][n] = f;
|
|
284 |
});
|
d9344f
|
285 |
|
69d05c
|
286 |
if (this.onCreate)
|
A |
287 |
this.onCreate(s[2], s[3], ns[cn].prototype);
|
|
288 |
},
|
18240a
|
289 |
|
69d05c
|
290 |
walk : function(o, f, n, s) {
|
A |
291 |
s = s || this;
|
18240a
|
292 |
|
69d05c
|
293 |
if (o) {
|
A |
294 |
if (n)
|
|
295 |
o = o[n];
|
18240a
|
296 |
|
69d05c
|
297 |
tinymce.each(o, function(o, i) {
|
A |
298 |
if (f.call(s, o, i, n) === false)
|
|
299 |
return false;
|
18240a
|
300 |
|
69d05c
|
301 |
tinymce.walk(o, f, n, s);
|
A |
302 |
});
|
|
303 |
}
|
|
304 |
},
|
18240a
|
305 |
|
69d05c
|
306 |
createNS : function(n, o) {
|
A |
307 |
var i, v;
|
d9344f
|
308 |
|
69d05c
|
309 |
o = o || win;
|
d9344f
|
310 |
|
69d05c
|
311 |
n = n.split('.');
|
A |
312 |
for (i=0; i<n.length; i++) {
|
|
313 |
v = n[i];
|
d9344f
|
314 |
|
69d05c
|
315 |
if (!o[v])
|
A |
316 |
o[v] = {};
|
|
317 |
|
|
318 |
o = o[v];
|
|
319 |
}
|
|
320 |
|
|
321 |
return o;
|
|
322 |
},
|
|
323 |
|
|
324 |
resolve : function(n, o) {
|
|
325 |
var i, l;
|
|
326 |
|
|
327 |
o = o || win;
|
|
328 |
|
|
329 |
n = n.split('.');
|
|
330 |
for (i = 0, l = n.length; i < l; i++) {
|
|
331 |
o = o[n[i]];
|
|
332 |
|
|
333 |
if (!o)
|
|
334 |
break;
|
|
335 |
}
|
|
336 |
|
|
337 |
return o;
|
|
338 |
},
|
|
339 |
|
|
340 |
addUnload : function(f, s) {
|
|
341 |
var t = this;
|
|
342 |
|
|
343 |
f = {func : f, scope : s || this};
|
|
344 |
|
|
345 |
if (!t.unloads) {
|
|
346 |
function unload() {
|
|
347 |
var li = t.unloads, o, n;
|
|
348 |
|
|
349 |
if (li) {
|
|
350 |
// Call unload handlers
|
|
351 |
for (n in li) {
|
|
352 |
o = li[n];
|
|
353 |
|
|
354 |
if (o && o.func)
|
|
355 |
o.func.call(o.scope, 1); // Send in one arg to distinct unload and user destroy
|
|
356 |
}
|
|
357 |
|
|
358 |
// Detach unload function
|
|
359 |
if (win.detachEvent) {
|
|
360 |
win.detachEvent('onbeforeunload', fakeUnload);
|
|
361 |
win.detachEvent('onunload', unload);
|
|
362 |
} else if (win.removeEventListener)
|
|
363 |
win.removeEventListener('unload', unload, false);
|
|
364 |
|
|
365 |
// Destroy references
|
|
366 |
t.unloads = o = li = w = unload = 0;
|
|
367 |
|
|
368 |
// Run garbarge collector on IE
|
|
369 |
if (win.CollectGarbage)
|
|
370 |
CollectGarbage();
|
|
371 |
}
|
|
372 |
};
|
|
373 |
|
|
374 |
function fakeUnload() {
|
|
375 |
var d = document;
|
|
376 |
|
|
377 |
// Is there things still loading, then do some magic
|
|
378 |
if (d.readyState == 'interactive') {
|
|
379 |
function stop() {
|
|
380 |
// Prevent memory leak
|
|
381 |
d.detachEvent('onstop', stop);
|
|
382 |
|
|
383 |
// Call unload handler
|
|
384 |
if (unload)
|
|
385 |
unload();
|
|
386 |
|
|
387 |
d = 0;
|
|
388 |
};
|
|
389 |
|
|
390 |
// Fire unload when the currently loading page is stopped
|
|
391 |
if (d)
|
|
392 |
d.attachEvent('onstop', stop);
|
|
393 |
|
|
394 |
// Remove onstop listener after a while to prevent the unload function
|
|
395 |
// to execute if the user presses cancel in an onbeforeunload
|
|
396 |
// confirm dialog and then presses the browser stop button
|
|
397 |
win.setTimeout(function() {
|
|
398 |
if (d)
|
|
399 |
d.detachEvent('onstop', stop);
|
|
400 |
}, 0);
|
|
401 |
}
|
|
402 |
};
|
|
403 |
|
|
404 |
// Attach unload handler
|
|
405 |
if (win.attachEvent) {
|
|
406 |
win.attachEvent('onunload', unload);
|
|
407 |
win.attachEvent('onbeforeunload', fakeUnload);
|
|
408 |
} else if (win.addEventListener)
|
|
409 |
win.addEventListener('unload', unload, false);
|
|
410 |
|
|
411 |
// Setup initial unload handler array
|
|
412 |
t.unloads = [f];
|
|
413 |
} else
|
|
414 |
t.unloads.push(f);
|
|
415 |
|
|
416 |
return f;
|
|
417 |
},
|
|
418 |
|
|
419 |
removeUnload : function(f) {
|
|
420 |
var u = this.unloads, r = null;
|
|
421 |
|
|
422 |
tinymce.each(u, function(o, i) {
|
|
423 |
if (o && o.func == f) {
|
|
424 |
u.splice(i, 1);
|
|
425 |
r = f;
|
|
426 |
return false;
|
|
427 |
}
|
|
428 |
});
|
|
429 |
|
|
430 |
return r;
|
|
431 |
},
|
|
432 |
|
|
433 |
explode : function(s, d) {
|
|
434 |
return s ? tinymce.map(s.split(d || ','), tinymce.trim) : s;
|
|
435 |
},
|
|
436 |
|
|
437 |
_addVer : function(u) {
|
|
438 |
var v;
|
|
439 |
|
|
440 |
if (!this.query)
|
|
441 |
return u;
|
|
442 |
|
|
443 |
v = (u.indexOf('?') == -1 ? '?' : '&') + this.query;
|
|
444 |
|
|
445 |
if (u.indexOf('#') == -1)
|
|
446 |
return u + v;
|
|
447 |
|
|
448 |
return u.replace('#', v + '#');
|
a9251b
|
449 |
},
|
T |
450 |
|
|
451 |
// Fix function for IE 9 where regexps isn't working correctly
|
|
452 |
// Todo: remove me once MS fixes the bug
|
|
453 |
_replace : function(find, replace, str) {
|
|
454 |
// On IE9 we have to fake $x replacement
|
|
455 |
if (isRegExpBroken) {
|
|
456 |
return str.replace(find, function() {
|
|
457 |
var val = replace, args = arguments, i;
|
|
458 |
|
|
459 |
for (i = 0; i < args.length - 2; i++) {
|
|
460 |
if (args[i] === undefined) {
|
|
461 |
val = val.replace(new RegExp('\\$' + i, 'g'), '');
|
|
462 |
} else {
|
|
463 |
val = val.replace(new RegExp('\\$' + i, 'g'), args[i]);
|
|
464 |
}
|
|
465 |
}
|
|
466 |
|
|
467 |
return val;
|
|
468 |
});
|
|
469 |
}
|
|
470 |
|
|
471 |
return str.replace(find, replace);
|
69d05c
|
472 |
}
|
A |
473 |
|
|
474 |
};
|
|
475 |
|
|
476 |
// Initialize the API
|
|
477 |
tinymce._init();
|
|
478 |
|
|
479 |
// Expose tinymce namespace to the global namespace (window)
|
|
480 |
win.tinymce = win.tinyMCE = tinymce;
|
a9251b
|
481 |
|
T |
482 |
// Describe the different namespaces
|
|
483 |
|
|
484 |
})(window);
|
69d05c
|
485 |
|
A |
486 |
|
d9344f
|
487 |
tinymce.create('tinymce.util.Dispatcher', {
|
S |
488 |
scope : null,
|
|
489 |
listeners : null,
|
|
490 |
|
|
491 |
Dispatcher : function(s) {
|
|
492 |
this.scope = s || this;
|
|
493 |
this.listeners = [];
|
|
494 |
},
|
|
495 |
|
|
496 |
add : function(cb, s) {
|
|
497 |
this.listeners.push({cb : cb, scope : s || this.scope});
|
|
498 |
|
|
499 |
return cb;
|
|
500 |
},
|
|
501 |
|
|
502 |
addToTop : function(cb, s) {
|
|
503 |
this.listeners.unshift({cb : cb, scope : s || this.scope});
|
|
504 |
|
|
505 |
return cb;
|
|
506 |
},
|
|
507 |
|
|
508 |
remove : function(cb) {
|
|
509 |
var l = this.listeners, o = null;
|
|
510 |
|
|
511 |
tinymce.each(l, function(c, i) {
|
|
512 |
if (cb == c.cb) {
|
|
513 |
o = cb;
|
|
514 |
l.splice(i, 1);
|
|
515 |
return false;
|
|
516 |
}
|
|
517 |
});
|
|
518 |
|
|
519 |
return o;
|
|
520 |
},
|
|
521 |
|
|
522 |
dispatch : function() {
|
|
523 |
var s, a = arguments, i, li = this.listeners, c;
|
|
524 |
|
|
525 |
// Needs to be a real loop since the listener count might change while looping
|
|
526 |
// And this is also more efficient
|
|
527 |
for (i = 0; i<li.length; i++) {
|
|
528 |
c = li[i];
|
|
529 |
s = c.cb.apply(c.scope, a);
|
|
530 |
|
|
531 |
if (s === false)
|
|
532 |
break;
|
|
533 |
}
|
|
534 |
|
|
535 |
return s;
|
|
536 |
}
|
|
537 |
|
|
538 |
});
|
69d05c
|
539 |
|
d9344f
|
540 |
(function() {
|
S |
541 |
var each = tinymce.each;
|
|
542 |
|
|
543 |
tinymce.create('tinymce.util.URI', {
|
|
544 |
URI : function(u, s) {
|
|
545 |
var t = this, o, a, b;
|
|
546 |
|
58fb65
|
547 |
// Trim whitespace
|
A |
548 |
u = tinymce.trim(u);
|
|
549 |
|
d9344f
|
550 |
// Default settings
|
S |
551 |
s = t.settings = s || {};
|
|
552 |
|
|
553 |
// Strange app protocol or local anchor
|
58fb65
|
554 |
if (/^(mailto|tel|news|javascript|about|data):/i.test(u) || /^\s*#/.test(u)) {
|
d9344f
|
555 |
t.source = u;
|
S |
556 |
return;
|
|
557 |
}
|
|
558 |
|
|
559 |
// Absolute path with no host, fake host and protocol
|
|
560 |
if (u.indexOf('/') === 0 && u.indexOf('//') !== 0)
|
|
561 |
u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u;
|
|
562 |
|
58fb65
|
563 |
// Relative path http:// or protocol relative //path
|
A |
564 |
if (!/^\w*:?\/\//.test(u))
|
d9344f
|
565 |
u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u);
|
S |
566 |
|
|
567 |
// Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
|
|
568 |
u = u.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something
|
|
569 |
u = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(u);
|
|
570 |
each(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], function(v, i) {
|
|
571 |
var s = u[i];
|
|
572 |
|
|
573 |
// Zope 3 workaround, they use @@something
|
|
574 |
if (s)
|
|
575 |
s = s.replace(/\(mce_at\)/g, '@@');
|
|
576 |
|
|
577 |
t[v] = s;
|
|
578 |
});
|
|
579 |
|
|
580 |
if (b = s.base_uri) {
|
|
581 |
if (!t.protocol)
|
|
582 |
t.protocol = b.protocol;
|
|
583 |
|
|
584 |
if (!t.userInfo)
|
|
585 |
t.userInfo = b.userInfo;
|
|
586 |
|
|
587 |
if (!t.port && t.host == 'mce_host')
|
|
588 |
t.port = b.port;
|
|
589 |
|
|
590 |
if (!t.host || t.host == 'mce_host')
|
|
591 |
t.host = b.host;
|
|
592 |
|
|
593 |
t.source = '';
|
|
594 |
}
|
|
595 |
|
|
596 |
//t.path = t.path || '/';
|
|
597 |
},
|
|
598 |
|
|
599 |
setPath : function(p) {
|
|
600 |
var t = this;
|
|
601 |
|
|
602 |
p = /^(.*?)\/?(\w+)?$/.exec(p);
|
|
603 |
|
|
604 |
// Update path parts
|
|
605 |
t.path = p[0];
|
|
606 |
t.directory = p[1];
|
|
607 |
t.file = p[2];
|
|
608 |
|
|
609 |
// Rebuild source
|
|
610 |
t.source = '';
|
|
611 |
t.getURI();
|
|
612 |
},
|
|
613 |
|
|
614 |
toRelative : function(u) {
|
|
615 |
var t = this, o;
|
|
616 |
|
29da64
|
617 |
if (u === "./")
|
A |
618 |
return u;
|
|
619 |
|
d9344f
|
620 |
u = new tinymce.util.URI(u, {base_uri : t});
|
S |
621 |
|
|
622 |
// Not on same domain/port or protocol
|
|
623 |
if ((u.host != 'mce_host' && t.host != u.host && u.host) || t.port != u.port || t.protocol != u.protocol)
|
|
624 |
return u.getURI();
|
|
625 |
|
|
626 |
o = t.toRelPath(t.path, u.path);
|
|
627 |
|
|
628 |
// Add query
|
|
629 |
if (u.query)
|
|
630 |
o += '?' + u.query;
|
|
631 |
|
|
632 |
// Add anchor
|
|
633 |
if (u.anchor)
|
|
634 |
o += '#' + u.anchor;
|
|
635 |
|
|
636 |
return o;
|
|
637 |
},
|
|
638 |
|
|
639 |
toAbsolute : function(u, nh) {
|
|
640 |
var u = new tinymce.util.URI(u, {base_uri : this});
|
|
641 |
|
58fb65
|
642 |
return u.getURI(this.host == u.host && this.protocol == u.protocol ? nh : 0);
|
d9344f
|
643 |
},
|
S |
644 |
|
|
645 |
toRelPath : function(base, path) {
|
29da64
|
646 |
var items, bp = 0, out = '', i, l;
|
d9344f
|
647 |
|
S |
648 |
// Split the paths
|
|
649 |
base = base.substring(0, base.lastIndexOf('/'));
|
|
650 |
base = base.split('/');
|
|
651 |
items = path.split('/');
|
|
652 |
|
|
653 |
if (base.length >= items.length) {
|
29da64
|
654 |
for (i = 0, l = base.length; i < l; i++) {
|
d9344f
|
655 |
if (i >= items.length || base[i] != items[i]) {
|
S |
656 |
bp = i + 1;
|
|
657 |
break;
|
|
658 |
}
|
|
659 |
}
|
|
660 |
}
|
|
661 |
|
|
662 |
if (base.length < items.length) {
|
29da64
|
663 |
for (i = 0, l = items.length; i < l; i++) {
|
d9344f
|
664 |
if (i >= base.length || base[i] != items[i]) {
|
S |
665 |
bp = i + 1;
|
|
666 |
break;
|
|
667 |
}
|
|
668 |
}
|
|
669 |
}
|
|
670 |
|
|
671 |
if (bp == 1)
|
|
672 |
return path;
|
|
673 |
|
29da64
|
674 |
for (i = 0, l = base.length - (bp - 1); i < l; i++)
|
d9344f
|
675 |
out += "../";
|
S |
676 |
|
29da64
|
677 |
for (i = bp - 1, l = items.length; i < l; i++) {
|
d9344f
|
678 |
if (i != bp - 1)
|
S |
679 |
out += "/" + items[i];
|
|
680 |
else
|
|
681 |
out += items[i];
|
|
682 |
}
|
|
683 |
|
|
684 |
return out;
|
|
685 |
},
|
|
686 |
|
|
687 |
toAbsPath : function(base, path) {
|
58fb65
|
688 |
var i, nb = 0, o = [], tr, outPath;
|
d9344f
|
689 |
|
S |
690 |
// Split paths
|
29da64
|
691 |
tr = /\/$/.test(path) ? '/' : '';
|
d9344f
|
692 |
base = base.split('/');
|
S |
693 |
path = path.split('/');
|
|
694 |
|
|
695 |
// Remove empty chunks
|
|
696 |
each(base, function(k) {
|
|
697 |
if (k)
|
|
698 |
o.push(k);
|
|
699 |
});
|
|
700 |
|
|
701 |
base = o;
|
|
702 |
|
|
703 |
// Merge relURLParts chunks
|
|
704 |
for (i = path.length - 1, o = []; i >= 0; i--) {
|
|
705 |
// Ignore empty or .
|
|
706 |
if (path[i].length == 0 || path[i] == ".")
|
|
707 |
continue;
|
|
708 |
|
|
709 |
// Is parent
|
|
710 |
if (path[i] == '..') {
|
|
711 |
nb++;
|
|
712 |
continue;
|
|
713 |
}
|
|
714 |
|
|
715 |
// Move up
|
|
716 |
if (nb > 0) {
|
|
717 |
nb--;
|
|
718 |
continue;
|
|
719 |
}
|
|
720 |
|
|
721 |
o.push(path[i]);
|
|
722 |
}
|
|
723 |
|
|
724 |
i = base.length - nb;
|
|
725 |
|
|
726 |
// If /a/b/c or /
|
|
727 |
if (i <= 0)
|
58fb65
|
728 |
outPath = o.reverse().join('/');
|
A |
729 |
else
|
|
730 |
outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/');
|
d9344f
|
731 |
|
58fb65
|
732 |
// Add front / if it's needed
|
A |
733 |
if (outPath.indexOf('/') !== 0)
|
|
734 |
outPath = '/' + outPath;
|
|
735 |
|
|
736 |
// Add traling / if it's needed
|
|
737 |
if (tr && outPath.lastIndexOf('/') !== outPath.length - 1)
|
|
738 |
outPath += tr;
|
|
739 |
|
|
740 |
return outPath;
|
d9344f
|
741 |
},
|
S |
742 |
|
|
743 |
getURI : function(nh) {
|
|
744 |
var s, t = this;
|
|
745 |
|
|
746 |
// Rebuild source
|
|
747 |
if (!t.source || nh) {
|
|
748 |
s = '';
|
|
749 |
|
|
750 |
if (!nh) {
|
|
751 |
if (t.protocol)
|
|
752 |
s += t.protocol + '://';
|
|
753 |
|
|
754 |
if (t.userInfo)
|
|
755 |
s += t.userInfo + '@';
|
|
756 |
|
|
757 |
if (t.host)
|
|
758 |
s += t.host;
|
|
759 |
|
|
760 |
if (t.port)
|
|
761 |
s += ':' + t.port;
|
|
762 |
}
|
|
763 |
|
|
764 |
if (t.path)
|
|
765 |
s += t.path;
|
|
766 |
|
|
767 |
if (t.query)
|
|
768 |
s += '?' + t.query;
|
|
769 |
|
|
770 |
if (t.anchor)
|
|
771 |
s += '#' + t.anchor;
|
|
772 |
|
|
773 |
t.source = s;
|
|
774 |
}
|
|
775 |
|
|
776 |
return t.source;
|
|
777 |
}
|
58fb65
|
778 |
});
|
d9344f
|
779 |
})();
|
69d05c
|
780 |
|
d9344f
|
781 |
(function() {
|
S |
782 |
var each = tinymce.each;
|
|
783 |
|
|
784 |
tinymce.create('static tinymce.util.Cookie', {
|
|
785 |
getHash : function(n) {
|
|
786 |
var v = this.get(n), h;
|
|
787 |
|
|
788 |
if (v) {
|
|
789 |
each(v.split('&'), function(v) {
|
|
790 |
v = v.split('=');
|
|
791 |
h = h || {};
|
|
792 |
h[unescape(v[0])] = unescape(v[1]);
|
|
793 |
});
|
|
794 |
}
|
|
795 |
|
|
796 |
return h;
|
|
797 |
},
|
|
798 |
|
|
799 |
setHash : function(n, v, e, p, d, s) {
|
|
800 |
var o = '';
|
|
801 |
|
|
802 |
each(v, function(v, k) {
|
|
803 |
o += (!o ? '' : '&') + escape(k) + '=' + escape(v);
|
|
804 |
});
|
|
805 |
|
|
806 |
this.set(n, o, e, p, d, s);
|
|
807 |
},
|
|
808 |
|
|
809 |
get : function(n) {
|
|
810 |
var c = document.cookie, e, p = n + "=", b;
|
|
811 |
|
|
812 |
// Strict mode
|
|
813 |
if (!c)
|
|
814 |
return;
|
|
815 |
|
|
816 |
b = c.indexOf("; " + p);
|
|
817 |
|
|
818 |
if (b == -1) {
|
|
819 |
b = c.indexOf(p);
|
|
820 |
|
|
821 |
if (b != 0)
|
|
822 |
return null;
|
|
823 |
} else
|
|
824 |
b += 2;
|
|
825 |
|
|
826 |
e = c.indexOf(";", b);
|
|
827 |
|
|
828 |
if (e == -1)
|
|
829 |
e = c.length;
|
|
830 |
|
|
831 |
return unescape(c.substring(b + p.length, e));
|
|
832 |
},
|
|
833 |
|
|
834 |
set : function(n, v, e, p, d, s) {
|
|
835 |
document.cookie = n + "=" + escape(v) +
|
|
836 |
((e) ? "; expires=" + e.toGMTString() : "") +
|
|
837 |
((p) ? "; path=" + escape(p) : "") +
|
|
838 |
((d) ? "; domain=" + d : "") +
|
|
839 |
((s) ? "; secure" : "");
|
|
840 |
},
|
|
841 |
|
|
842 |
remove : function(n, p) {
|
|
843 |
var d = new Date();
|
|
844 |
|
|
845 |
d.setTime(d.getTime() - 1000);
|
|
846 |
|
|
847 |
this.set(n, '', d, p, d);
|
|
848 |
}
|
58fb65
|
849 |
});
|
d9344f
|
850 |
})();
|
69d05c
|
851 |
|
a9251b
|
852 |
(function() {
|
T |
853 |
function serialize(o, quote) {
|
|
854 |
var i, v, t;
|
|
855 |
|
|
856 |
quote = quote || '"';
|
d9344f
|
857 |
|
S |
858 |
if (o == null)
|
|
859 |
return 'null';
|
|
860 |
|
|
861 |
t = typeof o;
|
|
862 |
|
|
863 |
if (t == 'string') {
|
|
864 |
v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
|
|
865 |
|
a9251b
|
866 |
return quote + o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g, function(a, b) {
|
T |
867 |
// Make sure single quotes never get encoded inside double quotes for JSON compatibility
|
|
868 |
if (quote === '"' && a === "'")
|
|
869 |
return a;
|
|
870 |
|
d9344f
|
871 |
i = v.indexOf(b);
|
S |
872 |
|
|
873 |
if (i + 1)
|
|
874 |
return '\\' + v.charAt(i + 1);
|
|
875 |
|
|
876 |
a = b.charCodeAt().toString(16);
|
|
877 |
|
|
878 |
return '\\u' + '0000'.substring(a.length) + a;
|
a9251b
|
879 |
}) + quote;
|
d9344f
|
880 |
}
|
S |
881 |
|
|
882 |
if (t == 'object') {
|
29da64
|
883 |
if (o.hasOwnProperty && o instanceof Array) {
|
d9344f
|
884 |
for (i=0, v = '['; i<o.length; i++)
|
a9251b
|
885 |
v += (i > 0 ? ',' : '') + serialize(o[i], quote);
|
d9344f
|
886 |
|
S |
887 |
return v + ']';
|
|
888 |
}
|
|
889 |
|
|
890 |
v = '{';
|
|
891 |
|
|
892 |
for (i in o)
|
a9251b
|
893 |
v += typeof o[i] != 'function' ? (v.length > 1 ? ',' + quote : quote) + i + quote +':' + serialize(o[i], quote) : '';
|
d9344f
|
894 |
|
S |
895 |
return v + '}';
|
|
896 |
}
|
|
897 |
|
|
898 |
return '' + o;
|
a9251b
|
899 |
};
|
d9344f
|
900 |
|
a9251b
|
901 |
tinymce.util.JSON = {
|
T |
902 |
serialize: serialize,
|
|
903 |
|
|
904 |
parse: function(s) {
|
|
905 |
try {
|
|
906 |
return eval('(' + s + ')');
|
|
907 |
} catch (ex) {
|
|
908 |
// Ignore
|
|
909 |
}
|
d9344f
|
910 |
}
|
S |
911 |
|
a9251b
|
912 |
};
|
T |
913 |
})();
|
d9344f
|
914 |
tinymce.create('static tinymce.util.XHR', {
|
S |
915 |
send : function(o) {
|
|
916 |
var x, t, w = window, c = 0;
|
|
917 |
|
|
918 |
// Default settings
|
|
919 |
o.scope = o.scope || this;
|
|
920 |
o.success_scope = o.success_scope || o.scope;
|
|
921 |
o.error_scope = o.error_scope || o.scope;
|
|
922 |
o.async = o.async === false ? false : true;
|
|
923 |
o.data = o.data || '';
|
|
924 |
|
|
925 |
function get(s) {
|
|
926 |
x = 0;
|
|
927 |
|
|
928 |
try {
|
|
929 |
x = new ActiveXObject(s);
|
|
930 |
} catch (ex) {
|
|
931 |
}
|
|
932 |
|
|
933 |
return x;
|
|
934 |
};
|
|
935 |
|
|
936 |
x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP');
|
|
937 |
|
|
938 |
if (x) {
|
|
939 |
if (x.overrideMimeType)
|
|
940 |
x.overrideMimeType(o.content_type);
|
|
941 |
|
|
942 |
x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async);
|
|
943 |
|
|
944 |
if (o.content_type)
|
|
945 |
x.setRequestHeader('Content-Type', o.content_type);
|
|
946 |
|
58fb65
|
947 |
x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
A |
948 |
|
d9344f
|
949 |
x.send(o.data);
|
S |
950 |
|
18240a
|
951 |
function ready() {
|
A |
952 |
if (!o.async || x.readyState == 4 || c++ > 10000) {
|
d9344f
|
953 |
if (o.success && c < 10000 && x.status == 200)
|
S |
954 |
o.success.call(o.success_scope, '' + x.responseText, x, o);
|
|
955 |
else if (o.error)
|
|
956 |
o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o);
|
|
957 |
|
|
958 |
x = null;
|
18240a
|
959 |
} else
|
A |
960 |
w.setTimeout(ready, 10);
|
|
961 |
};
|
|
962 |
|
|
963 |
// Syncronous request
|
|
964 |
if (!o.async)
|
|
965 |
return ready();
|
|
966 |
|
|
967 |
// Wait for response, onReadyStateChange can not be used since it leaks memory in IE
|
|
968 |
t = w.setTimeout(ready, 10);
|
d9344f
|
969 |
}
|
58fb65
|
970 |
}
|
d9344f
|
971 |
});
|
69d05c
|
972 |
|
d9344f
|
973 |
(function() {
|
S |
974 |
var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR;
|
|
975 |
|
|
976 |
tinymce.create('tinymce.util.JSONRequest', {
|
|
977 |
JSONRequest : function(s) {
|
|
978 |
this.settings = extend({
|
|
979 |
}, s);
|
|
980 |
this.count = 0;
|
|
981 |
},
|
|
982 |
|
|
983 |
send : function(o) {
|
|
984 |
var ecb = o.error, scb = o.success;
|
|
985 |
|
|
986 |
o = extend(this.settings, o);
|
|
987 |
|
|
988 |
o.success = function(c, x) {
|
|
989 |
c = JSON.parse(c);
|
|
990 |
|
|
991 |
if (typeof(c) == 'undefined') {
|
|
992 |
c = {
|
|
993 |
error : 'JSON Parse error.'
|
|
994 |
};
|
|
995 |
}
|
|
996 |
|
|
997 |
if (c.error)
|
|
998 |
ecb.call(o.error_scope || o.scope, c.error, x);
|
|
999 |
else
|
|
1000 |
scb.call(o.success_scope || o.scope, c.result);
|
|
1001 |
};
|
|
1002 |
|
|
1003 |
o.error = function(ty, x) {
|
a9251b
|
1004 |
if (ecb)
|
T |
1005 |
ecb.call(o.error_scope || o.scope, ty, x);
|
d9344f
|
1006 |
};
|
S |
1007 |
|
|
1008 |
o.data = JSON.serialize({
|
|
1009 |
id : o.id || 'c' + (this.count++),
|
|
1010 |
method : o.method,
|
|
1011 |
params : o.params
|
|
1012 |
});
|
|
1013 |
|
|
1014 |
// JSON content type for Ruby on rails. Bug: #1883287
|
|
1015 |
o.content_type = 'application/json';
|
|
1016 |
|
|
1017 |
XHR.send(o);
|
|
1018 |
},
|
|
1019 |
|
|
1020 |
'static' : {
|
|
1021 |
sendRPC : function(o) {
|
|
1022 |
return new tinymce.util.JSONRequest().send(o);
|
|
1023 |
}
|
|
1024 |
}
|
58fb65
|
1025 |
});
|
69d05c
|
1026 |
}());
|
A |
1027 |
(function(tinymce) {
|
a9251b
|
1028 |
var namedEntities, baseEntities, reverseEntities,
|
T |
1029 |
attrsCharsRegExp = /[&\"\u007E-\uD7FF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
|
|
1030 |
textCharsRegExp = /[<>&\u007E-\uD7FF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
|
|
1031 |
rawCharsRegExp = /[<>&\"\']/g,
|
|
1032 |
entityRegExp = /&(#)?([\w]+);/g,
|
|
1033 |
asciiMap = {
|
|
1034 |
128 : "\u20AC", 130 : "\u201A", 131 : "\u0192", 132 : "\u201E", 133 : "\u2026", 134 : "\u2020",
|
|
1035 |
135 : "\u2021", 136 : "\u02C6", 137 : "\u2030", 138 : "\u0160", 139 : "\u2039", 140 : "\u0152",
|
|
1036 |
142 : "\u017D", 145 : "\u2018", 146 : "\u2019", 147 : "\u201C", 148 : "\u201D", 149 : "\u2022",
|
|
1037 |
150 : "\u2013", 151 : "\u2014", 152 : "\u02DC", 153 : "\u2122", 154 : "\u0161", 155 : "\u203A",
|
|
1038 |
156 : "\u0153", 158 : "\u017E", 159 : "\u0178"
|
|
1039 |
};
|
|
1040 |
|
|
1041 |
// Raw entities
|
|
1042 |
baseEntities = {
|
|
1043 |
'"' : '"',
|
|
1044 |
"'" : ''',
|
|
1045 |
'<' : '<',
|
|
1046 |
'>' : '>',
|
|
1047 |
'&' : '&'
|
|
1048 |
};
|
|
1049 |
|
|
1050 |
// Reverse lookup table for raw entities
|
|
1051 |
reverseEntities = {
|
|
1052 |
'<' : '<',
|
|
1053 |
'>' : '>',
|
|
1054 |
'&' : '&',
|
|
1055 |
'"' : '"',
|
|
1056 |
''' : "'"
|
|
1057 |
};
|
|
1058 |
|
|
1059 |
// Decodes text by using the browser
|
|
1060 |
function nativeDecode(text) {
|
|
1061 |
var elm;
|
|
1062 |
|
|
1063 |
elm = document.createElement("div");
|
|
1064 |
elm.innerHTML = text;
|
|
1065 |
|
|
1066 |
return elm.textContent || elm.innerText || text;
|
|
1067 |
};
|
|
1068 |
|
|
1069 |
// Build a two way lookup table for the entities
|
|
1070 |
function buildEntitiesLookup(items, radix) {
|
|
1071 |
var i, chr, entity, lookup = {};
|
|
1072 |
|
|
1073 |
if (items) {
|
|
1074 |
items = items.split(',');
|
|
1075 |
radix = radix || 10;
|
|
1076 |
|
|
1077 |
// Build entities lookup table
|
|
1078 |
for (i = 0; i < items.length; i += 2) {
|
|
1079 |
chr = String.fromCharCode(parseInt(items[i], radix));
|
|
1080 |
|
|
1081 |
// Only add non base entities
|
|
1082 |
if (!baseEntities[chr]) {
|
|
1083 |
entity = '&' + items[i + 1] + ';';
|
|
1084 |
lookup[chr] = entity;
|
|
1085 |
lookup[entity] = chr;
|
|
1086 |
}
|
|
1087 |
}
|
|
1088 |
|
|
1089 |
return lookup;
|
|
1090 |
}
|
|
1091 |
};
|
|
1092 |
|
|
1093 |
// Unpack entities lookup where the numbers are in radix 32 to reduce the size
|
|
1094 |
namedEntities = buildEntitiesLookup(
|
|
1095 |
'50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' +
|
|
1096 |
'5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' +
|
|
1097 |
'5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' +
|
|
1098 |
'5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' +
|
|
1099 |
'68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' +
|
|
1100 |
'6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' +
|
|
1101 |
'6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' +
|
|
1102 |
'75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' +
|
|
1103 |
'7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' +
|
|
1104 |
'7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' +
|
|
1105 |
'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' +
|
|
1106 |
'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' +
|
|
1107 |
't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' +
|
|
1108 |
'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' +
|
|
1109 |
'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' +
|
|
1110 |
'81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' +
|
|
1111 |
'8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' +
|
|
1112 |
'8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' +
|
|
1113 |
'8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' +
|
|
1114 |
'8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' +
|
|
1115 |
'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' +
|
|
1116 |
'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' +
|
|
1117 |
'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' +
|
|
1118 |
'80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' +
|
|
1119 |
'811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro'
|
|
1120 |
, 32);
|
|
1121 |
|
|
1122 |
tinymce.html = tinymce.html || {};
|
|
1123 |
|
|
1124 |
tinymce.html.Entities = {
|
|
1125 |
encodeRaw : function(text, attr) {
|
|
1126 |
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
|
|
1127 |
return baseEntities[chr] || chr;
|
|
1128 |
});
|
|
1129 |
},
|
|
1130 |
|
|
1131 |
encodeAllRaw : function(text) {
|
|
1132 |
return ('' + text).replace(rawCharsRegExp, function(chr) {
|
|
1133 |
return baseEntities[chr] || chr;
|
|
1134 |
});
|
|
1135 |
},
|
|
1136 |
|
|
1137 |
encodeNumeric : function(text, attr) {
|
|
1138 |
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
|
|
1139 |
// Multi byte sequence convert it to a single entity
|
|
1140 |
if (chr.length > 1)
|
|
1141 |
return '&#' + (((chr.charCodeAt(0) - 0xD800) * 0x400) + (chr.charCodeAt(1) - 0xDC00) + 0x10000) + ';';
|
|
1142 |
|
|
1143 |
return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
|
|
1144 |
});
|
|
1145 |
},
|
|
1146 |
|
|
1147 |
encodeNamed : function(text, attr, entities) {
|
|
1148 |
entities = entities || namedEntities;
|
|
1149 |
|
|
1150 |
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
|
|
1151 |
return baseEntities[chr] || entities[chr] || chr;
|
|
1152 |
});
|
|
1153 |
},
|
|
1154 |
|
|
1155 |
getEncodeFunc : function(name, entities) {
|
|
1156 |
var Entities = tinymce.html.Entities;
|
|
1157 |
|
|
1158 |
entities = buildEntitiesLookup(entities) || namedEntities;
|
|
1159 |
|
|
1160 |
function encodeNamedAndNumeric(text, attr) {
|
|
1161 |
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
|
|
1162 |
return baseEntities[chr] || entities[chr] || '&#' + chr.charCodeAt(0) + ';' || chr;
|
|
1163 |
});
|
|
1164 |
};
|
|
1165 |
|
|
1166 |
function encodeCustomNamed(text, attr) {
|
|
1167 |
return Entities.encodeNamed(text, attr, entities);
|
|
1168 |
};
|
|
1169 |
|
|
1170 |
// Replace + with , to be compatible with previous TinyMCE versions
|
|
1171 |
name = tinymce.makeMap(name.replace(/\+/g, ','));
|
|
1172 |
|
|
1173 |
// Named and numeric encoder
|
|
1174 |
if (name.named && name.numeric)
|
|
1175 |
return encodeNamedAndNumeric;
|
|
1176 |
|
|
1177 |
// Named encoder
|
|
1178 |
if (name.named) {
|
|
1179 |
// Custom names
|
|
1180 |
if (entities)
|
|
1181 |
return encodeCustomNamed;
|
|
1182 |
|
|
1183 |
return Entities.encodeNamed;
|
|
1184 |
}
|
|
1185 |
|
|
1186 |
// Numeric
|
|
1187 |
if (name.numeric)
|
|
1188 |
return Entities.encodeNumeric;
|
|
1189 |
|
|
1190 |
// Raw encoder
|
|
1191 |
return Entities.encodeRaw;
|
|
1192 |
},
|
|
1193 |
|
|
1194 |
decode : function(text) {
|
|
1195 |
return text.replace(entityRegExp, function(all, numeric, value) {
|
|
1196 |
if (numeric) {
|
|
1197 |
value = parseInt(value);
|
|
1198 |
|
|
1199 |
// Support upper UTF
|
|
1200 |
if (value > 0xFFFF) {
|
|
1201 |
value -= 0x10000;
|
|
1202 |
|
|
1203 |
return String.fromCharCode(0xD800 + (value >> 10), 0xDC00 + (value & 0x3FF));
|
|
1204 |
} else
|
|
1205 |
return asciiMap[value] || String.fromCharCode(value);
|
|
1206 |
}
|
|
1207 |
|
|
1208 |
return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
|
|
1209 |
});
|
|
1210 |
}
|
|
1211 |
};
|
|
1212 |
})(tinymce);
|
|
1213 |
|
|
1214 |
tinymce.html.Styles = function(settings, schema) {
|
|
1215 |
var rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,
|
|
1216 |
urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,
|
|
1217 |
styleRegExp = /\s*([^:]+):\s*([^;]+);?/g,
|
|
1218 |
trimRightRegExp = /\s+$/,
|
|
1219 |
urlColorRegExp = /rgb/,
|
|
1220 |
undef, i, encodingLookup = {}, encodingItems;
|
|
1221 |
|
|
1222 |
settings = settings || {};
|
|
1223 |
|
|
1224 |
encodingItems = '\\" \\\' \\; \\: ; : _'.split(' ');
|
|
1225 |
for (i = 0; i < encodingItems.length; i++) {
|
|
1226 |
encodingLookup[encodingItems[i]] = '_' + i;
|
|
1227 |
encodingLookup['_' + i] = encodingItems[i];
|
|
1228 |
}
|
|
1229 |
|
|
1230 |
function toHex(match, r, g, b) {
|
|
1231 |
function hex(val) {
|
|
1232 |
val = parseInt(val).toString(16);
|
|
1233 |
|
|
1234 |
return val.length > 1 ? val : '0' + val; // 0 -> 00
|
|
1235 |
};
|
|
1236 |
|
|
1237 |
return '#' + hex(r) + hex(g) + hex(b);
|
|
1238 |
};
|
|
1239 |
|
|
1240 |
return {
|
|
1241 |
toHex : function(color) {
|
|
1242 |
return color.replace(rgbRegExp, toHex);
|
|
1243 |
},
|
|
1244 |
|
|
1245 |
parse : function(css) {
|
|
1246 |
var styles = {}, matches, name, value, isEncoded, urlConverter = settings.url_converter, urlConverterScope = settings.url_converter_scope || this;
|
|
1247 |
|
|
1248 |
function compress(prefix, suffix) {
|
|
1249 |
var top, right, bottom, left;
|
|
1250 |
|
|
1251 |
// Get values and check it it needs compressing
|
|
1252 |
top = styles[prefix + '-top' + suffix];
|
|
1253 |
if (!top)
|
|
1254 |
return;
|
|
1255 |
|
|
1256 |
right = styles[prefix + '-right' + suffix];
|
|
1257 |
if (top != right)
|
|
1258 |
return;
|
|
1259 |
|
|
1260 |
bottom = styles[prefix + '-bottom' + suffix];
|
|
1261 |
if (right != bottom)
|
|
1262 |
return;
|
|
1263 |
|
|
1264 |
left = styles[prefix + '-left' + suffix];
|
|
1265 |
if (bottom != left)
|
|
1266 |
return;
|
|
1267 |
|
|
1268 |
// Compress
|
|
1269 |
styles[prefix + suffix] = left;
|
|
1270 |
delete styles[prefix + '-top' + suffix];
|
|
1271 |
delete styles[prefix + '-right' + suffix];
|
|
1272 |
delete styles[prefix + '-bottom' + suffix];
|
|
1273 |
delete styles[prefix + '-left' + suffix];
|
|
1274 |
};
|
|
1275 |
|
|
1276 |
function canCompress(key) {
|
|
1277 |
var value = styles[key], i;
|
|
1278 |
|
|
1279 |
if (!value || value.indexOf(' ') < 0)
|
|
1280 |
return;
|
|
1281 |
|
|
1282 |
value = value.split(' ');
|
|
1283 |
i = value.length;
|
|
1284 |
while (i--) {
|
|
1285 |
if (value[i] !== value[0])
|
|
1286 |
return false;
|
|
1287 |
}
|
|
1288 |
|
|
1289 |
styles[key] = value[0];
|
|
1290 |
|
|
1291 |
return true;
|
|
1292 |
};
|
|
1293 |
|
|
1294 |
function compress2(target, a, b, c) {
|
|
1295 |
if (!canCompress(a))
|
|
1296 |
return;
|
|
1297 |
|
|
1298 |
if (!canCompress(b))
|
|
1299 |
return;
|
|
1300 |
|
|
1301 |
if (!canCompress(c))
|
|
1302 |
return;
|
|
1303 |
|
|
1304 |
// Compress
|
|
1305 |
styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
|
|
1306 |
delete styles[a];
|
|
1307 |
delete styles[b];
|
|
1308 |
delete styles[c];
|
|
1309 |
};
|
|
1310 |
|
|
1311 |
// Encodes the specified string by replacing all \" \' ; : with _<num>
|
|
1312 |
function encode(str) {
|
|
1313 |
isEncoded = true;
|
|
1314 |
|
|
1315 |
return encodingLookup[str];
|
|
1316 |
};
|
|
1317 |
|
|
1318 |
// Decodes the specified string by replacing all _<num> with it's original value \" \' etc
|
|
1319 |
// It will also decode the \" \' if keep_slashes is set to fale or omitted
|
|
1320 |
function decode(str, keep_slashes) {
|
|
1321 |
if (isEncoded) {
|
|
1322 |
str = str.replace(/_[0-9]/g, function(str) {
|
|
1323 |
return encodingLookup[str];
|
|
1324 |
});
|
|
1325 |
}
|
|
1326 |
|
|
1327 |
if (!keep_slashes)
|
|
1328 |
str = str.replace(/\\([\'\";:])/g, "$1");
|
|
1329 |
|
|
1330 |
return str;
|
|
1331 |
}
|
|
1332 |
|
|
1333 |
if (css) {
|
|
1334 |
// Encode \" \' % and ; and : inside strings so they don't interfere with the style parsing
|
|
1335 |
css = css.replace(/\\[\"\';:_]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, function(str) {
|
|
1336 |
return str.replace(/[;:]/g, encode);
|
|
1337 |
});
|
|
1338 |
|
|
1339 |
// Parse styles
|
|
1340 |
while (matches = styleRegExp.exec(css)) {
|
|
1341 |
name = matches[1].replace(trimRightRegExp, '').toLowerCase();
|
|
1342 |
value = matches[2].replace(trimRightRegExp, '');
|
|
1343 |
|
|
1344 |
if (name && value.length > 0) {
|
|
1345 |
// Opera will produce 700 instead of bold in their style values
|
|
1346 |
if (name === 'font-weight' && value === '700')
|
|
1347 |
value = 'bold';
|
|
1348 |
else if (name === 'color' || name === 'background-color') // Lowercase colors like RED
|
|
1349 |
value = value.toLowerCase();
|
|
1350 |
|
|
1351 |
// Convert RGB colors to HEX
|
|
1352 |
value = value.replace(rgbRegExp, toHex);
|
|
1353 |
|
|
1354 |
// Convert URLs and force them into url('value') format
|
|
1355 |
value = value.replace(urlOrStrRegExp, function(match, url, url2, url3, str, str2) {
|
|
1356 |
str = str || str2;
|
|
1357 |
|
|
1358 |
if (str) {
|
|
1359 |
str = decode(str);
|
|
1360 |
|
|
1361 |
// Force strings into single quote format
|
|
1362 |
return "'" + str.replace(/\'/g, "\\'") + "'";
|
|
1363 |
}
|
|
1364 |
|
|
1365 |
url = decode(url || url2 || url3);
|
|
1366 |
|
|
1367 |
// Convert the URL to relative/absolute depending on config
|
|
1368 |
if (urlConverter)
|
|
1369 |
url = urlConverter.call(urlConverterScope, url, 'style');
|
|
1370 |
|
|
1371 |
// Output new URL format
|
|
1372 |
return "url('" + url.replace(/\'/g, "\\'") + "')";
|
|
1373 |
});
|
|
1374 |
|
|
1375 |
styles[name] = isEncoded ? decode(value, true) : value;
|
|
1376 |
}
|
|
1377 |
|
|
1378 |
styleRegExp.lastIndex = matches.index + matches[0].length;
|
|
1379 |
}
|
|
1380 |
|
|
1381 |
// Compress the styles to reduce it's size for example IE will expand styles
|
|
1382 |
compress("border", "");
|
|
1383 |
compress("border", "-width");
|
|
1384 |
compress("border", "-color");
|
|
1385 |
compress("border", "-style");
|
|
1386 |
compress("padding", "");
|
|
1387 |
compress("margin", "");
|
|
1388 |
compress2('border', 'border-width', 'border-style', 'border-color');
|
|
1389 |
|
|
1390 |
// Remove pointless border, IE produces these
|
|
1391 |
if (styles.border === 'medium none')
|
|
1392 |
delete styles.border;
|
|
1393 |
}
|
|
1394 |
|
|
1395 |
return styles;
|
|
1396 |
},
|
|
1397 |
|
|
1398 |
serialize : function(styles, element_name) {
|
|
1399 |
var css = '', name, value;
|
|
1400 |
|
|
1401 |
function serializeStyles(name) {
|
|
1402 |
var styleList, i, l, name, value;
|
|
1403 |
|
|
1404 |
styleList = schema.styles[name];
|
|
1405 |
if (styleList) {
|
|
1406 |
for (i = 0, l = styleList.length; i < l; i++) {
|
|
1407 |
name = styleList[i];
|
|
1408 |
value = styles[name];
|
|
1409 |
|
|
1410 |
if (value !== undef && value.length > 0)
|
|
1411 |
css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
|
|
1412 |
}
|
|
1413 |
}
|
|
1414 |
};
|
|
1415 |
|
|
1416 |
// Serialize styles according to schema
|
|
1417 |
if (element_name && schema && schema.styles) {
|
|
1418 |
// Serialize global styles and element specific styles
|
|
1419 |
serializeStyles('*');
|
|
1420 |
serializeStyles(name);
|
|
1421 |
} else {
|
|
1422 |
// Output the styles in the order they are inside the object
|
|
1423 |
for (name in styles) {
|
|
1424 |
value = styles[name];
|
|
1425 |
|
|
1426 |
if (value !== undef && value.length > 0)
|
|
1427 |
css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
|
|
1428 |
}
|
|
1429 |
}
|
|
1430 |
|
|
1431 |
return css;
|
|
1432 |
}
|
|
1433 |
};
|
|
1434 |
};
|
|
1435 |
|
|
1436 |
(function(tinymce) {
|
|
1437 |
var transitional = {}, boolAttrMap, blockElementsMap, shortEndedElementsMap, nonEmptyElementsMap,
|
|
1438 |
whiteSpaceElementsMap, selfClosingElementsMap, makeMap = tinymce.makeMap, each = tinymce.each;
|
|
1439 |
|
|
1440 |
function split(str, delim) {
|
|
1441 |
return str.split(delim || ',');
|
|
1442 |
};
|
|
1443 |
|
|
1444 |
function unpack(lookup, data) {
|
|
1445 |
var key, elements = {};
|
|
1446 |
|
|
1447 |
function replace(value) {
|
|
1448 |
return value.replace(/[A-Z]+/g, function(key) {
|
|
1449 |
return replace(lookup[key]);
|
|
1450 |
});
|
|
1451 |
};
|
|
1452 |
|
|
1453 |
// Unpack lookup
|
|
1454 |
for (key in lookup) {
|
|
1455 |
if (lookup.hasOwnProperty(key))
|
|
1456 |
lookup[key] = replace(lookup[key]);
|
|
1457 |
}
|
|
1458 |
|
|
1459 |
// Unpack and parse data into object map
|
|
1460 |
replace(data).replace(/#/g, '#text').replace(/(\w+)\[([^\]]+)\]\[([^\]]*)\]/g, function(str, name, attributes, children) {
|
|
1461 |
attributes = split(attributes, '|');
|
|
1462 |
|
|
1463 |
elements[name] = {
|
|
1464 |
attributes : makeMap(attributes),
|
|
1465 |
attributesOrder : attributes,
|
|
1466 |
children : makeMap(children, '|', {'#comment' : {}})
|
|
1467 |
}
|
|
1468 |
});
|
|
1469 |
|
|
1470 |
return elements;
|
|
1471 |
};
|
|
1472 |
|
|
1473 |
// Build a lookup table for block elements both lowercase and uppercase
|
|
1474 |
blockElementsMap = 'h1,h2,h3,h4,h5,h6,hr,p,div,address,pre,form,table,tbody,thead,tfoot,' +
|
|
1475 |
'th,tr,td,li,ol,ul,caption,blockquote,center,dl,dt,dd,dir,fieldset,' +
|
|
1476 |
'noscript,menu,isindex,samp,header,footer,article,section,hgroup';
|
|
1477 |
blockElementsMap = makeMap(blockElementsMap, ',', makeMap(blockElementsMap.toUpperCase()));
|
|
1478 |
|
|
1479 |
// This is the XHTML 1.0 transitional elements with it's attributes and children packed to reduce it's size
|
|
1480 |
transitional = unpack({
|
|
1481 |
Z : 'H|K|N|O|P',
|
|
1482 |
Y : 'X|form|R|Q',
|
|
1483 |
ZG : 'E|span|width|align|char|charoff|valign',
|
|
1484 |
X : 'p|T|div|U|W|isindex|fieldset|table',
|
|
1485 |
ZF : 'E|align|char|charoff|valign',
|
|
1486 |
W : 'pre|hr|blockquote|address|center|noframes',
|
|
1487 |
ZE : 'abbr|axis|headers|scope|rowspan|colspan|align|char|charoff|valign|nowrap|bgcolor|width|height',
|
|
1488 |
ZD : '[E][S]',
|
|
1489 |
U : 'ul|ol|dl|menu|dir',
|
|
1490 |
ZC : 'p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q',
|
|
1491 |
T : 'h1|h2|h3|h4|h5|h6',
|
|
1492 |
ZB : 'X|S|Q',
|
|
1493 |
S : 'R|P',
|
|
1494 |
ZA : 'a|G|J|M|O|P',
|
|
1495 |
R : 'a|H|K|N|O',
|
|
1496 |
Q : 'noscript|P',
|
|
1497 |
P : 'ins|del|script',
|
|
1498 |
O : 'input|select|textarea|label|button',
|
|
1499 |
N : 'M|L',
|
|
1500 |
M : 'em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym',
|
|
1501 |
L : 'sub|sup',
|
|
1502 |
K : 'J|I',
|
|
1503 |
J : 'tt|i|b|u|s|strike',
|
|
1504 |
I : 'big|small|font|basefont',
|
|
1505 |
H : 'G|F',
|
|
1506 |
G : 'br|span|bdo',
|
|
1507 |
F : 'object|applet|img|map|iframe',
|
|
1508 |
E : 'A|B|C',
|
|
1509 |
D : 'accesskey|tabindex|onfocus|onblur',
|
|
1510 |
C : 'onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup',
|
|
1511 |
B : 'lang|xml:lang|dir',
|
|
1512 |
A : 'id|class|style|title'
|
|
1513 |
}, 'script[id|charset|type|language|src|defer|xml:space][]' +
|
|
1514 |
'style[B|id|type|media|title|xml:space][]' +
|
|
1515 |
'object[E|declare|classid|codebase|data|type|codetype|archive|standby|width|height|usemap|name|tabindex|align|border|hspace|vspace][#|param|Y]' +
|
|
1516 |
'param[id|name|value|valuetype|type][]' +
|
|
1517 |
'p[E|align][#|S]' +
|
|
1518 |
'a[E|D|charset|type|name|href|hreflang|rel|rev|shape|coords|target][#|Z]' +
|
|
1519 |
'br[A|clear][]' +
|
|
1520 |
'span[E][#|S]' +
|
|
1521 |
'bdo[A|C|B][#|S]' +
|
|
1522 |
'applet[A|codebase|archive|code|object|alt|name|width|height|align|hspace|vspace][#|param|Y]' +
|
|
1523 |
'h1[E|align][#|S]' +
|
|
1524 |
'img[E|src|alt|name|longdesc|width|height|usemap|ismap|align|border|hspace|vspace][]' +
|
|
1525 |
'map[B|C|A|name][X|form|Q|area]' +
|
|
1526 |
'h2[E|align][#|S]' +
|
|
1527 |
'iframe[A|longdesc|name|src|frameborder|marginwidth|marginheight|scrolling|align|width|height][#|Y]' +
|
|
1528 |
'h3[E|align][#|S]' +
|
|
1529 |
'tt[E][#|S]' +
|
|
1530 |
'i[E][#|S]' +
|
|
1531 |
'b[E][#|S]' +
|
|
1532 |
'u[E][#|S]' +
|
|
1533 |
's[E][#|S]' +
|
|
1534 |
'strike[E][#|S]' +
|
|
1535 |
'big[E][#|S]' +
|
|
1536 |
'small[E][#|S]' +
|
|
1537 |
'font[A|B|size|color|face][#|S]' +
|
|
1538 |
'basefont[id|size|color|face][]' +
|
|
1539 |
'em[E][#|S]' +
|
|
1540 |
'strong[E][#|S]' +
|
|
1541 |
'dfn[E][#|S]' +
|
|
1542 |
'code[E][#|S]' +
|
|
1543 |
'q[E|cite][#|S]' +
|
|
1544 |
'samp[E][#|S]' +
|
|
1545 |
'kbd[E][#|S]' +
|
|
1546 |
'var[E][#|S]' +
|
|
1547 |
'cite[E][#|S]' +
|
|
1548 |
'abbr[E][#|S]' +
|
|
1549 |
'acronym[E][#|S]' +
|
|
1550 |
'sub[E][#|S]' +
|
|
1551 |
'sup[E][#|S]' +
|
|
1552 |
'input[E|D|type|name|value|checked|disabled|readonly|size|maxlength|src|alt|usemap|onselect|onchange|accept|align][]' +
|
|
1553 |
'select[E|name|size|multiple|disabled|tabindex|onfocus|onblur|onchange][optgroup|option]' +
|
|
1554 |
'optgroup[E|disabled|label][option]' +
|
|
1555 |
'option[E|selected|disabled|label|value][]' +
|
|
1556 |
'textarea[E|D|name|rows|cols|disabled|readonly|onselect|onchange][]' +
|
|
1557 |
'label[E|for|accesskey|onfocus|onblur][#|S]' +
|
|
1558 |
'button[E|D|name|value|type|disabled][#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]' +
|
|
1559 |
'h4[E|align][#|S]' +
|
|
1560 |
'ins[E|cite|datetime][#|Y]' +
|
|
1561 |
'h5[E|align][#|S]' +
|
|
1562 |
'del[E|cite|datetime][#|Y]' +
|
|
1563 |
'h6[E|align][#|S]' +
|
|
1564 |
'div[E|align][#|Y]' +
|
|
1565 |
'ul[E|type|compact][li]' +
|
|
1566 |
'li[E|type|value][#|Y]' +
|
|
1567 |
'ol[E|type|compact|start][li]' +
|
|
1568 |
'dl[E|compact][dt|dd]' +
|
|
1569 |
'dt[E][#|S]' +
|
|
1570 |
'dd[E][#|Y]' +
|
|
1571 |
'menu[E|compact][li]' +
|
|
1572 |
'dir[E|compact][li]' +
|
|
1573 |
'pre[E|width|xml:space][#|ZA]' +
|
|
1574 |
'hr[E|align|noshade|size|width][]' +
|
|
1575 |
'blockquote[E|cite][#|Y]' +
|
|
1576 |
'address[E][#|S|p]' +
|
|
1577 |
'center[E][#|Y]' +
|
|
1578 |
'noframes[E][#|Y]' +
|
|
1579 |
'isindex[A|B|prompt][]' +
|
|
1580 |
'fieldset[E][#|legend|Y]' +
|
|
1581 |
'legend[E|accesskey|align][#|S]' +
|
|
1582 |
'table[E|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor][caption|col|colgroup|thead|tfoot|tbody|tr]' +
|
|
1583 |
'caption[E|align][#|S]' +
|
|
1584 |
'col[ZG][]' +
|
|
1585 |
'colgroup[ZG][col]' +
|
|
1586 |
'thead[ZF][tr]' +
|
|
1587 |
'tr[ZF|bgcolor][th|td]' +
|
|
1588 |
'th[E|ZE][#|Y]' +
|
|
1589 |
'form[E|action|method|name|enctype|onsubmit|onreset|accept|accept-charset|target][#|X|R|Q]' +
|
|
1590 |
'noscript[E][#|Y]' +
|
|
1591 |
'td[E|ZE][#|Y]' +
|
|
1592 |
'tfoot[ZF][tr]' +
|
|
1593 |
'tbody[ZF][tr]' +
|
|
1594 |
'area[E|D|shape|coords|href|nohref|alt|target][]' +
|
|
1595 |
'base[id|href|target][]' +
|
|
1596 |
'body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]'
|
|
1597 |
);
|
|
1598 |
|
|
1599 |
boolAttrMap = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected,preload,autoplay,loop,controls');
|
|
1600 |
shortEndedElementsMap = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,source');
|
|
1601 |
nonEmptyElementsMap = tinymce.extend(makeMap('td,th,iframe,video,object'), shortEndedElementsMap);
|
|
1602 |
whiteSpaceElementsMap = makeMap('pre,script,style');
|
|
1603 |
selfClosingElementsMap = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
|
|
1604 |
|
|
1605 |
tinymce.html.Schema = function(settings) {
|
|
1606 |
var self = this, elements = {}, children = {}, patternElements = [], validStyles;
|
|
1607 |
|
|
1608 |
settings = settings || {};
|
|
1609 |
|
|
1610 |
// Allow all elements and attributes if verify_html is set to false
|
|
1611 |
if (settings.verify_html === false)
|
|
1612 |
settings.valid_elements = '*[*]';
|
|
1613 |
|
|
1614 |
// Build styles list
|
|
1615 |
if (settings.valid_styles) {
|
|
1616 |
validStyles = {};
|
|
1617 |
|
|
1618 |
// Convert styles into a rule list
|
|
1619 |
each(settings.valid_styles, function(value, key) {
|
|
1620 |
validStyles[key] = tinymce.explode(value);
|
|
1621 |
});
|
|
1622 |
}
|
|
1623 |
|
|
1624 |
// Converts a wildcard expression string to a regexp for example *a will become /.*a/.
|
|
1625 |
function patternToRegExp(str) {
|
|
1626 |
return new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
|
|
1627 |
};
|
|
1628 |
|
|
1629 |
// Parses the specified valid_elements string and adds to the current rules
|
|
1630 |
// This function is a bit hard to read since it's heavily optimized for speed
|
|
1631 |
function addValidElements(valid_elements) {
|
|
1632 |
var ei, el, ai, al, yl, matches, element, attr, attrData, elementName, attrName, attrType, attributes, attributesOrder,
|
|
1633 |
prefix, outputName, globalAttributes, globalAttributesOrder, transElement, key, childKey, value,
|
|
1634 |
elementRuleRegExp = /^([#+-])?([^\[\/]+)(?:\/([^\[]+))?(?:\[([^\]]+)\])?$/,
|
|
1635 |
attrRuleRegExp = /^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,
|
|
1636 |
hasPatternsRegExp = /[*?+]/;
|
|
1637 |
|
|
1638 |
if (valid_elements) {
|
|
1639 |
// Split valid elements into an array with rules
|
|
1640 |
valid_elements = split(valid_elements);
|
|
1641 |
|
|
1642 |
if (elements['@']) {
|
|
1643 |
globalAttributes = elements['@'].attributes;
|
|
1644 |
globalAttributesOrder = elements['@'].attributesOrder;
|
|
1645 |
}
|
|
1646 |
|
|
1647 |
// Loop all rules
|
|
1648 |
for (ei = 0, el = valid_elements.length; ei < el; ei++) {
|
|
1649 |
// Parse element rule
|
|
1650 |
matches = elementRuleRegExp.exec(valid_elements[ei]);
|
|
1651 |
if (matches) {
|
|
1652 |
// Setup local names for matches
|
|
1653 |
prefix = matches[1];
|
|
1654 |
elementName = matches[2];
|
|
1655 |
outputName = matches[3];
|
|
1656 |
attrData = matches[4];
|
|
1657 |
|
|
1658 |
// Create new attributes and attributesOrder
|
|
1659 |
attributes = {};
|
|
1660 |
attributesOrder = [];
|
|
1661 |
|
|
1662 |
// Create the new element
|
|
1663 |
element = {
|
|
1664 |
attributes : attributes,
|
|
1665 |
attributesOrder : attributesOrder
|
|
1666 |
};
|
|
1667 |
|
|
1668 |
// Padd empty elements prefix
|
|
1669 |
if (prefix === '#')
|
|
1670 |
element.paddEmpty = true;
|
|
1671 |
|
|
1672 |
// Remove empty elements prefix
|
|
1673 |
if (prefix === '-')
|
|
1674 |
element.removeEmpty = true;
|
|
1675 |
|
|
1676 |
// Copy attributes from global rule into current rule
|
|
1677 |
if (globalAttributes) {
|
|
1678 |
for (key in globalAttributes)
|
|
1679 |
attributes[key] = globalAttributes[key];
|
|
1680 |
|
|
1681 |
attributesOrder.push.apply(attributesOrder, globalAttributesOrder);
|
|
1682 |
}
|
|
1683 |
|
|
1684 |
// Attributes defined
|
|
1685 |
if (attrData) {
|
|
1686 |
attrData = split(attrData, '|');
|
|
1687 |
for (ai = 0, al = attrData.length; ai < al; ai++) {
|
|
1688 |
matches = attrRuleRegExp.exec(attrData[ai]);
|
|
1689 |
if (matches) {
|
|
1690 |
attr = {};
|
|
1691 |
attrType = matches[1];
|
|
1692 |
attrName = matches[2].replace(/::/g, ':');
|
|
1693 |
prefix = matches[3];
|
|
1694 |
value = matches[4];
|
|
1695 |
|
|
1696 |
// Required
|
|
1697 |
if (attrType === '!') {
|
|
1698 |
element.attributesRequired = element.attributesRequired || [];
|
|
1699 |
element.attributesRequired.push(attrName);
|
|
1700 |
attr.required = true;
|
|
1701 |
}
|
|
1702 |
|
|
1703 |
// Denied from global
|
|
1704 |
if (attrType === '-') {
|
|
1705 |
delete attributes[attrName];
|
|
1706 |
attributesOrder.splice(tinymce.inArray(attributesOrder, attrName), 1);
|
|
1707 |
continue;
|
|
1708 |
}
|
|
1709 |
|
|
1710 |
// Default value
|
|
1711 |
if (prefix) {
|
|
1712 |
// Default value
|
|
1713 |
if (prefix === '=') {
|
|
1714 |
element.attributesDefault = element.attributesDefault || [];
|
|
1715 |
element.attributesDefault.push({name: attrName, value: value});
|
|
1716 |
attr.defaultValue = value;
|
|
1717 |
}
|
|
1718 |
|
|
1719 |
// Forced value
|
|
1720 |
if (prefix === ':') {
|
|
1721 |
element.attributesForced = element.attributesForced || [];
|
|
1722 |
element.attributesForced.push({name: attrName, value: value});
|
|
1723 |
attr.forcedValue = value;
|
|
1724 |
}
|
|
1725 |
|
|
1726 |
// Required values
|
|
1727 |
if (prefix === '<')
|
|
1728 |
attr.validValues = makeMap(value, '?');
|
|
1729 |
}
|
|
1730 |
|
|
1731 |
// Check for attribute patterns
|
|
1732 |
if (hasPatternsRegExp.test(attrName)) {
|
|
1733 |
element.attributePatterns = element.attributePatterns || [];
|
|
1734 |
attr.pattern = patternToRegExp(attrName);
|
|
1735 |
element.attributePatterns.push(attr);
|
|
1736 |
} else {
|
|
1737 |
// Add attribute to order list if it doesn't already exist
|
|
1738 |
if (!attributes[attrName])
|
|
1739 |
attributesOrder.push(attrName);
|
|
1740 |
|
|
1741 |
attributes[attrName] = attr;
|
|
1742 |
}
|
|
1743 |
}
|
|
1744 |
}
|
|
1745 |
}
|
|
1746 |
|
|
1747 |
// Global rule, store away these for later usage
|
|
1748 |
if (!globalAttributes && elementName == '@') {
|
|
1749 |
globalAttributes = attributes;
|
|
1750 |
globalAttributesOrder = attributesOrder;
|
|
1751 |
}
|
|
1752 |
|
|
1753 |
// Handle substitute elements such as b/strong
|
|
1754 |
if (outputName) {
|
|
1755 |
element.outputName = elementName;
|
|
1756 |
elements[outputName] = element;
|
|
1757 |
}
|
|
1758 |
|
|
1759 |
// Add pattern or exact element
|
|
1760 |
if (hasPatternsRegExp.test(elementName)) {
|
|
1761 |
element.pattern = patternToRegExp(elementName);
|
|
1762 |
patternElements.push(element);
|
|
1763 |
} else
|
|
1764 |
elements[elementName] = element;
|
|
1765 |
}
|
|
1766 |
}
|
|
1767 |
}
|
|
1768 |
};
|
|
1769 |
|
|
1770 |
function setValidElements(valid_elements) {
|
|
1771 |
elements = {};
|
|
1772 |
patternElements = [];
|
|
1773 |
|
|
1774 |
addValidElements(valid_elements);
|
|
1775 |
|
|
1776 |
each(transitional, function(element, name) {
|
|
1777 |
children[name] = element.children;
|
|
1778 |
});
|
|
1779 |
};
|
|
1780 |
|
|
1781 |
// Adds custom non HTML elements to the schema
|
|
1782 |
function addCustomElements(custom_elements) {
|
|
1783 |
var customElementRegExp = /^(~)?(.+)$/;
|
|
1784 |
|
|
1785 |
if (custom_elements) {
|
|
1786 |
each(split(custom_elements), function(rule) {
|
|
1787 |
var matches = customElementRegExp.exec(rule),
|
|
1788 |
cloneName = matches[1] === '~' ? 'span' : 'div',
|
|
1789 |
name = matches[2];
|
|
1790 |
|
|
1791 |
children[name] = children[cloneName];
|
|
1792 |
|
|
1793 |
// Add custom elements at span/div positions
|
|
1794 |
each(children, function(element, child) {
|
|
1795 |
if (element[cloneName])
|
|
1796 |
element[name] = element[cloneName];
|
|
1797 |
});
|
|
1798 |
});
|
|
1799 |
}
|
|
1800 |
};
|
|
1801 |
|
|
1802 |
// Adds valid children to the schema object
|
|
1803 |
function addValidChildren(valid_children) {
|
|
1804 |
var childRuleRegExp = /^([+\-]?)(\w+)\[([^\]]+)\]$/;
|
|
1805 |
|
|
1806 |
if (valid_children) {
|
|
1807 |
each(split(valid_children), function(rule) {
|
|
1808 |
var matches = childRuleRegExp.exec(rule), parent, prefix;
|
|
1809 |
|
|
1810 |
if (matches) {
|
|
1811 |
prefix = matches[1];
|
|
1812 |
|
|
1813 |
// Add/remove items from default
|
|
1814 |
if (prefix)
|
|
1815 |
parent = children[matches[2]];
|
|
1816 |
else
|
|
1817 |
parent = children[matches[2]] = {'#comment' : {}};
|
|
1818 |
|
|
1819 |
parent = children[matches[2]];
|
|
1820 |
|
|
1821 |
each(split(matches[3], '|'), function(child) {
|
|
1822 |
if (prefix === '-')
|
|
1823 |
delete parent[child];
|
|
1824 |
else
|
|
1825 |
parent[child] = {};
|
|
1826 |
});
|
|
1827 |
}
|
|
1828 |
});
|
|
1829 |
}
|
|
1830 |
}
|
|
1831 |
|
|
1832 |
if (!settings.valid_elements) {
|
|
1833 |
// No valid elements defined then clone the elements from the transitional spec
|
|
1834 |
each(transitional, function(element, name) {
|
|
1835 |
elements[name] = {
|
|
1836 |
attributes : element.attributes,
|
|
1837 |
attributesOrder : element.attributesOrder
|
|
1838 |
};
|
|
1839 |
|
|
1840 |
children[name] = element.children;
|
|
1841 |
});
|
|
1842 |
|
|
1843 |
// Switch these
|
|
1844 |
each(split('strong/b,em/i'), function(item) {
|
|
1845 |
item = split(item, '/');
|
|
1846 |
elements[item[1]].outputName = item[0];
|
|
1847 |
});
|
|
1848 |
|
|
1849 |
// Add default alt attribute for images
|
|
1850 |
elements.img.attributesDefault = [{name: 'alt', value: ''}];
|
|
1851 |
|
|
1852 |
// Remove these if they are empty by default
|
|
1853 |
each(split('ol,ul,li,sub,sup,blockquote,tr,div,span,font,a,table,tbody'), function(name) {
|
|
1854 |
elements[name].removeEmpty = true;
|
|
1855 |
});
|
|
1856 |
|
|
1857 |
// Padd these by default
|
|
1858 |
each(split('p,h1,h2,h3,h4,h5,h6,th,td,pre,div,address,caption'), function(name) {
|
|
1859 |
elements[name].paddEmpty = true;
|
|
1860 |
});
|
|
1861 |
} else
|
|
1862 |
setValidElements(settings.valid_elements);
|
|
1863 |
|
|
1864 |
addCustomElements(settings.custom_elements);
|
|
1865 |
addValidChildren(settings.valid_children);
|
|
1866 |
addValidElements(settings.extended_valid_elements);
|
|
1867 |
|
|
1868 |
// Todo: Remove this when we fix list handling to be valid
|
|
1869 |
addValidChildren('+ol[ul|ol],+ul[ul|ol]');
|
|
1870 |
|
|
1871 |
// Delete invalid elements
|
|
1872 |
if (settings.invalid_elements) {
|
|
1873 |
tinymce.each(tinymce.explode(settings.invalid_elements), function(item) {
|
|
1874 |
if (elements[item])
|
|
1875 |
delete elements[item];
|
|
1876 |
});
|
|
1877 |
}
|
|
1878 |
|
|
1879 |
self.children = children;
|
|
1880 |
|
|
1881 |
self.styles = validStyles;
|
|
1882 |
|
|
1883 |
self.getBoolAttrs = function() {
|
|
1884 |
return boolAttrMap;
|
|
1885 |
};
|
|
1886 |
|
|
1887 |
self.getBlockElements = function() {
|
|
1888 |
return blockElementsMap;
|
|
1889 |
};
|
|
1890 |
|
|
1891 |
self.getShortEndedElements = function() {
|
|
1892 |
return shortEndedElementsMap;
|
|
1893 |
};
|
|
1894 |
|
|
1895 |
self.getSelfClosingElements = function() {
|
|
1896 |
return selfClosingElementsMap;
|
|
1897 |
};
|
|
1898 |
|
|
1899 |
self.getNonEmptyElements = function() {
|
|
1900 |
return nonEmptyElementsMap;
|
|
1901 |
};
|
|
1902 |
|
|
1903 |
self.getWhiteSpaceElements = function() {
|
|
1904 |
return whiteSpaceElementsMap;
|
|
1905 |
};
|
|
1906 |
|
|
1907 |
self.isValidChild = function(name, child) {
|
|
1908 |
var parent = children[name];
|
|
1909 |
|
|
1910 |
return !!(parent && parent[child]);
|
|
1911 |
};
|
|
1912 |
|
|
1913 |
self.getElementRule = function(name) {
|
|
1914 |
var element = elements[name], i;
|
|
1915 |
|
|
1916 |
// Exact match found
|
|
1917 |
if (element)
|
|
1918 |
return element;
|
|
1919 |
|
|
1920 |
// No exact match then try the patterns
|
|
1921 |
i = patternElements.length;
|
|
1922 |
while (i--) {
|
|
1923 |
element = patternElements[i];
|
|
1924 |
|
|
1925 |
if (element.pattern.test(name))
|
|
1926 |
return element;
|
|
1927 |
}
|
|
1928 |
};
|
|
1929 |
|
|
1930 |
self.addValidElements = addValidElements;
|
|
1931 |
|
|
1932 |
self.setValidElements = setValidElements;
|
|
1933 |
|
|
1934 |
self.addCustomElements = addCustomElements;
|
|
1935 |
|
|
1936 |
self.addValidChildren = addValidChildren;
|
|
1937 |
};
|
|
1938 |
|
|
1939 |
// Expose boolMap and blockElementMap as static properties for usage in DOMUtils
|
|
1940 |
tinymce.html.Schema.boolAttrMap = boolAttrMap;
|
|
1941 |
tinymce.html.Schema.blockElementsMap = blockElementsMap;
|
|
1942 |
})(tinymce);
|
|
1943 |
|
|
1944 |
(function(tinymce) {
|
|
1945 |
tinymce.html.SaxParser = function(settings, schema) {
|
|
1946 |
var self = this, noop = function() {};
|
|
1947 |
|
|
1948 |
settings = settings || {};
|
|
1949 |
self.schema = schema = schema || new tinymce.html.Schema();
|
|
1950 |
|
|
1951 |
if (settings.fix_self_closing !== false)
|
|
1952 |
settings.fix_self_closing = true;
|
|
1953 |
|
|
1954 |
// Add handler functions from settings and setup default handlers
|
|
1955 |
tinymce.each('comment cdata text start end pi doctype'.split(' '), function(name) {
|
|
1956 |
if (name)
|
|
1957 |
self[name] = settings[name] || noop;
|
|
1958 |
});
|
|
1959 |
|
|
1960 |
self.parse = function(html) {
|
|
1961 |
var self = this, matches, index = 0, value, endRegExp, stack = [], attrList, i, text, name,
|
|
1962 |
shortEndedElements, fillAttrsMap, isShortEnded, validate, elementRule, isValidElement, attr, attribsValue,
|
|
1963 |
validAttributesMap, validAttributePatterns, attributesRequired, attributesDefault, attributesForced, selfClosing,
|
|
1964 |
tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0, decode = tinymce.html.Entities.decode, fixSelfClosing;
|
|
1965 |
|
|
1966 |
function processEndTag(name) {
|
|
1967 |
var pos, i;
|
|
1968 |
|
|
1969 |
// Find position of parent of the same type
|
|
1970 |
pos = stack.length;
|
|
1971 |
while (pos--) {
|
|
1972 |
if (stack[pos].name === name)
|
|
1973 |
break;
|
|
1974 |
}
|
|
1975 |
|
|
1976 |
// Found parent
|
|
1977 |
if (pos >= 0) {
|
|
1978 |
// Close all the open elements
|
|
1979 |
for (i = stack.length - 1; i >= pos; i--) {
|
|
1980 |
name = stack[i];
|
|
1981 |
|
|
1982 |
if (name.valid)
|
|
1983 |
self.end(name.name);
|
|
1984 |
}
|
|
1985 |
|
|
1986 |
// Remove the open elements from the stack
|
|
1987 |
stack.length = pos;
|
|
1988 |
}
|
|
1989 |
};
|
|
1990 |
|
|
1991 |
// Precompile RegExps and map objects
|
|
1992 |
tokenRegExp = new RegExp('<(?:' +
|
|
1993 |
'(?:!--([\\w\\W]*?)-->)|' + // Comment
|
|
1994 |
'(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|' + // CDATA
|
|
1995 |
'(?:!DOCTYPE([\\w\\W]*?)>)|' + // DOCTYPE
|
|
1996 |
'(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|' + // PI
|
|
1997 |
'(?:\\/([^>]+)>)|' + // End element
|
|
1998 |
'(?:([^\\s\\/<>]+)\\s*((?:[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*)>)' + // Start element
|
|
1999 |
')', 'g');
|
|
2000 |
|
|
2001 |
attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:\\.|[^\"])*)\")|(?:\'((?:\\.|[^\'])*)\')|([^>\s]+)))?/g;
|
|
2002 |
specialElements = {
|
|
2003 |
'script' : /<\/script[^>]*>/gi,
|
|
2004 |
'style' : /<\/style[^>]*>/gi,
|
|
2005 |
'noscript' : /<\/noscript[^>]*>/gi
|
|
2006 |
};
|
|
2007 |
|
|
2008 |
// Setup lookup tables for empty elements and boolean attributes
|
|
2009 |
shortEndedElements = schema.getShortEndedElements();
|
|
2010 |
selfClosing = schema.getSelfClosingElements();
|
|
2011 |
fillAttrsMap = schema.getBoolAttrs();
|
|
2012 |
validate = settings.validate;
|
|
2013 |
fixSelfClosing = settings.fix_self_closing;
|
|
2014 |
|
|
2015 |
while (matches = tokenRegExp.exec(html)) {
|
|
2016 |
// Text
|
|
2017 |
if (index < matches.index)
|
|
2018 |
self.text(decode(html.substr(index, matches.index - index)));
|
|
2019 |
|
|
2020 |
if (value = matches[6]) { // End element
|
|
2021 |
processEndTag(value.toLowerCase());
|
|
2022 |
} else if (value = matches[7]) { // Start element
|
|
2023 |
value = value.toLowerCase();
|
|
2024 |
isShortEnded = value in shortEndedElements;
|
|
2025 |
|
|
2026 |
// Is self closing tag for example an <li> after an open <li>
|
|
2027 |
if (fixSelfClosing && selfClosing[value] && stack.length > 0 && stack[stack.length - 1].name === value)
|
|
2028 |
processEndTag(value);
|
|
2029 |
|
|
2030 |
// Validate element
|
|
2031 |
if (!validate || (elementRule = schema.getElementRule(value))) {
|
|
2032 |
isValidElement = true;
|
|
2033 |
|
|
2034 |
// Grab attributes map and patters when validation is enabled
|
|
2035 |
if (validate) {
|
|
2036 |
validAttributesMap = elementRule.attributes;
|
|
2037 |
validAttributePatterns = elementRule.attributePatterns;
|
|
2038 |
}
|
|
2039 |
|
|
2040 |
// Parse attributes
|
|
2041 |
if (attribsValue = matches[8]) {
|
|
2042 |
attrList = [];
|
|
2043 |
attrList.map = {};
|
|
2044 |
|
|
2045 |
attribsValue.replace(attrRegExp, function(match, name, value, val2, val3) {
|
|
2046 |
var attrRule, i;
|
|
2047 |
|
|
2048 |
name = name.toLowerCase();
|
|
2049 |
value = name in fillAttrsMap ? name : decode(value || val2 || val3 || ''); // Handle boolean attribute than value attribute
|
|
2050 |
|
|
2051 |
// Validate name and value
|
|
2052 |
if (validate && name.indexOf('data-') !== 0) {
|
|
2053 |
attrRule = validAttributesMap[name];
|
|
2054 |
|
|
2055 |
// Find rule by pattern matching
|
|
2056 |
if (!attrRule && validAttributePatterns) {
|
|
2057 |
i = validAttributePatterns.length;
|
|
2058 |
while (i--) {
|
|
2059 |
attrRule = validAttributePatterns[i];
|
|
2060 |
if (attrRule.pattern.test(name))
|
|
2061 |
break;
|
|
2062 |
}
|
|
2063 |
|
|
2064 |
// No rule matched
|
|
2065 |
if (i === -1)
|
|
2066 |
attrRule = null;
|
|
2067 |
}
|
|
2068 |
|
|
2069 |
// No attribute rule found
|
|
2070 |
if (!attrRule)
|
|
2071 |
return;
|
|
2072 |
|
|
2073 |
// Validate value
|
|
2074 |
if (attrRule.validValues && !(value in attrRule.validValues))
|
|
2075 |
return;
|
|
2076 |
}
|
|
2077 |
|
|
2078 |
// Add attribute to list and map
|
|
2079 |
attrList.map[name] = value;
|
|
2080 |
attrList.push({
|
|
2081 |
name: name,
|
|
2082 |
value: value
|
|
2083 |
});
|
|
2084 |
});
|
|
2085 |
} else {
|
|
2086 |
attrList = [];
|
|
2087 |
attrList.map = {};
|
|
2088 |
}
|
|
2089 |
|
|
2090 |
// Process attributes if validation is enabled
|
|
2091 |
if (validate) {
|
|
2092 |
attributesRequired = elementRule.attributesRequired;
|
|
2093 |
attributesDefault = elementRule.attributesDefault;
|
|
2094 |
attributesForced = elementRule.attributesForced;
|
|
2095 |
|
|
2096 |
// Handle forced attributes
|
|
2097 |
if (attributesForced) {
|
|
2098 |
i = attributesForced.length;
|
|
2099 |
while (i--) {
|
|
2100 |
attr = attributesForced[i];
|
|
2101 |
name = attr.name;
|
|
2102 |
attrValue = attr.value;
|
|
2103 |
|
|
2104 |
if (attrValue === '{$uid}')
|
|
2105 |
attrValue = 'mce_' + idCount++;
|
|
2106 |
|
|
2107 |
attrList.map[name] = attrValue;
|
|
2108 |
attrList.push({name: name, value: attrValue});
|
|
2109 |
}
|
|
2110 |
}
|
|
2111 |
|
|
2112 |
// Handle default attributes
|
|
2113 |
if (attributesDefault) {
|
|
2114 |
i = attributesDefault.length;
|
|
2115 |
while (i--) {
|
|
2116 |
attr = attributesDefault[i];
|
|
2117 |
name = attr.name;
|
|
2118 |
|
|
2119 |
if (!(name in attrList.map)) {
|
|
2120 |
attrValue = attr.value;
|
|
2121 |
|
|
2122 |
if (attrValue === '{$uid}')
|
|
2123 |
attrValue = 'mce_' + idCount++;
|
|
2124 |
|
|
2125 |
attrList.map[name] = attrValue;
|
|
2126 |
attrList.push({name: name, value: attrValue});
|
|
2127 |
}
|
|
2128 |
}
|
|
2129 |
}
|
|
2130 |
|
|
2131 |
// Handle required attributes
|
|
2132 |
if (attributesRequired) {
|
|
2133 |
i = attributesRequired.length;
|
|
2134 |
while (i--) {
|
|
2135 |
if (attributesRequired[i] in attrList.map)
|
|
2136 |
break;
|
|
2137 |
}
|
|
2138 |
|
|
2139 |
// None of the required attributes where found
|
|
2140 |
if (i === -1)
|
|
2141 |
isValidElement = false;
|
|
2142 |
}
|
|
2143 |
|
|
2144 |
// Invalidate element if it's marked as bogus
|
|
2145 |
if (attrList.map['data-mce-bogus'])
|
|
2146 |
isValidElement = false;
|
|
2147 |
}
|
|
2148 |
|
|
2149 |
if (isValidElement)
|
|
2150 |
self.start(value, attrList, isShortEnded);
|
|
2151 |
} else
|
|
2152 |
isValidElement = false;
|
|
2153 |
|
|
2154 |
// Treat script, noscript and style a bit different since they may include code that looks like elements
|
|
2155 |
if (endRegExp = specialElements[value]) {
|
|
2156 |
endRegExp.lastIndex = index = matches.index + matches[0].length;
|
|
2157 |
|
|
2158 |
if (matches = endRegExp.exec(html)) {
|
|
2159 |
if (isValidElement)
|
|
2160 |
text = html.substr(index, matches.index - index);
|
|
2161 |
|
|
2162 |
index = matches.index + matches[0].length;
|
|
2163 |
} else {
|
|
2164 |
text = html.substr(index);
|
|
2165 |
index = html.length;
|
|
2166 |
}
|
|
2167 |
|
|
2168 |
if (isValidElement && text.length > 0)
|
|
2169 |
self.text(text, true);
|
|
2170 |
|
|
2171 |
if (isValidElement)
|
|
2172 |
self.end(value);
|
|
2173 |
|
|
2174 |
tokenRegExp.lastIndex = index;
|
|
2175 |
continue;
|
|
2176 |
}
|
|
2177 |
|
|
2178 |
// Push value on to stack
|
|
2179 |
if (!isShortEnded) {
|
|
2180 |
if (!attribsValue || attribsValue.indexOf('/') != attribsValue.length - 1)
|
|
2181 |
stack.push({name: value, valid: isValidElement});
|
|
2182 |
else if (isValidElement)
|
|
2183 |
self.end(value);
|
|
2184 |
}
|
|
2185 |
} else if (value = matches[1]) { // Comment
|
|
2186 |
self.comment(value);
|
|
2187 |
} else if (value = matches[2]) { // CDATA
|
|
2188 |
self.cdata(value);
|
|
2189 |
} else if (value = matches[3]) { // DOCTYPE
|
|
2190 |
self.doctype(value);
|
|
2191 |
} else if (value = matches[4]) { // PI
|
|
2192 |
self.pi(value, matches[5]);
|
|
2193 |
}
|
|
2194 |
|
|
2195 |
index = matches.index + matches[0].length;
|
|
2196 |
}
|
|
2197 |
|
|
2198 |
// Text
|
|
2199 |
if (index < html.length)
|
|
2200 |
self.text(decode(html.substr(index)));
|
|
2201 |
|
|
2202 |
// Close any open elements
|
|
2203 |
for (i = stack.length - 1; i >= 0; i--) {
|
|
2204 |
value = stack[i];
|
|
2205 |
|
|
2206 |
if (value.valid)
|
|
2207 |
self.end(value.name);
|
|
2208 |
}
|
|
2209 |
};
|
|
2210 |
}
|
|
2211 |
})(tinymce);
|
|
2212 |
|
|
2213 |
(function(tinymce) {
|
|
2214 |
var whiteSpaceRegExp = /^[ \t\r\n]*$/, typeLookup = {
|
|
2215 |
'#text' : 3,
|
|
2216 |
'#comment' : 8,
|
|
2217 |
'#cdata' : 4,
|
|
2218 |
'#pi' : 7,
|
|
2219 |
'#doctype' : 10,
|
|
2220 |
'#document-fragment' : 11
|
|
2221 |
};
|
|
2222 |
|
|
2223 |
// Walks the tree left/right
|
|
2224 |
function walk(node, root_node, prev) {
|
|
2225 |
var sibling, parent, startName = prev ? 'lastChild' : 'firstChild', siblingName = prev ? 'prev' : 'next';
|
|
2226 |
|
|
2227 |
// Walk into nodes if it has a start
|
|
2228 |
if (node[startName])
|
|
2229 |
return node[startName];
|
|
2230 |
|
|
2231 |
// Return the sibling if it has one
|
|
2232 |
if (node !== root_node) {
|
|
2233 |
sibling = node[siblingName];
|
|
2234 |
|
|
2235 |
if (sibling)
|
|
2236 |
return sibling;
|
|
2237 |
|
|
2238 |
// Walk up the parents to look for siblings
|
|
2239 |
for (parent = node.parent; parent && parent !== root_node; parent = parent.parent) {
|
|
2240 |
sibling = parent[siblingName];
|
|
2241 |
|
|
2242 |
if (sibling)
|
|
2243 |
return sibling;
|
|
2244 |
}
|
|
2245 |
}
|
|
2246 |
};
|
|
2247 |
|
|
2248 |
function Node(name, type) {
|
|
2249 |
this.name = name;
|
|
2250 |
this.type = type;
|
|
2251 |
|
|
2252 |
if (type === 1) {
|
|
2253 |
this.attributes = [];
|
|
2254 |
this.attributes.map = {};
|
|
2255 |
}
|
|
2256 |
}
|
|
2257 |
|
|
2258 |
tinymce.extend(Node.prototype, {
|
|
2259 |
replace : function(node) {
|
|
2260 |
var self = this;
|
|
2261 |
|
|
2262 |
if (node.parent)
|
|
2263 |
node.remove();
|
|
2264 |
|
|
2265 |
self.insert(node, self);
|
|
2266 |
self.remove();
|
|
2267 |
|
|
2268 |
return self;
|
|
2269 |
},
|
|
2270 |
|
|
2271 |
attr : function(name, value) {
|
|
2272 |
var self = this, attrs, i, undef;
|
|
2273 |
|
|
2274 |
if (typeof name !== "string") {
|
|
2275 |
for (i in name)
|
|
2276 |
self.attr(i, name[i]);
|
|
2277 |
|
|
2278 |
return self;
|
|
2279 |
}
|
|
2280 |
|
|
2281 |
if (attrs = self.attributes) {
|
|
2282 |
if (value !== undef) {
|
|
2283 |
// Remove attribute
|
|
2284 |
if (value === null) {
|
|
2285 |
if (name in attrs.map) {
|
|
2286 |
delete attrs.map[name];
|
|
2287 |
|
|
2288 |
i = attrs.length;
|
|
2289 |
while (i--) {
|
|
2290 |
if (attrs[i].name === name) {
|
|
2291 |
attrs = attrs.splice(i, 1);
|
|
2292 |
return self;
|
|
2293 |
}
|
|
2294 |
}
|
|
2295 |
}
|
|
2296 |
|
|
2297 |
return self;
|
|
2298 |
}
|
|
2299 |
|
|
2300 |
// Set attribute
|
|
2301 |
if (name in attrs.map) {
|
|
2302 |
// Set attribute
|
|
2303 |
i = attrs.length;
|
|
2304 |
while (i--) {
|
|
2305 |
if (attrs[i].name === name) {
|
|
2306 |
attrs[i].value = value;
|
|
2307 |
break;
|
|
2308 |
}
|
|
2309 |
}
|
|
2310 |
} else
|
|
2311 |
attrs.push({name: name, value: value});
|
|
2312 |
|
|
2313 |
attrs.map[name] = value;
|
|
2314 |
|
|
2315 |
return self;
|
|
2316 |
} else {
|
|
2317 |
return attrs.map[name];
|
|
2318 |
}
|
|
2319 |
}
|
|
2320 |
},
|
|
2321 |
|
|
2322 |
clone : function() {
|
|
2323 |
var self = this, clone = new Node(self.name, self.type), i, l, selfAttrs, selfAttr, cloneAttrs;
|
|
2324 |
|
|
2325 |
// Clone element attributes
|
|
2326 |
if (selfAttrs = self.attributes) {
|
|
2327 |
cloneAttrs = [];
|
|
2328 |
cloneAttrs.map = {};
|
|
2329 |
|
|
2330 |
for (i = 0, l = selfAttrs.length; i < l; i++) {
|
|
2331 |
selfAttr = selfAttrs[i];
|
|
2332 |
|
|
2333 |
// Clone everything except id
|
|
2334 |
if (selfAttr.name !== 'id') {
|
|
2335 |
cloneAttrs[cloneAttrs.length] = {name: selfAttr.name, value: selfAttr.value};
|
|
2336 |
cloneAttrs.map[selfAttr.name] = selfAttr.value;
|
|
2337 |
}
|
|
2338 |
}
|
|
2339 |
|
|
2340 |
clone.attributes = cloneAttrs;
|
|
2341 |
}
|
|
2342 |
|
|
2343 |
clone.value = self.value;
|
|
2344 |
clone.shortEnded = self.shortEnded;
|
|
2345 |
|
|
2346 |
return clone;
|
|
2347 |
},
|
|
2348 |
|
|
2349 |
wrap : function(wrapper) {
|
|
2350 |
var self = this;
|
|
2351 |
|
|
2352 |
self.parent.insert(wrapper, self);
|
|
2353 |
wrapper.append(self);
|
|
2354 |
|
|
2355 |
return self;
|
|
2356 |
},
|
|
2357 |
|
|
2358 |
unwrap : function() {
|
|
2359 |
var self = this, node, next;
|
|
2360 |
|
|
2361 |
for (node = self.firstChild; node; ) {
|
|
2362 |
next = node.next;
|
|
2363 |
self.insert(node, self, true);
|
|
2364 |
node = next;
|
|
2365 |
}
|
|
2366 |
|
|
2367 |
self.remove();
|
|
2368 |
},
|
|
2369 |
|
|
2370 |
remove : function() {
|
|
2371 |
var self = this, parent = self.parent, next = self.next, prev = self.prev;
|
|
2372 |
|
|
2373 |
if (parent) {
|
|
2374 |
if (parent.firstChild === self) {
|
|
2375 |
parent.firstChild = next;
|
|
2376 |
|
|
2377 |
if (next)
|
|
2378 |
next.prev = null;
|
|
2379 |
} else {
|
|
2380 |
prev.next = next;
|
|
2381 |
}
|
|
2382 |
|
|
2383 |
if (parent.lastChild === self) {
|
|
2384 |
parent.lastChild = prev;
|
|
2385 |
|
|
2386 |
if (prev)
|
|
2387 |
prev.next = null;
|
|
2388 |
} else {
|
|
2389 |
next.prev = prev;
|
|
2390 |
}
|
|
2391 |
|
|
2392 |
self.parent = self.next = self.prev = null;
|
|
2393 |
}
|
|
2394 |
|
|
2395 |
return self;
|
|
2396 |
},
|
|
2397 |
|
|
2398 |
append : function(node) {
|
|
2399 |
var self = this, last;
|
|
2400 |
|
|
2401 |
if (node.parent)
|
|
2402 |
node.remove();
|
|
2403 |
|
|
2404 |
last = self.lastChild;
|
|
2405 |
if (last) {
|
|
2406 |
last.next = node;
|
|
2407 |
node.prev = last;
|
|
2408 |
self.lastChild = node;
|
|
2409 |
} else
|
|
2410 |
self.lastChild = self.firstChild = node;
|
|
2411 |
|
|
2412 |
node.parent = self;
|
|
2413 |
|
|
2414 |
return node;
|
|
2415 |
},
|
|
2416 |
|
|
2417 |
insert : function(node, ref_node, before) {
|
|
2418 |
var parent;
|
|
2419 |
|
|
2420 |
if (node.parent)
|
|
2421 |
node.remove();
|
|
2422 |
|
|
2423 |
parent = ref_node.parent || this;
|
|
2424 |
|
|
2425 |
if (before) {
|
|
2426 |
if (ref_node === parent.firstChild)
|
|
2427 |
parent.firstChild = node;
|
|
2428 |
else
|
|
2429 |
ref_node.prev.next = node;
|
|
2430 |
|
|
2431 |
node.prev = ref_node.prev;
|
|
2432 |
node.next = ref_node;
|
|
2433 |
ref_node.prev = node;
|
|
2434 |
} else {
|
|
2435 |
if (ref_node === parent.lastChild)
|
|
2436 |
parent.lastChild = node;
|
|
2437 |
else
|
|
2438 |
ref_node.next.prev = node;
|
|
2439 |
|
|
2440 |
node.next = ref_node.next;
|
|
2441 |
node.prev = ref_node;
|
|
2442 |
ref_node.next = node;
|
|
2443 |
}
|
|
2444 |
|
|
2445 |
node.parent = parent;
|
|
2446 |
|
|
2447 |
return node;
|
|
2448 |
},
|
|
2449 |
|
|
2450 |
getAll : function(name) {
|
|
2451 |
var self = this, node, collection = [];
|
|
2452 |
|
|
2453 |
for (node = self.firstChild; node; node = walk(node, self)) {
|
|
2454 |
if (node.name === name)
|
|
2455 |
collection.push(node);
|
|
2456 |
}
|
|
2457 |
|
|
2458 |
return collection;
|
|
2459 |
},
|
|
2460 |
|
|
2461 |
empty : function() {
|
|
2462 |
var self = this, nodes, i, node;
|
|
2463 |
|
|
2464 |
// Remove all children
|
|
2465 |
if (self.firstChild) {
|
|
2466 |
nodes = [];
|
|
2467 |
|
|
2468 |
// Collect the children
|
|
2469 |
for (node = self.firstChild; node; node = walk(node, self))
|
|
2470 |
nodes.push(node);
|
|
2471 |
|
|
2472 |
// Remove the children
|
|
2473 |
i = nodes.length;
|
|
2474 |
while (i--) {
|
|
2475 |
node = nodes[i];
|
|
2476 |
node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
|
|
2477 |
}
|
|
2478 |
}
|
|
2479 |
|
|
2480 |
self.firstChild = self.lastChild = null;
|
|
2481 |
|
|
2482 |
return self;
|
|
2483 |
},
|
|
2484 |
|
|
2485 |
isEmpty : function(elements) {
|
|
2486 |
var self = this, node = self.firstChild, i, name;
|
|
2487 |
|
|
2488 |
if (node) {
|
|
2489 |
do {
|
|
2490 |
if (node.type === 1) {
|
|
2491 |
// Ignore bogus elements
|
|
2492 |
if (node.attributes.map['data-mce-bogus'])
|
|
2493 |
continue;
|
|
2494 |
|
|
2495 |
// Keep empty elements like <img />
|
|
2496 |
if (elements[node.name])
|
|
2497 |
return false;
|
|
2498 |
|
|
2499 |
// Keep elements with data attributes or name attribute like <a name="1"></a>
|
|
2500 |
i = node.attributes.length;
|
|
2501 |
while (i--) {
|
|
2502 |
name = node.attributes[i].name;
|
|
2503 |
if (name === "name" || name.indexOf('data-') === 0)
|
|
2504 |
return false;
|
|
2505 |
}
|
|
2506 |
}
|
|
2507 |
|
|
2508 |
// Keep non whitespace text nodes
|
|
2509 |
if ((node.type === 3 && !whiteSpaceRegExp.test(node.value)))
|
|
2510 |
return false;
|
|
2511 |
} while (node = walk(node, self));
|
|
2512 |
}
|
|
2513 |
|
|
2514 |
return true;
|
|
2515 |
}
|
|
2516 |
});
|
|
2517 |
|
|
2518 |
tinymce.extend(Node, {
|
|
2519 |
create : function(name, attrs) {
|
|
2520 |
var node, attrName;
|
|
2521 |
|
|
2522 |
// Create node
|
|
2523 |
node = new Node(name, typeLookup[name] || 1);
|
|
2524 |
|
|
2525 |
// Add attributes if needed
|
|
2526 |
if (attrs) {
|
|
2527 |
for (attrName in attrs)
|
|
2528 |
node.attr(attrName, attrs[attrName]);
|
|
2529 |
}
|
|
2530 |
|
|
2531 |
return node;
|
|
2532 |
}
|
|
2533 |
});
|
|
2534 |
|
|
2535 |
tinymce.html.Node = Node;
|
|
2536 |
})(tinymce);
|
|
2537 |
|
|
2538 |
(function(tinymce) {
|
|
2539 |
var Node = tinymce.html.Node;
|
|
2540 |
|
|
2541 |
tinymce.html.DomParser = function(settings, schema) {
|
|
2542 |
var self = this, nodeFilters = {}, attributeFilters = [], matchedNodes = {}, matchedAttributes = {};
|
|
2543 |
|
|
2544 |
settings = settings || {};
|
|
2545 |
settings.validate = "validate" in settings ? settings.validate : true;
|
|
2546 |
settings.root_name = settings.root_name || 'body';
|
|
2547 |
self.schema = schema = schema || new tinymce.html.Schema();
|
|
2548 |
|
|
2549 |
function fixInvalidChildren(nodes) {
|
|
2550 |
var ni, node, parent, parents, newParent, currentNode, tempNode, childNode, i,
|
|
2551 |
childClone, nonEmptyElements, nonSplitableElements, sibling, nextNode;
|
|
2552 |
|
|
2553 |
nonSplitableElements = tinymce.makeMap('tr,td,th,tbody,thead,tfoot,table');
|
|
2554 |
nonEmptyElements = schema.getNonEmptyElements();
|
|
2555 |
|
|
2556 |
for (ni = 0; ni < nodes.length; ni++) {
|
|
2557 |
node = nodes[ni];
|
|
2558 |
|
|
2559 |
// Already removed
|
|
2560 |
if (!node.parent)
|
|
2561 |
continue;
|
|
2562 |
|
|
2563 |
// Get list of all parent nodes until we find a valid parent to stick the child into
|
|
2564 |
parents = [node];
|
|
2565 |
for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && !nonSplitableElements[parent.name]; parent = parent.parent)
|
|
2566 |
parents.push(parent);
|
|
2567 |
|
|
2568 |
// Found a suitable parent
|
|
2569 |
if (parent && parents.length > 1) {
|
|
2570 |
// Reverse the array since it makes looping easier
|
|
2571 |
parents.reverse();
|
|
2572 |
|
|
2573 |
// Clone the related parent and insert that after the moved node
|
|
2574 |
newParent = currentNode = self.filterNode(parents[0].clone());
|
|
2575 |
|
|
2576 |
// Start cloning and moving children on the left side of the target node
|
|
2577 |
for (i = 0; i < parents.length - 1; i++) {
|
|
2578 |
if (schema.isValidChild(currentNode.name, parents[i].name)) {
|
|
2579 |
tempNode = self.filterNode(parents[i].clone());
|
|
2580 |
currentNode.append(tempNode);
|
|
2581 |
} else
|
|
2582 |
tempNode = currentNode;
|
|
2583 |
|
|
2584 |
for (childNode = parents[i].firstChild; childNode && childNode != parents[i + 1]; ) {
|
|
2585 |
nextNode = childNode.next;
|
|
2586 |
tempNode.append(childNode);
|
|
2587 |
childNode = nextNode;
|
|
2588 |
}
|
|
2589 |
|
|
2590 |
currentNode = tempNode;
|
|
2591 |
}
|
|
2592 |
|
|
2593 |
if (!newParent.isEmpty(nonEmptyElements)) {
|
|
2594 |
parent.insert(newParent, parents[0], true);
|
|
2595 |
parent.insert(node, newParent);
|
|
2596 |
} else {
|
|
2597 |
parent.insert(node, parents[0], true);
|
|
2598 |
}
|
|
2599 |
|
|
2600 |
// Check if the element is empty by looking through it's contents and special treatment for <p><br /></p>
|
|
2601 |
parent = parents[0];
|
|
2602 |
if (parent.isEmpty(nonEmptyElements) || parent.firstChild === parent.lastChild && parent.firstChild.name === 'br') {
|
|
2603 |
parent.empty().remove();
|
|
2604 |
}
|
|
2605 |
} else if (node.parent) {
|
|
2606 |
// If it's an LI try to find a UL/OL for it or wrap it
|
|
2607 |
if (node.name === 'li') {
|
|
2608 |
sibling = node.prev;
|
|
2609 |
if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
|
|
2610 |
sibling.append(node);
|
|
2611 |
continue;
|
|
2612 |
}
|
|
2613 |
|
|
2614 |
sibling = node.next;
|
|
2615 |
if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
|
|
2616 |
sibling.insert(node, sibling.firstChild, true);
|
|
2617 |
continue;
|
|
2618 |
}
|
|
2619 |
|
|
2620 |
node.wrap(self.filterNode(new Node('ul', 1)));
|
|
2621 |
continue;
|
|
2622 |
}
|
|
2623 |
|
|
2624 |
// Try wrapping the element in a DIV
|
|
2625 |
if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
|
|
2626 |
node.wrap(self.filterNode(new Node('div', 1)));
|
|
2627 |
} else {
|
|
2628 |
// We failed wrapping it, then remove or unwrap it
|
|
2629 |
if (node.name === 'style' || node.name === 'script')
|
|
2630 |
node.empty().remove();
|
|
2631 |
else
|
|
2632 |
node.unwrap();
|
|
2633 |
}
|
|
2634 |
}
|
|
2635 |
}
|
|
2636 |
};
|
|
2637 |
|
|
2638 |
self.filterNode = function(node) {
|
|
2639 |
var i, name, list;
|
|
2640 |
|
|
2641 |
// Run element filters
|
|
2642 |
if (name in nodeFilters) {
|
|
2643 |
list = matchedNodes[name];
|
|
2644 |
|
|
2645 |
if (list)
|
|
2646 |
list.push(node);
|
|
2647 |
else
|
|
2648 |
matchedNodes[name] = [node];
|
|
2649 |
}
|
|
2650 |
|
|
2651 |
// Run attribute filters
|
|
2652 |
i = attributeFilters.length;
|
|
2653 |
while (i--) {
|
|
2654 |
name = attributeFilters[i].name;
|
|
2655 |
|
|
2656 |
if (name in node.attributes.map) {
|
|
2657 |
list = matchedAttributes[name];
|
|
2658 |
|
|
2659 |
if (list)
|
|
2660 |
list.push(node);
|
|
2661 |
else
|
|
2662 |
matchedAttributes[name] = [node];
|
|
2663 |
}
|
|
2664 |
}
|
|
2665 |
|
|
2666 |
return node;
|
|
2667 |
};
|
|
2668 |
|
|
2669 |
self.addNodeFilter = function(name, callback) {
|
|
2670 |
tinymce.each(tinymce.explode(name), function(name) {
|
|
2671 |
var list = nodeFilters[name];
|
|
2672 |
|
|
2673 |
if (!list)
|
|
2674 |
nodeFilters[name] = list = [];
|
|
2675 |
|
|
2676 |
list.push(callback);
|
|
2677 |
});
|
|
2678 |
};
|
|
2679 |
|
|
2680 |
self.addAttributeFilter = function(name, callback) {
|
|
2681 |
tinymce.each(tinymce.explode(name), function(name) {
|
|
2682 |
var i;
|
|
2683 |
|
|
2684 |
for (i = 0; i < attributeFilters.length; i++) {
|
|
2685 |
if (attributeFilters[i].name === name) {
|
|
2686 |
attributeFilters[i].callbacks.push(callback);
|
|
2687 |
return;
|
|
2688 |
}
|
|
2689 |
}
|
|
2690 |
|
|
2691 |
attributeFilters.push({name: name, callbacks: [callback]});
|
|
2692 |
});
|
|
2693 |
};
|
|
2694 |
|
|
2695 |
self.parse = function(html, args) {
|
|
2696 |
var parser, rootNode, node, nodes, i, l, fi, fl, list, name, validate,
|
|
2697 |
blockElements, startWhiteSpaceRegExp, invalidChildren = [],
|
|
2698 |
endWhiteSpaceRegExp, allWhiteSpaceRegExp, whiteSpaceElements, children, nonEmptyElements;
|
|
2699 |
|
|
2700 |
args = args || {};
|
|
2701 |
matchedNodes = {};
|
|
2702 |
matchedAttributes = {};
|
|
2703 |
blockElements = tinymce.extend(tinymce.makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
|
|
2704 |
nonEmptyElements = schema.getNonEmptyElements();
|
|
2705 |
children = schema.children;
|
|
2706 |
validate = settings.validate;
|
|
2707 |
|
|
2708 |
whiteSpaceElements = schema.getWhiteSpaceElements();
|
|
2709 |
startWhiteSpaceRegExp = /^[ \t\r\n]+/;
|
|
2710 |
endWhiteSpaceRegExp = /[ \t\r\n]+$/;
|
|
2711 |
allWhiteSpaceRegExp = /[ \t\r\n]+/g;
|
|
2712 |
|
|
2713 |
function createNode(name, type) {
|
|
2714 |
var node = new Node(name, type), list;
|
|
2715 |
|
|
2716 |
if (name in nodeFilters) {
|
|
2717 |
list = matchedNodes[name];
|
|
2718 |
|
|
2719 |
if (list)
|
|
2720 |
list.push(node);
|
|
2721 |
else
|
|
2722 |
matchedNodes[name] = [node];
|
|
2723 |
}
|
|
2724 |
|
|
2725 |
return node;
|
|
2726 |
};
|
|
2727 |
|
|
2728 |
function removeWhitespaceBefore(node) {
|
|
2729 |
var textNode, textVal, sibling;
|
|
2730 |
|
|
2731 |
for (textNode = node.prev; textNode && textNode.type === 3; ) {
|
|
2732 |
textVal = textNode.value.replace(endWhiteSpaceRegExp, '');
|
|
2733 |
|
|
2734 |
if (textVal.length > 0) {
|
|
2735 |
textNode.value = textVal;
|
|
2736 |
textNode = textNode.prev;
|
|
2737 |
} else {
|
|
2738 |
sibling = textNode.prev;
|
|
2739 |
textNode.remove();
|
|
2740 |
textNode = sibling;
|
|
2741 |
}
|
|
2742 |
}
|
|
2743 |
};
|
|
2744 |
|
|
2745 |
parser = new tinymce.html.SaxParser({
|
|
2746 |
validate : validate,
|
|
2747 |
fix_self_closing : !validate, // Let the DOM parser handle <li> in <li> or <p> in <p> for better results
|
|
2748 |
|
|
2749 |
cdata: function(text) {
|
|
2750 |
node.append(createNode('#cdata', 4)).value = text;
|
|
2751 |
},
|
|
2752 |
|
|
2753 |
text: function(text, raw) {
|
|
2754 |
var textNode;
|
|
2755 |
|
|
2756 |
// Trim all redundant whitespace on non white space elements
|
|
2757 |
if (!whiteSpaceElements[node.name]) {
|
|
2758 |
text = text.replace(allWhiteSpaceRegExp, ' ');
|
|
2759 |
|
|
2760 |
if (node.lastChild && blockElements[node.lastChild.name])
|
|
2761 |
text = text.replace(startWhiteSpaceRegExp, '');
|
|
2762 |
}
|
|
2763 |
|
|
2764 |
// Do we need to create the node
|
|
2765 |
if (text.length !== 0) {
|
|
2766 |
textNode = createNode('#text', 3);
|
|
2767 |
textNode.raw = !!raw;
|
|
2768 |
node.append(textNode).value = text;
|
|
2769 |
}
|
|
2770 |
},
|
|
2771 |
|
|
2772 |
comment: function(text) {
|
|
2773 |
node.append(createNode('#comment', 8)).value = text;
|
|
2774 |
},
|
|
2775 |
|
|
2776 |
pi: function(name, text) {
|
|
2777 |
node.append(createNode(name, 7)).value = text;
|
|
2778 |
removeWhitespaceBefore(node);
|
|
2779 |
},
|
|
2780 |
|
|
2781 |
doctype: function(text) {
|
|
2782 |
var newNode;
|
|
2783 |
|
|
2784 |
newNode = node.append(createNode('#doctype', 10));
|
|
2785 |
newNode.value = text;
|
|
2786 |
removeWhitespaceBefore(node);
|
|
2787 |
},
|
|
2788 |
|
|
2789 |
start: function(name, attrs, empty) {
|
|
2790 |
var newNode, attrFiltersLen, elementRule, textNode, attrName, text, sibling, parent;
|
|
2791 |
|
|
2792 |
elementRule = validate ? schema.getElementRule(name) : {};
|
|
2793 |
if (elementRule) {
|
|
2794 |
newNode = createNode(elementRule.outputName || name, 1);
|
|
2795 |
newNode.attributes = attrs;
|
|
2796 |
newNode.shortEnded = empty;
|
|
2797 |
|
|
2798 |
node.append(newNode);
|
|
2799 |
|
|
2800 |
// Check if node is valid child of the parent node is the child is
|
|
2801 |
// unknown we don't collect it since it's probably a custom element
|
|
2802 |
parent = children[node.name];
|
|
2803 |
if (parent && children[newNode.name] && !parent[newNode.name])
|
|
2804 |
invalidChildren.push(newNode);
|
|
2805 |
|
|
2806 |
attrFiltersLen = attributeFilters.length;
|
|
2807 |
while (attrFiltersLen--) {
|
|
2808 |
attrName = attributeFilters[attrFiltersLen].name;
|
|
2809 |
|
|
2810 |
if (attrName in attrs.map) {
|
|
2811 |
list = matchedAttributes[attrName];
|
|
2812 |
|
|
2813 |
if (list)
|
|
2814 |
list.push(newNode);
|
|
2815 |
else
|
|
2816 |
matchedAttributes[attrName] = [newNode];
|
|
2817 |
}
|
|
2818 |
}
|
|
2819 |
|
|
2820 |
// Trim whitespace before block
|
|
2821 |
if (blockElements[name])
|
|
2822 |
removeWhitespaceBefore(newNode);
|
|
2823 |
|
|
2824 |
// Change current node if the element wasn't empty i.e not <br /> or <img />
|
|
2825 |
if (!empty)
|
|
2826 |
node = newNode;
|
|
2827 |
}
|
|
2828 |
},
|
|
2829 |
|
|
2830 |
end: function(name) {
|
|
2831 |
var textNode, elementRule, text, sibling, tempNode;
|
|
2832 |
|
|
2833 |
elementRule = validate ? schema.getElementRule(name) : {};
|
|
2834 |
if (elementRule) {
|
|
2835 |
if (blockElements[name]) {
|
|
2836 |
if (!whiteSpaceElements[node.name]) {
|
|
2837 |
// Trim whitespace at beginning of block
|
|
2838 |
for (textNode = node.firstChild; textNode && textNode.type === 3; ) {
|
|
2839 |
text = textNode.value.replace(startWhiteSpaceRegExp, '');
|
|
2840 |
|
|
2841 |
if (text.length > 0) {
|
|
2842 |
textNode.value = text;
|
|
2843 |
textNode = textNode.next;
|
|
2844 |
} else {
|
|
2845 |
sibling = textNode.next;
|
|
2846 |
textNode.remove();
|
|
2847 |
textNode = sibling;
|
|
2848 |
}
|
|
2849 |
}
|
|
2850 |
|
|
2851 |
// Trim whitespace at end of block
|
|
2852 |
for (textNode = node.lastChild; textNode && textNode.type === 3; ) {
|
|
2853 |
text = textNode.value.replace(endWhiteSpaceRegExp, '');
|
|
2854 |
|
|
2855 |
if (text.length > 0) {
|
|
2856 |
textNode.value = text;
|
|
2857 |
textNode = textNode.prev;
|
|
2858 |
} else {
|
|
2859 |
sibling = textNode.prev;
|
|
2860 |
textNode.remove();
|
|
2861 |
textNode = sibling;
|
|
2862 |
}
|
|
2863 |
}
|
|
2864 |
}
|
|
2865 |
|
|
2866 |
// Trim start white space
|
|
2867 |
textNode = node.prev;
|
|
2868 |
if (textNode && textNode.type === 3) {
|
|
2869 |
text = textNode.value.replace(startWhiteSpaceRegExp, '');
|
|
2870 |
|
|
2871 |
if (text.length > 0)
|
|
2872 |
textNode.value = text;
|
|
2873 |
else
|
|
2874 |
textNode.remove();
|
|
2875 |
}
|
|
2876 |
}
|
|
2877 |
|
|
2878 |
// Handle empty nodes
|
|
2879 |
if (elementRule.removeEmpty || elementRule.paddEmpty) {
|
|
2880 |
if (node.isEmpty(nonEmptyElements)) {
|
|
2881 |
if (elementRule.paddEmpty)
|
|
2882 |
node.empty().append(new Node('#text', '3')).value = '\u00a0';
|
|
2883 |
else {
|
|
2884 |
// Leave nodes that have a name like <a name="name">
|
|
2885 |
if (!node.attributes.map.name) {
|
|
2886 |
tempNode = node.parent;
|
|
2887 |
node.empty().remove();
|
|
2888 |
node = tempNode;
|
|
2889 |
return;
|
|
2890 |
}
|
|
2891 |
}
|
|
2892 |
}
|
|
2893 |
}
|
|
2894 |
|
|
2895 |
node = node.parent;
|
|
2896 |
}
|
|
2897 |
}
|
|
2898 |
}, schema);
|
|
2899 |
|
|
2900 |
rootNode = node = new Node(settings.root_name, 11);
|
|
2901 |
|
|
2902 |
parser.parse(html);
|
|
2903 |
|
|
2904 |
if (validate)
|
|
2905 |
fixInvalidChildren(invalidChildren);
|
|
2906 |
|
|
2907 |
// Run node filters
|
|
2908 |
for (name in matchedNodes) {
|
|
2909 |
list = nodeFilters[name];
|
|
2910 |
nodes = matchedNodes[name];
|
|
2911 |
|
|
2912 |
// Remove already removed children
|
|
2913 |
fi = nodes.length;
|
|
2914 |
while (fi--) {
|
|
2915 |
if (!nodes[fi].parent)
|
|
2916 |
nodes.splice(fi, 1);
|
|
2917 |
}
|
|
2918 |
|
|
2919 |
for (i = 0, l = list.length; i < l; i++)
|
|
2920 |
list[i](nodes, name, args);
|
|
2921 |
}
|
|
2922 |
|
|
2923 |
// Run attribute filters
|
|
2924 |
for (i = 0, l = attributeFilters.length; i < l; i++) {
|
|
2925 |
list = attributeFilters[i];
|
|
2926 |
|
|
2927 |
if (list.name in matchedAttributes) {
|
|
2928 |
nodes = matchedAttributes[list.name];
|
|
2929 |
|
|
2930 |
// Remove already removed children
|
|
2931 |
fi = nodes.length;
|
|
2932 |
while (fi--) {
|
|
2933 |
if (!nodes[fi].parent)
|
|
2934 |
nodes.splice(fi, 1);
|
|
2935 |
}
|
|
2936 |
|
|
2937 |
for (fi = 0, fl = list.callbacks.length; fi < fl; fi++)
|
|
2938 |
list.callbacks[fi](nodes, list.name, args);
|
|
2939 |
}
|
|
2940 |
}
|
|
2941 |
|
|
2942 |
return rootNode;
|
|
2943 |
};
|
|
2944 |
|
|
2945 |
// Remove <br> at end of block elements Gecko and WebKit injects BR elements to
|
|
2946 |
// make it possible to place the caret inside empty blocks. This logic tries to remove
|
|
2947 |
// these elements and keep br elements that where intended to be there intact
|
|
2948 |
if (settings.remove_trailing_brs) {
|
|
2949 |
self.addNodeFilter('br', function(nodes, name) {
|
|
2950 |
var i, l = nodes.length, node, blockElements = schema.getBlockElements(),
|
|
2951 |
nonEmptyElements = schema.getNonEmptyElements(), parent, prev, prevName;
|
|
2952 |
|
|
2953 |
// Must loop forwards since it will otherwise remove all brs in <p>a<br><br><br></p>
|
|
2954 |
for (i = 0; i < l; i++) {
|
|
2955 |
node = nodes[i];
|
|
2956 |
parent = node.parent;
|
|
2957 |
|
|
2958 |
if (blockElements[node.parent.name] && node === parent.lastChild) {
|
|
2959 |
// Loop all nodes to the right of the current node and check for other BR elements
|
|
2960 |
// excluding bookmarks since they are invisible
|
|
2961 |
prev = node.prev;
|
|
2962 |
while (prev) {
|
|
2963 |
prevName = prev.name;
|
|
2964 |
|
|
2965 |
// Ignore bookmarks
|
|
2966 |
if (prevName !== "span" || prev.attr('data-mce-type') !== 'bookmark') {
|
|
2967 |
// Found a non BR element
|
|
2968 |
if (prevName !== "br")
|
|
2969 |
break;
|
|
2970 |
|
|
2971 |
// Found another br it's a <br><br> structure then don't remove anything
|
|
2972 |
if (prevName === 'br') {
|
|
2973 |
node = null;
|
|
2974 |
break;
|
|
2975 |
}
|
|
2976 |
}
|
|
2977 |
|
|
2978 |
prev = prev.prev;
|
|
2979 |
}
|
|
2980 |
|
|
2981 |
if (node) {
|
|
2982 |
node.remove();
|
|
2983 |
|
|
2984 |
// Is the parent to be considered empty after we removed the BR
|
|
2985 |
if (parent.isEmpty(nonEmptyElements)) {
|
|
2986 |
elementRule = schema.getElementRule(parent.name);
|
|
2987 |
|
|
2988 |
// Remove or padd the element depending on schema rule
|
|
2989 |
if (elementRule.removeEmpty)
|
|
2990 |
parent.remove();
|
|
2991 |
else if (elementRule.paddEmpty)
|
|
2992 |
parent.empty().append(new tinymce.html.Node('#text', 3)).value = '\u00a0';
|
|
2993 |
}
|
|
2994 |
}
|
|
2995 |
}
|
|
2996 |
}
|
|
2997 |
});
|
|
2998 |
}
|
|
2999 |
}
|
|
3000 |
})(tinymce);
|
|
3001 |
|
|
3002 |
tinymce.html.Writer = function(settings) {
|
|
3003 |
var html = [], indent, indentBefore, indentAfter, encode, htmlOutput;
|
|
3004 |
|
|
3005 |
settings = settings || {};
|
|
3006 |
indent = settings.indent;
|
|
3007 |
indentBefore = tinymce.makeMap(settings.indent_before || '');
|
|
3008 |
indentAfter = tinymce.makeMap(settings.indent_after || '');
|
|
3009 |
encode = tinymce.html.Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
|
|
3010 |
htmlOutput = settings.element_format == "html";
|
|
3011 |
|
|
3012 |
return {
|
|
3013 |
start: function(name, attrs, empty) {
|
|
3014 |
var i, l, attr, value;
|
|
3015 |
|
|
3016 |
if (indent && indentBefore[name] && html.length > 0) {
|
|
3017 |
value = html[html.length - 1];
|
|
3018 |
|
|
3019 |
if (value.length > 0 && value !== '\n')
|
|
3020 |
html.push('\n');
|
|
3021 |
}
|
|
3022 |
|
|
3023 |
html.push('<', name);
|
|
3024 |
|
|
3025 |
if (attrs) {
|
|
3026 |
for (i = 0, l = attrs.length; i < l; i++) {
|
|
3027 |
attr = attrs[i];
|
|
3028 |
html.push(' ', attr.name, '="', encode(attr.value, true), '"');
|
|
3029 |
}
|
|
3030 |
}
|
|
3031 |
|
|
3032 |
if (!empty || htmlOutput)
|
|
3033 |
html[html.length] = '>';
|
|
3034 |
else
|
|
3035 |
html[html.length] = ' />';
|
|
3036 |
|
|
3037 |
if (empty && indent && indentAfter[name] && html.length > 0) {
|
|
3038 |
value = html[html.length - 1];
|
|
3039 |
|
|
3040 |
if (value.length > 0 && value !== '\n')
|
|
3041 |
html.push('\n');
|
|
3042 |
}
|
|
3043 |
},
|
|
3044 |
|
|
3045 |
end: function(name) {
|
|
3046 |
var value;
|
|
3047 |
|
|
3048 |
/*if (indent && indentBefore[name] && html.length > 0) {
|
|
3049 |
value = html[html.length - 1];
|
|
3050 |
|
|
3051 |
if (value.length > 0 && value !== '\n')
|
|
3052 |
html.push('\n');
|
|
3053 |
}*/
|
|
3054 |
|
|
3055 |
html.push('</', name, '>');
|
|
3056 |
|
|
3057 |
if (indent && indentAfter[name] && html.length > 0) {
|
|
3058 |
value = html[html.length - 1];
|
|
3059 |
|
|
3060 |
if (value.length > 0 && value !== '\n')
|
|
3061 |
html.push('\n');
|
|
3062 |
}
|
|
3063 |
},
|
|
3064 |
|
|
3065 |
text: function(text, raw) {
|
|
3066 |
if (text.length > 0)
|
|
3067 |
html[html.length] = raw ? text : encode(text);
|
|
3068 |
},
|
|
3069 |
|
|
3070 |
cdata: function(text) {
|
|
3071 |
html.push('<![CDATA[', text, ']]>');
|
|
3072 |
},
|
|
3073 |
|
|
3074 |
comment: function(text) {
|
|
3075 |
html.push('<!--', text, '-->');
|
|
3076 |
},
|
|
3077 |
|
|
3078 |
pi: function(name, text) {
|
|
3079 |
if (text)
|
|
3080 |
html.push('<?', name, ' ', text, '?>');
|
|
3081 |
else
|
|
3082 |
html.push('<?', name, '?>');
|
|
3083 |
|
|
3084 |
if (indent)
|
|
3085 |
html.push('\n');
|
|
3086 |
},
|
|
3087 |
|
|
3088 |
doctype: function(text) {
|
|
3089 |
html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
|
|
3090 |
},
|
|
3091 |
|
|
3092 |
reset: function() {
|
|
3093 |
html.length = 0;
|
|
3094 |
},
|
|
3095 |
|
|
3096 |
getContent: function() {
|
|
3097 |
return html.join('').replace(/\n$/, '');
|
|
3098 |
}
|
|
3099 |
};
|
|
3100 |
};
|
|
3101 |
|
|
3102 |
(function(tinymce) {
|
|
3103 |
tinymce.html.Serializer = function(settings, schema) {
|
|
3104 |
var self = this, writer = new tinymce.html.Writer(settings);
|
|
3105 |
|
|
3106 |
settings = settings || {};
|
|
3107 |
settings.validate = "validate" in settings ? settings.validate : true;
|
|
3108 |
|
|
3109 |
self.schema = schema = schema || new tinymce.html.Schema();
|
|
3110 |
self.writer = writer;
|
|
3111 |
|
|
3112 |
self.serialize = function(node) {
|
|
3113 |
var handlers, validate;
|
|
3114 |
|
|
3115 |
validate = settings.validate;
|
|
3116 |
|
|
3117 |
handlers = {
|
|
3118 |
// #text
|
|
3119 |
3: function(node, raw) {
|
|
3120 |
writer.text(node.value, node.raw);
|
|
3121 |
},
|
|
3122 |
|
|
3123 |
// #comment
|
|
3124 |
8: function(node) {
|
|
3125 |
writer.comment(node.value);
|
|
3126 |
},
|
|
3127 |
|
|
3128 |
// Processing instruction
|
|
3129 |
7: function(node) {
|
|
3130 |
writer.pi(node.name, node.value);
|
|
3131 |
},
|
|
3132 |
|
|
3133 |
// Doctype
|
|
3134 |
10: function(node) {
|
|
3135 |
writer.doctype(node.value);
|
|
3136 |
},
|
|
3137 |
|
|
3138 |
// CDATA
|
|
3139 |
4: function(node) {
|
|
3140 |
writer.cdata(node.value);
|
|
3141 |
},
|
|
3142 |
|
|
3143 |
// Document fragment
|
|
3144 |
11: function(node) {
|
|
3145 |
if ((node = node.firstChild)) {
|
|
3146 |
do {
|
|
3147 |
walk(node);
|
|
3148 |
} while (node = node.next);
|
|
3149 |
}
|
|
3150 |
}
|
|
3151 |
};
|
|
3152 |
|
|
3153 |
writer.reset();
|
|
3154 |
|
|
3155 |
function walk(node) {
|
|
3156 |
var handler = handlers[node.type], name, isEmpty, attrs, attrName, attrValue, sortedAttrs, i, l, elementRule;
|
|
3157 |
|
|
3158 |
if (!handler) {
|
|
3159 |
name = node.name;
|
|
3160 |
isEmpty = node.shortEnded;
|
|
3161 |
attrs = node.attributes;
|
|
3162 |
|
|
3163 |
// Sort attributes
|
|
3164 |
if (validate && attrs && attrs.length > 1) {
|
|
3165 |
sortedAttrs = [];
|
|
3166 |
sortedAttrs.map = {};
|
|
3167 |
|
|
3168 |
elementRule = schema.getElementRule(node.name);
|
|
3169 |
for (i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
|
|
3170 |
attrName = elementRule.attributesOrder[i];
|
|
3171 |
|
|
3172 |
if (attrName in attrs.map) {
|
|
3173 |
attrValue = attrs.map[attrName];
|
|
3174 |
sortedAttrs.map[attrName] = attrValue;
|
|
3175 |
sortedAttrs.push({name: attrName, value: attrValue});
|
|
3176 |
}
|
|
3177 |
}
|
|
3178 |
|
|
3179 |
for (i = 0, l = attrs.length; i < l; i++) {
|
|
3180 |
attrName = attrs[i].name;
|
|
3181 |
|
|
3182 |
if (!(attrName in sortedAttrs.map)) {
|
|
3183 |
attrValue = attrs.map[attrName];
|
|
3184 |
sortedAttrs.map[attrName] = attrValue;
|
|
3185 |
sortedAttrs.push({name: attrName, value: attrValue});
|
|
3186 |
}
|
|
3187 |
}
|
|
3188 |
|
|
3189 |
attrs = sortedAttrs;
|
|
3190 |
}
|
|
3191 |
|
|
3192 |
writer.start(node.name, attrs, isEmpty);
|
|
3193 |
|
|
3194 |
if (!isEmpty) {
|
|
3195 |
if ((node = node.firstChild)) {
|
|
3196 |
do {
|
|
3197 |
walk(node);
|
|
3198 |
} while (node = node.next);
|
|
3199 |
}
|
|
3200 |
|
|
3201 |
writer.end(name);
|
|
3202 |
}
|
|
3203 |
} else
|
|
3204 |
handler(node);
|
|
3205 |
}
|
|
3206 |
|
|
3207 |
// Serialize element and treat all non elements as fragments
|
|
3208 |
if (node.type == 1 && !settings.inner)
|
|
3209 |
walk(node);
|
|
3210 |
else
|
|
3211 |
handlers[11](node);
|
|
3212 |
|
|
3213 |
return writer.getContent();
|
|
3214 |
};
|
|
3215 |
}
|
|
3216 |
})(tinymce);
|
|
3217 |
|
|
3218 |
(function(tinymce) {
|
d9344f
|
3219 |
// Shorten names
|
69d05c
|
3220 |
var each = tinymce.each,
|
A |
3221 |
is = tinymce.is,
|
|
3222 |
isWebKit = tinymce.isWebKit,
|
|
3223 |
isIE = tinymce.isIE,
|
a9251b
|
3224 |
Entities = tinymce.html.Entities,
|
69d05c
|
3225 |
simpleSelectorRe = /^([a-z0-9],?)+$/i,
|
a9251b
|
3226 |
blockElementsMap = tinymce.html.Schema.blockElementsMap,
|
T |
3227 |
whiteSpaceRegExp = /^[ \t\r\n]*$/;
|
d9344f
|
3228 |
|
S |
3229 |
tinymce.create('tinymce.dom.DOMUtils', {
|
|
3230 |
doc : null,
|
|
3231 |
root : null,
|
|
3232 |
files : null,
|
|
3233 |
pixelStyles : /^(top|left|bottom|right|width|height|borderWidth)$/,
|
29da64
|
3234 |
props : {
|
A |
3235 |
"for" : "htmlFor",
|
|
3236 |
"class" : "className",
|
|
3237 |
className : "className",
|
|
3238 |
checked : "checked",
|
|
3239 |
disabled : "disabled",
|
|
3240 |
maxlength : "maxLength",
|
|
3241 |
readonly : "readOnly",
|
|
3242 |
selected : "selected",
|
|
3243 |
value : "value",
|
|
3244 |
id : "id",
|
|
3245 |
name : "name",
|
|
3246 |
type : "type"
|
|
3247 |
},
|
d9344f
|
3248 |
|
S |
3249 |
DOMUtils : function(d, s) {
|
69d05c
|
3250 |
var t = this, globalStyle;
|
d9344f
|
3251 |
|
S |
3252 |
t.doc = d;
|
|
3253 |
t.win = window;
|
|
3254 |
t.files = {};
|
|
3255 |
t.cssFlicker = false;
|
|
3256 |
t.counter = 0;
|
a9251b
|
3257 |
t.stdMode = !tinymce.isIE || d.documentMode >= 8;
|
T |
3258 |
t.boxModel = !tinymce.isIE || d.compatMode == "CSS1Compat" || t.stdMode;
|
|
3259 |
t.hasOuterHTML = "outerHTML" in d.createElement("a");
|
d9344f
|
3260 |
|
58fb65
|
3261 |
t.settings = s = tinymce.extend({
|
d9344f
|
3262 |
keep_values : false,
|
a9251b
|
3263 |
hex_colors : 1
|
d9344f
|
3264 |
}, s);
|
a9251b
|
3265 |
|
T |
3266 |
t.schema = s.schema;
|
|
3267 |
t.styles = new tinymce.html.Styles({
|
|
3268 |
url_converter : s.url_converter,
|
|
3269 |
url_converter_scope : s.url_converter_scope
|
|
3270 |
}, s.schema);
|
d9344f
|
3271 |
|
S |
3272 |
// Fix IE6SP2 flicker and check it failed for pre SP2
|
|
3273 |
if (tinymce.isIE6) {
|
|
3274 |
try {
|
|
3275 |
d.execCommand('BackgroundImageCache', false, true);
|
|
3276 |
} catch (e) {
|
|
3277 |
t.cssFlicker = true;
|
|
3278 |
}
|
69d05c
|
3279 |
}
|
A |
3280 |
|
a9251b
|
3281 |
if (isIE) {
|
T |
3282 |
// Add missing HTML 4/5 elements to IE
|
|
3283 |
('abbr article aside audio canvas ' +
|
|
3284 |
'details figcaption figure footer ' +
|
|
3285 |
'header hgroup mark menu meter nav ' +
|
|
3286 |
'output progress section summary ' +
|
|
3287 |
'time video').replace(/\w+/g, function(name) {
|
|
3288 |
d.createElement(name);
|
69d05c
|
3289 |
});
|
d9344f
|
3290 |
}
|
S |
3291 |
|
|
3292 |
tinymce.addUnload(t.destroy, t);
|
|
3293 |
},
|
|
3294 |
|
|
3295 |
getRoot : function() {
|
|
3296 |
var t = this, s = t.settings;
|
|
3297 |
|
|
3298 |
return (s && t.get(s.root_element)) || t.doc.body;
|
|
3299 |
},
|
|
3300 |
|
|
3301 |
getViewPort : function(w) {
|
|
3302 |
var d, b;
|
|
3303 |
|
|
3304 |
w = !w ? this.win : w;
|
|
3305 |
d = w.document;
|
|
3306 |
b = this.boxModel ? d.documentElement : d.body;
|
|
3307 |
|
|
3308 |
// Returns viewport size excluding scrollbars
|
|
3309 |
return {
|
|
3310 |
x : w.pageXOffset || b.scrollLeft,
|
|
3311 |
y : w.pageYOffset || b.scrollTop,
|
|
3312 |
w : w.innerWidth || b.clientWidth,
|
|
3313 |
h : w.innerHeight || b.clientHeight
|
|
3314 |
};
|
|
3315 |
},
|
|
3316 |
|
|
3317 |
getRect : function(e) {
|
29da64
|
3318 |
var p, t = this, sr;
|
d9344f
|
3319 |
|
S |
3320 |
e = t.get(e);
|
|
3321 |
p = t.getPos(e);
|
29da64
|
3322 |
sr = t.getSize(e);
|
A |
3323 |
|
|
3324 |
return {
|
|
3325 |
x : p.x,
|
|
3326 |
y : p.y,
|
|
3327 |
w : sr.w,
|
|
3328 |
h : sr.h
|
|
3329 |
};
|
|
3330 |
},
|
|
3331 |
|
|
3332 |
getSize : function(e) {
|
|
3333 |
var t = this, w, h;
|
|
3334 |
|
|
3335 |
e = t.get(e);
|
d9344f
|
3336 |
w = t.getStyle(e, 'width');
|
S |
3337 |
h = t.getStyle(e, 'height');
|
|
3338 |
|
|
3339 |
// Non pixel value, then force offset/clientWidth
|
|
3340 |
if (w.indexOf('px') === -1)
|
|
3341 |
w = 0;
|
|
3342 |
|
|
3343 |
// Non pixel value, then force offset/clientWidth
|
|
3344 |
if (h.indexOf('px') === -1)
|
|
3345 |
h = 0;
|
|
3346 |
|
|
3347 |
return {
|
|
3348 |
w : parseInt(w) || e.offsetWidth || e.clientWidth,
|
|
3349 |
h : parseInt(h) || e.offsetHeight || e.clientHeight
|
|
3350 |
};
|
|
3351 |
},
|
|
3352 |
|
29da64
|
3353 |
getParent : function(n, f, r) {
|
A |
3354 |
return this.getParents(n, f, r, false);
|
|
3355 |
},
|
|
3356 |
|
|
3357 |
getParents : function(n, f, r, c) {
|
|
3358 |
var t = this, na, se = t.settings, o = [];
|
|
3359 |
|
|
3360 |
n = t.get(n);
|
|
3361 |
c = c === undefined;
|
d9344f
|
3362 |
|
S |
3363 |
if (se.strict_root)
|
29da64
|
3364 |
r = r || t.getRoot();
|
d9344f
|
3365 |
|
S |
3366 |
// Wrap node name as func
|
|
3367 |
if (is(f, 'string')) {
|
29da64
|
3368 |
na = f;
|
d9344f
|
3369 |
|
29da64
|
3370 |
if (f === '*') {
|
A |
3371 |
f = function(n) {return n.nodeType == 1;};
|
|
3372 |
} else {
|
|
3373 |
f = function(n) {
|
|
3374 |
return t.is(n, na);
|
|
3375 |
};
|
|
3376 |
}
|
d9344f
|
3377 |
}
|
S |
3378 |
|
|
3379 |
while (n) {
|
29da64
|
3380 |
if (n == r || !n.nodeType || n.nodeType === 9)
|
A |
3381 |
break;
|
d9344f
|
3382 |
|
29da64
|
3383 |
if (!f || f(n)) {
|
A |
3384 |
if (c)
|
|
3385 |
o.push(n);
|
|
3386 |
else
|
|
3387 |
return n;
|
|
3388 |
}
|
d9344f
|
3389 |
|
S |
3390 |
n = n.parentNode;
|
|
3391 |
}
|
|
3392 |
|
29da64
|
3393 |
return c ? o : null;
|
d9344f
|
3394 |
},
|
S |
3395 |
|
|
3396 |
get : function(e) {
|
|
3397 |
var n;
|
|
3398 |
|
18240a
|
3399 |
if (e && this.doc && typeof(e) == 'string') {
|
d9344f
|
3400 |
n = e;
|
S |
3401 |
e = this.doc.getElementById(e);
|
|
3402 |
|
|
3403 |
// IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick
|
|
3404 |
if (e && e.id !== n)
|
|
3405 |
return this.doc.getElementsByName(n)[1];
|
|
3406 |
}
|
|
3407 |
|
|
3408 |
return e;
|
|
3409 |
},
|
|
3410 |
|
58fb65
|
3411 |
getNext : function(node, selector) {
|
A |
3412 |
return this._findSib(node, selector, 'nextSibling');
|
|
3413 |
},
|
|
3414 |
|
|
3415 |
getPrev : function(node, selector) {
|
|
3416 |
return this._findSib(node, selector, 'previousSibling');
|
|
3417 |
},
|
|
3418 |
|
d9344f
|
3419 |
|
S |
3420 |
select : function(pa, s) {
|
29da64
|
3421 |
var t = this;
|
d9344f
|
3422 |
|
29da64
|
3423 |
return tinymce.dom.Sizzle(pa, t.get(s) || t.get(t.settings.root_element) || t.doc, []);
|
58fb65
|
3424 |
},
|
A |
3425 |
|
69d05c
|
3426 |
is : function(n, selector) {
|
A |
3427 |
var i;
|
|
3428 |
|
|
3429 |
// If it isn't an array then try to do some simple selectors instead of Sizzle for to boost performance
|
|
3430 |
if (n.length === undefined) {
|
|
3431 |
// Simple all selector
|
|
3432 |
if (selector === '*')
|
|
3433 |
return n.nodeType == 1;
|
|
3434 |
|
|
3435 |
// Simple selector just elements
|
|
3436 |
if (simpleSelectorRe.test(selector)) {
|
|
3437 |
selector = selector.toLowerCase().split(/,/);
|
|
3438 |
n = n.nodeName.toLowerCase();
|
|
3439 |
|
|
3440 |
for (i = selector.length - 1; i >= 0; i--) {
|
|
3441 |
if (selector[i] == n)
|
|
3442 |
return true;
|
|
3443 |
}
|
|
3444 |
|
|
3445 |
return false;
|
|
3446 |
}
|
|
3447 |
}
|
|
3448 |
|
|
3449 |
return tinymce.dom.Sizzle.matches(selector, n.nodeType ? [n] : n).length > 0;
|
d9344f
|
3450 |
},
|
S |
3451 |
|
|
3452 |
|
|
3453 |
add : function(p, n, a, h, c) {
|
|
3454 |
var t = this;
|
|
3455 |
|
|
3456 |
return this.run(p, function(p) {
|
|
3457 |
var e, k;
|
|
3458 |
|
|
3459 |
e = is(n, 'string') ? t.doc.createElement(n) : n;
|
29da64
|
3460 |
t.setAttribs(e, a);
|
d9344f
|
3461 |
|
S |
3462 |
if (h) {
|
|
3463 |
if (h.nodeType)
|
|
3464 |
e.appendChild(h);
|
|
3465 |
else
|
|
3466 |
t.setHTML(e, h);
|
|
3467 |
}
|
|
3468 |
|
|
3469 |
return !c ? p.appendChild(e) : e;
|
|
3470 |
});
|
|
3471 |
},
|
|
3472 |
|
|
3473 |
create : function(n, a, h) {
|
|
3474 |
return this.add(this.doc.createElement(n), n, a, h, 1);
|
|
3475 |
},
|
|
3476 |
|
|
3477 |
createHTML : function(n, a, h) {
|
|
3478 |
var o = '', t = this, k;
|
|
3479 |
|
|
3480 |
o += '<' + n;
|
|
3481 |
|
|
3482 |
for (k in a) {
|
|
3483 |
if (a.hasOwnProperty(k))
|
|
3484 |
o += ' ' + k + '="' + t.encode(a[k]) + '"';
|
|
3485 |
}
|
|
3486 |
|
a9251b
|
3487 |
// A call to tinymce.is doesn't work for some odd reason on IE9 possible bug inside their JS runtime
|
T |
3488 |
if (typeof(h) != "undefined")
|
d9344f
|
3489 |
return o + '>' + h + '</' + n + '>';
|
S |
3490 |
|
|
3491 |
return o + ' />';
|
|
3492 |
},
|
|
3493 |
|
69d05c
|
3494 |
remove : function(node, keep_children) {
|
A |
3495 |
return this.run(node, function(node) {
|
a9251b
|
3496 |
var child, parent = node.parentNode;
|
d9344f
|
3497 |
|
69d05c
|
3498 |
if (!parent)
|
d9344f
|
3499 |
return null;
|
S |
3500 |
|
69d05c
|
3501 |
if (keep_children) {
|
A |
3502 |
while (child = node.firstChild) {
|
|
3503 |
// IE 8 will crash if you don't remove completely empty text nodes
|
2011be
|
3504 |
if (!tinymce.isIE || child.nodeType !== 3 || child.nodeValue)
|
69d05c
|
3505 |
parent.insertBefore(child, node);
|
A |
3506 |
else
|
|
3507 |
node.removeChild(child);
|
|
3508 |
}
|
d9344f
|
3509 |
}
|
S |
3510 |
|
69d05c
|
3511 |
return parent.removeChild(node);
|
d9344f
|
3512 |
});
|
S |
3513 |
},
|
|
3514 |
|
|
3515 |
setStyle : function(n, na, v) {
|
|
3516 |
var t = this;
|
|
3517 |
|
|
3518 |
return t.run(n, function(e) {
|
|
3519 |
var s, i;
|
|
3520 |
|
|
3521 |
s = e.style;
|
|
3522 |
|
|
3523 |
// Camelcase it, if needed
|
|
3524 |
na = na.replace(/-(\D)/g, function(a, b){
|
|
3525 |
return b.toUpperCase();
|
|
3526 |
});
|
|
3527 |
|
|
3528 |
// Default px suffix on these
|
|
3529 |
if (t.pixelStyles.test(na) && (tinymce.is(v, 'number') || /^[\-0-9\.]+$/.test(v)))
|
|
3530 |
v += 'px';
|
|
3531 |
|
|
3532 |
switch (na) {
|
|
3533 |
case 'opacity':
|
|
3534 |
// IE specific opacity
|
|
3535 |
if (isIE) {
|
|
3536 |
s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")";
|
|
3537 |
|
|
3538 |
if (!n.currentStyle || !n.currentStyle.hasLayout)
|
|
3539 |
s.display = 'inline-block';
|
|
3540 |
}
|
|
3541 |
|
|
3542 |
// Fix for older browsers
|
|
3543 |
s[na] = s['-moz-opacity'] = s['-khtml-opacity'] = v || '';
|
|
3544 |
break;
|
|
3545 |
|
|
3546 |
case 'float':
|
|
3547 |
isIE ? s.styleFloat = v : s.cssFloat = v;
|
|
3548 |
break;
|
|
3549 |
|
|
3550 |
default:
|
|
3551 |
s[na] = v || '';
|
|
3552 |
}
|
|
3553 |
|
|
3554 |
// Force update of the style data
|
|
3555 |
if (t.settings.update_styles)
|
a9251b
|
3556 |
t.setAttrib(e, 'data-mce-style');
|
d9344f
|
3557 |
});
|
S |
3558 |
},
|
|
3559 |
|
|
3560 |
getStyle : function(n, na, c) {
|
|
3561 |
n = this.get(n);
|
|
3562 |
|
|
3563 |
if (!n)
|
a9251b
|
3564 |
return;
|
d9344f
|
3565 |
|
S |
3566 |
// Gecko
|
|
3567 |
if (this.doc.defaultView && c) {
|
|
3568 |
// Remove camelcase
|
|
3569 |
na = na.replace(/[A-Z]/g, function(a){
|
|
3570 |
return '-' + a;
|
|
3571 |
});
|
|
3572 |
|
|
3573 |
try {
|
|
3574 |
return this.doc.defaultView.getComputedStyle(n, null).getPropertyValue(na);
|
|
3575 |
} catch (ex) {
|
|
3576 |
// Old safari might fail
|
|
3577 |
return null;
|
|
3578 |
}
|
|
3579 |
}
|
|
3580 |
|
|
3581 |
// Camelcase it, if needed
|
|
3582 |
na = na.replace(/-(\D)/g, function(a, b){
|
|
3583 |
return b.toUpperCase();
|
|
3584 |
});
|
|
3585 |
|
|
3586 |
if (na == 'float')
|
|
3587 |
na = isIE ? 'styleFloat' : 'cssFloat';
|
|
3588 |
|
|
3589 |
// IE & Opera
|
|
3590 |
if (n.currentStyle && c)
|
|
3591 |
return n.currentStyle[na];
|
|
3592 |
|
a9251b
|
3593 |
return n.style ? n.style[na] : undefined;
|
d9344f
|
3594 |
},
|
S |
3595 |
|
|
3596 |
setStyles : function(e, o) {
|
|
3597 |
var t = this, s = t.settings, ol;
|
|
3598 |
|
|
3599 |
ol = s.update_styles;
|
|
3600 |
s.update_styles = 0;
|
|
3601 |
|
|
3602 |
each(o, function(v, n) {
|
|
3603 |
t.setStyle(e, n, v);
|
|
3604 |
});
|
|
3605 |
|
|
3606 |
// Update style info
|
|
3607 |
s.update_styles = ol;
|
|
3608 |
if (s.update_styles)
|
|
3609 |
t.setAttrib(e, s.cssText);
|
a9251b
|
3610 |
},
|
T |
3611 |
|
|
3612 |
removeAllAttribs: function(e) {
|
|
3613 |
return this.run(e, function(e) {
|
|
3614 |
var i, attrs = e.attributes;
|
|
3615 |
for (i = attrs.length - 1; i >= 0; i--) {
|
|
3616 |
e.removeAttributeNode(attrs.item(i));
|
|
3617 |
}
|
|
3618 |
});
|
d9344f
|
3619 |
},
|
S |
3620 |
|
|
3621 |
setAttrib : function(e, n, v) {
|
|
3622 |
var t = this;
|
|
3623 |
|
29da64
|
3624 |
// Whats the point
|
A |
3625 |
if (!e || !n)
|
|
3626 |
return;
|
|
3627 |
|
d9344f
|
3628 |
// Strict XML mode
|
S |
3629 |
if (t.settings.strict)
|
|
3630 |
n = n.toLowerCase();
|
|
3631 |
|
|
3632 |
return this.run(e, function(e) {
|
|
3633 |
var s = t.settings;
|
|
3634 |
|
|
3635 |
switch (n) {
|
|
3636 |
case "style":
|
29da64
|
3637 |
if (!is(v, 'string')) {
|
A |
3638 |
each(v, function(v, n) {
|
|
3639 |
t.setStyle(e, n, v);
|
|
3640 |
});
|
|
3641 |
|
|
3642 |
return;
|
|
3643 |
}
|
|
3644 |
|
18240a
|
3645 |
// No mce_style for elements with these since they might get resized by the user
|
d9344f
|
3646 |
if (s.keep_values) {
|
18240a
|
3647 |
if (v && !t._isRes(v))
|
a9251b
|
3648 |
e.setAttribute('data-mce-style', v, 2);
|
d9344f
|
3649 |
else
|
a9251b
|
3650 |
e.removeAttribute('data-mce-style', 2);
|
d9344f
|
3651 |
}
|
S |
3652 |
|
|
3653 |
e.style.cssText = v;
|
|
3654 |
break;
|
|
3655 |
|
|
3656 |
case "class":
|
|
3657 |
e.className = v || ''; // Fix IE null bug
|
|
3658 |
break;
|
|
3659 |
|
|
3660 |
case "src":
|
|
3661 |
case "href":
|
|
3662 |
if (s.keep_values) {
|
|
3663 |
if (s.url_converter)
|
|
3664 |
v = s.url_converter.call(s.url_converter_scope || t, v, n, e);
|
|
3665 |
|
a9251b
|
3666 |
t.setAttrib(e, 'data-mce-' + n, v, 2);
|
d9344f
|
3667 |
}
|
S |
3668 |
|
18240a
|
3669 |
break;
|
a9251b
|
3670 |
|
18240a
|
3671 |
case "shape":
|
a9251b
|
3672 |
e.setAttribute('data-mce-style', v);
|
d9344f
|
3673 |
break;
|
S |
3674 |
}
|
|
3675 |
|
|
3676 |
if (is(v) && v !== null && v.length !== 0)
|
|
3677 |
e.setAttribute(n, '' + v, 2);
|
|
3678 |
else
|
|
3679 |
e.removeAttribute(n, 2);
|
|
3680 |
});
|
|
3681 |
},
|
|
3682 |
|
|
3683 |
setAttribs : function(e, o) {
|
|
3684 |
var t = this;
|
|
3685 |
|
|
3686 |
return this.run(e, function(e) {
|
|
3687 |
each(o, function(v, n) {
|
|
3688 |
t.setAttrib(e, n, v);
|
|
3689 |
});
|
|
3690 |
});
|
|
3691 |
},
|
|
3692 |
|
|
3693 |
getAttrib : function(e, n, dv) {
|
|
3694 |
var v, t = this;
|
|
3695 |
|
|
3696 |
e = t.get(e);
|
|
3697 |
|
18240a
|
3698 |
if (!e || e.nodeType !== 1)
|
d9344f
|
3699 |
return false;
|
S |
3700 |
|
|
3701 |
if (!is(dv))
|
29da64
|
3702 |
dv = '';
|
d9344f
|
3703 |
|
S |
3704 |
// Try the mce variant for these
|
18240a
|
3705 |
if (/^(src|href|style|coords|shape)$/.test(n)) {
|
a9251b
|
3706 |
v = e.getAttribute("data-mce-" + n);
|
d9344f
|
3707 |
|
S |
3708 |
if (v)
|
|
3709 |
return v;
|
|
3710 |
}
|
|
3711 |
|
29da64
|
3712 |
if (isIE && t.props[n]) {
|
A |
3713 |
v = e[t.props[n]];
|
|
3714 |
v = v && v.nodeValue ? v.nodeValue : v;
|
d9344f
|
3715 |
}
|
S |
3716 |
|
29da64
|
3717 |
if (!v)
|
A |
3718 |
v = e.getAttribute(n, 2);
|
58fb65
|
3719 |
|
A |
3720 |
// Check boolean attribs
|
|
3721 |
if (/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(n)) {
|
|
3722 |
if (e[t.props[n]] === true && v === '')
|
|
3723 |
return n;
|
|
3724 |
|
|
3725 |
return v ? n : '';
|
|
3726 |
}
|
|
3727 |
|
|
3728 |
// Inner input elements will override attributes on form elements
|
|
3729 |
if (e.nodeName === "FORM" && e.getAttributeNode(n))
|
|
3730 |
return e.getAttributeNode(n).nodeValue;
|
d9344f
|
3731 |
|
29da64
|
3732 |
if (n === 'style') {
|
A |
3733 |
v = v || e.style.cssText;
|
d9344f
|
3734 |
|
29da64
|
3735 |
if (v) {
|
69d05c
|
3736 |
v = t.serializeStyle(t.parseStyle(v), e.nodeName);
|
d9344f
|
3737 |
|
29da64
|
3738 |
if (t.settings.keep_values && !t._isRes(v))
|
a9251b
|
3739 |
e.setAttribute('data-mce-style', v);
|
29da64
|
3740 |
}
|
d9344f
|
3741 |
}
|
S |
3742 |
|
|
3743 |
// Remove Apple and WebKit stuff
|
|
3744 |
if (isWebKit && n === "class" && v)
|
|
3745 |
v = v.replace(/(apple|webkit)\-[a-z\-]+/gi, '');
|
|
3746 |
|
|
3747 |
// Handle IE issues
|
|
3748 |
if (isIE) {
|
|
3749 |
switch (n) {
|
|
3750 |
case 'rowspan':
|
|
3751 |
case 'colspan':
|
|
3752 |
// IE returns 1 as default value
|
|
3753 |
if (v === 1)
|
|
3754 |
v = '';
|
|
3755 |
|
|
3756 |
break;
|
|
3757 |
|
|
3758 |
case 'size':
|
|
3759 |
// IE returns +0 as default value for size
|
29da64
|
3760 |
if (v === '+0' || v === 20 || v === 0)
|
A |
3761 |
v = '';
|
|
3762 |
|
|
3763 |
break;
|
|
3764 |
|
|
3765 |
case 'width':
|
|
3766 |
case 'height':
|
|
3767 |
case 'vspace':
|
|
3768 |
case 'checked':
|
|
3769 |
case 'disabled':
|
|
3770 |
case 'readonly':
|
|
3771 |
if (v === 0)
|
d9344f
|
3772 |
v = '';
|
S |
3773 |
|
|
3774 |
break;
|
|
3775 |
|
|
3776 |
case 'hspace':
|
|
3777 |
// IE returns -1 as default value
|
|
3778 |
if (v === -1)
|
|
3779 |
v = '';
|
|
3780 |
|
|
3781 |
break;
|
|
3782 |
|
29da64
|
3783 |
case 'maxlength':
|
d9344f
|
3784 |
case 'tabindex':
|
18240a
|
3785 |
// IE returns default value
|
29da64
|
3786 |
if (v === 32768 || v === 2147483647 || v === '32768')
|
18240a
|
3787 |
v = '';
|
A |
3788 |
|
|
3789 |
break;
|
|
3790 |
|
29da64
|
3791 |
case 'multiple':
|
A |
3792 |
case 'compact':
|
|
3793 |
case 'noshade':
|
|
3794 |
case 'nowrap':
|
|
3795 |
if (v === 65535)
|
|
3796 |
return n;
|
d9344f
|
3797 |
|
29da64
|
3798 |
return dv;
|
d9344f
|
3799 |
|
S |
3800 |
case 'shape':
|
|
3801 |
v = v.toLowerCase();
|
|
3802 |
break;
|
|
3803 |
|
|
3804 |
default:
|
|
3805 |
// IE has odd anonymous function for event attributes
|
|
3806 |
if (n.indexOf('on') === 0 && v)
|
a9251b
|
3807 |
v = tinymce._replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/, '$1', '' + v);
|
d9344f
|
3808 |
}
|
S |
3809 |
}
|
|
3810 |
|
29da64
|
3811 |
return (v !== undefined && v !== null && v !== '') ? '' + v : dv;
|
d9344f
|
3812 |
},
|
S |
3813 |
|
29da64
|
3814 |
getPos : function(n, ro) {
|
d9344f
|
3815 |
var t = this, x = 0, y = 0, e, d = t.doc, r;
|
S |
3816 |
|
|
3817 |
n = t.get(n);
|
29da64
|
3818 |
ro = ro || d.body;
|
d9344f
|
3819 |
|
29da64
|
3820 |
if (n) {
|
A |
3821 |
// Use getBoundingClientRect on IE, Opera has it but it's not perfect
|
|
3822 |
if (isIE && !t.stdMode) {
|
|
3823 |
n = n.getBoundingClientRect();
|
|
3824 |
e = t.boxModel ? d.documentElement : d.body;
|
|
3825 |
x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border
|
|
3826 |
x = (x == 'medium' || t.boxModel && !t.isIE6) && 2 || x;
|
d9344f
|
3827 |
|
29da64
|
3828 |
return {x : n.left + e.scrollLeft - x, y : n.top + e.scrollTop - x};
|
d9344f
|
3829 |
}
|
S |
3830 |
|
29da64
|
3831 |
r = n;
|
A |
3832 |
while (r && r != ro && r.nodeType) {
|
|
3833 |
x += r.offsetLeft || 0;
|
|
3834 |
y += r.offsetTop || 0;
|
|
3835 |
r = r.offsetParent;
|
|
3836 |
}
|
d9344f
|
3837 |
|
29da64
|
3838 |
r = n.parentNode;
|
A |
3839 |
while (r && r != ro && r.nodeType) {
|
|
3840 |
x -= r.scrollLeft || 0;
|
|
3841 |
y -= r.scrollTop || 0;
|
|
3842 |
r = r.parentNode;
|
|
3843 |
}
|
d9344f
|
3844 |
}
|
S |
3845 |
|
|
3846 |
return {x : x, y : y};
|
|
3847 |
},
|
|
3848 |
|
|
3849 |
parseStyle : function(st) {
|
a9251b
|
3850 |
return this.styles.parse(st);
|
d9344f
|
3851 |
},
|
S |
3852 |
|
69d05c
|
3853 |
serializeStyle : function(o, name) {
|
a9251b
|
3854 |
return this.styles.serialize(o, name);
|
d9344f
|
3855 |
},
|
S |
3856 |
|
|
3857 |
loadCSS : function(u) {
|
58fb65
|
3858 |
var t = this, d = t.doc, head;
|
d9344f
|
3859 |
|
S |
3860 |
if (!u)
|
|
3861 |
u = '';
|
|
3862 |
|
58fb65
|
3863 |
head = t.select('head')[0];
|
A |
3864 |
|
d9344f
|
3865 |
each(u.split(','), function(u) {
|
58fb65
|
3866 |
var link;
|
A |
3867 |
|
d9344f
|
3868 |
if (t.files[u])
|
S |
3869 |
return;
|
|
3870 |
|
|
3871 |
t.files[u] = true;
|
58fb65
|
3872 |
link = t.create('link', {rel : 'stylesheet', href : tinymce._addVer(u)});
|
A |
3873 |
|
|
3874 |
// IE 8 has a bug where dynamically loading stylesheets would produce a 1 item remaining bug
|
|
3875 |
// This fix seems to resolve that issue by realcing the document ones a stylesheet finishes loading
|
|
3876 |
// It's ugly but it seems to work fine.
|
a9251b
|
3877 |
if (isIE && d.documentMode && d.recalc) {
|
58fb65
|
3878 |
link.onload = function() {
|
a9251b
|
3879 |
if (d.recalc)
|
T |
3880 |
d.recalc();
|
|
3881 |
|
58fb65
|
3882 |
link.onload = null;
|
A |
3883 |
};
|
|
3884 |
}
|
|
3885 |
|
|
3886 |
head.appendChild(link);
|
d9344f
|
3887 |
});
|
S |
3888 |
},
|
|
3889 |
|
|
3890 |
addClass : function(e, c) {
|
|
3891 |
return this.run(e, function(e) {
|
|
3892 |
var o;
|
|
3893 |
|
|
3894 |
if (!c)
|
|
3895 |
return 0;
|
|
3896 |
|
|
3897 |
if (this.hasClass(e, c))
|
|
3898 |
return e.className;
|
|
3899 |
|
|
3900 |
o = this.removeClass(e, c);
|
|
3901 |
|
|
3902 |
return e.className = (o != '' ? (o + ' ') : '') + c;
|
|
3903 |
});
|
|
3904 |
},
|
|
3905 |
|
|
3906 |
removeClass : function(e, c) {
|
|
3907 |
var t = this, re;
|
|
3908 |
|
|
3909 |
return t.run(e, function(e) {
|
|
3910 |
var v;
|
|
3911 |
|
|
3912 |
if (t.hasClass(e, c)) {
|
|
3913 |
if (!re)
|
|
3914 |
re = new RegExp("(^|\\s+)" + c + "(\\s+|$)", "g");
|
|
3915 |
|
|
3916 |
v = e.className.replace(re, ' ');
|
69d05c
|
3917 |
v = tinymce.trim(v != ' ' ? v : '');
|
d9344f
|
3918 |
|
69d05c
|
3919 |
e.className = v;
|
A |
3920 |
|
|
3921 |
// Empty class attr
|
|
3922 |
if (!v) {
|
|
3923 |
e.removeAttribute('class');
|
|
3924 |
e.removeAttribute('className');
|
|
3925 |
}
|
|
3926 |
|
|
3927 |
return v;
|
d9344f
|
3928 |
}
|
S |
3929 |
|
|
3930 |
return e.className;
|
|
3931 |
});
|
|
3932 |
},
|
|
3933 |
|
|
3934 |
hasClass : function(n, c) {
|
|
3935 |
n = this.get(n);
|
|
3936 |
|
|
3937 |
if (!n || !c)
|
|
3938 |
return false;
|
|
3939 |
|
|
3940 |
return (' ' + n.className + ' ').indexOf(' ' + c + ' ') !== -1;
|
|
3941 |
},
|
|
3942 |
|
|
3943 |
show : function(e) {
|
|
3944 |
return this.setStyle(e, 'display', 'block');
|
|
3945 |
},
|
|
3946 |
|
|
3947 |
hide : function(e) {
|
|
3948 |
return this.setStyle(e, 'display', 'none');
|
|
3949 |
},
|
|
3950 |
|
|
3951 |
isHidden : function(e) {
|
|
3952 |
e = this.get(e);
|
|
3953 |
|
29da64
|
3954 |
return !e || e.style.display == 'none' || this.getStyle(e, 'display') == 'none';
|
d9344f
|
3955 |
},
|
S |
3956 |
|
|
3957 |
uniqueId : function(p) {
|
|
3958 |
return (!p ? 'mce_' : p) + (this.counter++);
|
|
3959 |
},
|
|
3960 |
|
a9251b
|
3961 |
setHTML : function(element, html) {
|
T |
3962 |
var self = this;
|
d9344f
|
3963 |
|
a9251b
|
3964 |
return self.run(element, function(element) {
|
d9344f
|
3965 |
if (isIE) {
|
a9251b
|
3966 |
// Remove all child nodes, IE keeps empty text nodes in DOM
|
T |
3967 |
while (element.firstChild)
|
|
3968 |
element.removeChild(element.firstChild);
|
69d05c
|
3969 |
|
a9251b
|
3970 |
try {
|
T |
3971 |
// IE will remove comments from the beginning
|
|
3972 |
// unless you padd the contents with something
|
|
3973 |
element.innerHTML = '<br />' + html;
|
|
3974 |
element.removeChild(element.firstChild);
|
|
3975 |
} catch (ex) {
|
|
3976 |
// 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
|
|
3977 |
// This seems to fix this problem
|
d9344f
|
3978 |
|
a9251b
|
3979 |
// Create new div with HTML contents and a BR infront to keep comments
|
T |
3980 |
element = self.create('div');
|
|
3981 |
element.innerHTML = '<br />' + html;
|
d9344f
|
3982 |
|
a9251b
|
3983 |
// Add all children from div to target
|
T |
3984 |
each (element.childNodes, function(node, i) {
|
|
3985 |
// Skip br element
|
|
3986 |
if (i)
|
|
3987 |
element.appendChild(node);
|
|
3988 |
});
|
d9344f
|
3989 |
}
|
S |
3990 |
} else
|
a9251b
|
3991 |
element.innerHTML = html;
|
d9344f
|
3992 |
|
a9251b
|
3993 |
return html;
|
d9344f
|
3994 |
});
|
S |
3995 |
},
|
|
3996 |
|
a9251b
|
3997 |
getOuterHTML : function(elm) {
|
T |
3998 |
var doc, self = this;
|
d9344f
|
3999 |
|
a9251b
|
4000 |
elm = self.get(elm);
|
d9344f
|
4001 |
|
a9251b
|
4002 |
if (!elm)
|
d9344f
|
4003 |
return null;
|
S |
4004 |
|
a9251b
|
4005 |
if (elm.nodeType === 1 && self.hasOuterHTML)
|
T |
4006 |
return elm.outerHTML;
|
d9344f
|
4007 |
|
a9251b
|
4008 |
doc = (elm.ownerDocument || self.doc).createElement("body");
|
T |
4009 |
doc.appendChild(elm.cloneNode(true));
|
d9344f
|
4010 |
|
a9251b
|
4011 |
return doc.innerHTML;
|
d9344f
|
4012 |
},
|
S |
4013 |
|
|
4014 |
setOuterHTML : function(e, h, d) {
|
|
4015 |
var t = this;
|
|
4016 |
|
58fb65
|
4017 |
function setHTML(e, h, d) {
|
d9344f
|
4018 |
var n, tp;
|
69d05c
|
4019 |
|
58fb65
|
4020 |
tp = d.createElement("body");
|
A |
4021 |
tp.innerHTML = h;
|
d9344f
|
4022 |
|
58fb65
|
4023 |
n = tp.lastChild;
|
A |
4024 |
while (n) {
|
|
4025 |
t.insertAfter(n.cloneNode(true), e);
|
|
4026 |
n = n.previousSibling;
|
|
4027 |
}
|
|
4028 |
|
|
4029 |
t.remove(e);
|
|
4030 |
};
|
|
4031 |
|
|
4032 |
return this.run(e, function(e) {
|
d9344f
|
4033 |
e = t.get(e);
|
S |
4034 |
|
58fb65
|
4035 |
// Only set HTML on elements
|
A |
4036 |
if (e.nodeType == 1) {
|
|
4037 |
d = d || e.ownerDocument || t.doc;
|
d9344f
|
4038 |
|
58fb65
|
4039 |
if (isIE) {
|
A |
4040 |
try {
|
|
4041 |
// Try outerHTML for IE it sometimes produces an unknown runtime error
|
|
4042 |
if (isIE && e.nodeType == 1)
|
|
4043 |
e.outerHTML = h;
|
|
4044 |
else
|
|
4045 |
setHTML(e, h, d);
|
|
4046 |
} catch (ex) {
|
|
4047 |
// Fix for unknown runtime error
|
|
4048 |
setHTML(e, h, d);
|
|
4049 |
}
|
|
4050 |
} else
|
|
4051 |
setHTML(e, h, d);
|
d9344f
|
4052 |
}
|
S |
4053 |
});
|
|
4054 |
},
|
|
4055 |
|
a9251b
|
4056 |
decode : Entities.decode,
|
d9344f
|
4057 |
|
a9251b
|
4058 |
encode : Entities.encodeAllRaw,
|
d9344f
|
4059 |
|
69d05c
|
4060 |
insertAfter : function(node, reference_node) {
|
A |
4061 |
reference_node = this.get(reference_node);
|
d9344f
|
4062 |
|
69d05c
|
4063 |
return this.run(node, function(node) {
|
A |
4064 |
var parent, nextSibling;
|
d9344f
|
4065 |
|
69d05c
|
4066 |
parent = reference_node.parentNode;
|
A |
4067 |
nextSibling = reference_node.nextSibling;
|
d9344f
|
4068 |
|
69d05c
|
4069 |
if (nextSibling)
|
A |
4070 |
parent.insertBefore(node, nextSibling);
|
d9344f
|
4071 |
else
|
69d05c
|
4072 |
parent.appendChild(node);
|
d9344f
|
4073 |
|
69d05c
|
4074 |
return node;
|
d9344f
|
4075 |
});
|
S |
4076 |
},
|
|
4077 |
|
a9251b
|
4078 |
isBlock : function(node) {
|
T |
4079 |
var type = node.nodeType;
|
d9344f
|
4080 |
|
a9251b
|
4081 |
// If it's a node then check the type and use the nodeName
|
T |
4082 |
if (type)
|
|
4083 |
return !!(type === 1 && blockElementsMap[node.nodeName]);
|
d9344f
|
4084 |
|
a9251b
|
4085 |
return !!blockElementsMap[node];
|
d9344f
|
4086 |
},
|
S |
4087 |
|
|
4088 |
replace : function(n, o, k) {
|
29da64
|
4089 |
var t = this;
|
A |
4090 |
|
d9344f
|
4091 |
if (is(o, 'array'))
|
S |
4092 |
n = n.cloneNode(true);
|
|
4093 |
|
29da64
|
4094 |
return t.run(o, function(o) {
|
d9344f
|
4095 |
if (k) {
|
69d05c
|
4096 |
each(tinymce.grep(o.childNodes), function(c) {
|
A |
4097 |
n.appendChild(c);
|
d9344f
|
4098 |
});
|
29da64
|
4099 |
}
|
d9344f
|
4100 |
|
S |
4101 |
return o.parentNode.replaceChild(n, o);
|
|
4102 |
});
|
69d05c
|
4103 |
},
|
A |
4104 |
|
|
4105 |
rename : function(elm, name) {
|
|
4106 |
var t = this, newElm;
|
|
4107 |
|
|
4108 |
if (elm.nodeName != name.toUpperCase()) {
|
|
4109 |
// Rename block element
|
|
4110 |
newElm = t.create(name);
|
|
4111 |
|
|
4112 |
// Copy attribs to new block
|
|
4113 |
each(t.getAttribs(elm), function(attr_node) {
|
|
4114 |
t.setAttrib(newElm, attr_node.nodeName, t.getAttrib(elm, attr_node.nodeName));
|
|
4115 |
});
|
|
4116 |
|
|
4117 |
// Replace block
|
|
4118 |
t.replace(newElm, elm, 1);
|
|
4119 |
}
|
|
4120 |
|
|
4121 |
return newElm || elm;
|
d9344f
|
4122 |
},
|
29da64
|
4123 |
|
A |
4124 |
findCommonAncestor : function(a, b) {
|
|
4125 |
var ps = a, pe;
|
|
4126 |
|
|
4127 |
while (ps) {
|
|
4128 |
pe = b;
|
|
4129 |
|
|
4130 |
while (pe && ps != pe)
|
|
4131 |
pe = pe.parentNode;
|
|
4132 |
|
|
4133 |
if (ps == pe)
|
|
4134 |
break;
|
|
4135 |
|
|
4136 |
ps = ps.parentNode;
|
|
4137 |
}
|
|
4138 |
|
|
4139 |
if (!ps && a.ownerDocument)
|
|
4140 |
return a.ownerDocument.documentElement;
|
|
4141 |
|
|
4142 |
return ps;
|
|
4143 |
},
|
d9344f
|
4144 |
|
S |
4145 |
toHex : function(s) {
|
|
4146 |
var c = /^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(s);
|
|
4147 |
|
|
4148 |
function hex(s) {
|
|
4149 |
s = parseInt(s).toString(16);
|
|
4150 |
|
|
4151 |
return s.length > 1 ? s : '0' + s; // 0 -> 00
|
|
4152 |
};
|
|
4153 |
|
|
4154 |
if (c) {
|
|
4155 |
s = '#' + hex(c[1]) + hex(c[2]) + hex(c[3]);
|
|
4156 |
|
|
4157 |
return s;
|
|
4158 |
}
|
|
4159 |
|
|
4160 |
return s;
|
|
4161 |
},
|
|
4162 |
|
|
4163 |
getClasses : function() {
|
|
4164 |
var t = this, cl = [], i, lo = {}, f = t.settings.class_filter, ov;
|
|
4165 |
|
|
4166 |
if (t.classes)
|
|
4167 |
return t.classes;
|
|
4168 |
|
|
4169 |
function addClasses(s) {
|
|
4170 |
// IE style imports
|
|
4171 |
each(s.imports, function(r) {
|
|
4172 |
addClasses(r);
|
|
4173 |
});
|
|
4174 |
|
|
4175 |
each(s.cssRules || s.rules, function(r) {
|
|
4176 |
// Real type or fake it on IE
|
|
4177 |
switch (r.type || 1) {
|
|
4178 |
// Rule
|
|
4179 |
case 1:
|
|
4180 |
if (r.selectorText) {
|
|
4181 |
each(r.selectorText.split(','), function(v) {
|
|
4182 |
v = v.replace(/^\s*|\s*$|^\s\./g, "");
|
|
4183 |
|
|
4184 |
// Is internal or it doesn't contain a class
|
|
4185 |
if (/\.mce/.test(v) || !/\.[\w\-]+$/.test(v))
|
|
4186 |
return;
|
|
4187 |
|
|
4188 |
// Remove everything but class name
|
|
4189 |
ov = v;
|
a9251b
|
4190 |
v = tinymce._replace(/.*\.([a-z0-9_\-]+).*/i, '$1', v);
|
d9344f
|
4191 |
|
S |
4192 |
// Filter classes
|
|
4193 |
if (f && !(v = f(v, ov)))
|
|
4194 |
return;
|
|
4195 |
|
|
4196 |
if (!lo[v]) {
|
|
4197 |
cl.push({'class' : v});
|
|
4198 |
lo[v] = 1;
|
|
4199 |
}
|
|
4200 |
});
|
|
4201 |
}
|
|
4202 |
break;
|
|
4203 |
|
|
4204 |
// Import
|
|
4205 |
case 3:
|
|
4206 |
addClasses(r.styleSheet);
|
|
4207 |
break;
|
|
4208 |
}
|
|
4209 |
});
|
|
4210 |
};
|
|
4211 |
|
|
4212 |
try {
|
|
4213 |
each(t.doc.styleSheets, addClasses);
|
|
4214 |
} catch (ex) {
|
|
4215 |
// Ignore
|
|
4216 |
}
|
|
4217 |
|
|
4218 |
if (cl.length > 0)
|
|
4219 |
t.classes = cl;
|
|
4220 |
|
|
4221 |
return cl;
|
|
4222 |
},
|
|
4223 |
|
|
4224 |
run : function(e, f, s) {
|
|
4225 |
var t = this, o;
|
|
4226 |
|
|
4227 |
if (t.doc && typeof(e) === 'string')
|
29da64
|
4228 |
e = t.get(e);
|
d9344f
|
4229 |
|
S |
4230 |
if (!e)
|
|
4231 |
return false;
|
|
4232 |
|
|
4233 |
s = s || this;
|
|
4234 |
if (!e.nodeType && (e.length || e.length === 0)) {
|
|
4235 |
o = [];
|
|
4236 |
|
|
4237 |
each(e, function(e, i) {
|
|
4238 |
if (e) {
|
|
4239 |
if (typeof(e) == 'string')
|
|
4240 |
e = t.doc.getElementById(e);
|
|
4241 |
|
|
4242 |
o.push(f.call(s, e, i));
|
|
4243 |
}
|
|
4244 |
});
|
|
4245 |
|
|
4246 |
return o;
|
|
4247 |
}
|
|
4248 |
|
|
4249 |
return f.call(s, e);
|
|
4250 |
},
|
|
4251 |
|
|
4252 |
getAttribs : function(n) {
|
|
4253 |
var o;
|
|
4254 |
|
|
4255 |
n = this.get(n);
|
|
4256 |
|
|
4257 |
if (!n)
|
|
4258 |
return [];
|
|
4259 |
|
|
4260 |
if (isIE) {
|
|
4261 |
o = [];
|
|
4262 |
|
|
4263 |
// Object will throw exception in IE
|
|
4264 |
if (n.nodeName == 'OBJECT')
|
|
4265 |
return n.attributes;
|
|
4266 |
|
58fb65
|
4267 |
// IE doesn't keep the selected attribute if you clone option elements
|
A |
4268 |
if (n.nodeName === 'OPTION' && this.getAttrib(n, 'selected'))
|
|
4269 |
o.push({specified : 1, nodeName : 'selected'});
|
|
4270 |
|
d9344f
|
4271 |
// It's crazy that this is faster in IE but it's because it returns all attributes all the time
|
69d05c
|
4272 |
n.cloneNode(false).outerHTML.replace(/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi, '').replace(/[\w:\-]+/gi, function(a) {
|
58fb65
|
4273 |
o.push({specified : 1, nodeName : a});
|
d9344f
|
4274 |
});
|
S |
4275 |
|
|
4276 |
return o;
|
|
4277 |
}
|
|
4278 |
|
|
4279 |
return n.attributes;
|
|
4280 |
},
|
|
4281 |
|
a9251b
|
4282 |
isEmpty : function(node, elements) {
|
T |
4283 |
var self = this, i, attributes, type, walker, name;
|
|
4284 |
|
|
4285 |
node = node.firstChild;
|
|
4286 |
if (node) {
|
|
4287 |
walker = new tinymce.dom.TreeWalker(node);
|
|
4288 |
elements = elements || self.schema ? self.schema.getNonEmptyElements() : null;
|
|
4289 |
|
|
4290 |
do {
|
|
4291 |
type = node.nodeType;
|
|
4292 |
|
|
4293 |
if (type === 1) {
|
|
4294 |
// Ignore bogus elements
|
|
4295 |
if (node.getAttribute('data-mce-bogus'))
|
|
4296 |
continue;
|
|
4297 |
|
|
4298 |
// Keep empty elements like <img />
|
|
4299 |
if (elements && elements[node.nodeName.toLowerCase()])
|
|
4300 |
return false;
|
|
4301 |
|
|
4302 |
// Keep elements with data attributes or name attribute like <a name="1"></a>
|
|
4303 |
attributes = self.getAttribs(node);
|
|
4304 |
i = node.attributes.length;
|
|
4305 |
while (i--) {
|
|
4306 |
name = node.attributes[i].nodeName;
|
|
4307 |
if (name === "name" || name.indexOf('data-') === 0)
|
|
4308 |
return false;
|
|
4309 |
}
|
|
4310 |
}
|
|
4311 |
|
|
4312 |
// Keep non whitespace text nodes
|
|
4313 |
if ((type === 3 && !whiteSpaceRegExp.test(node.nodeValue)))
|
|
4314 |
return false;
|
|
4315 |
} while (node = walker.next());
|
|
4316 |
}
|
|
4317 |
|
|
4318 |
return true;
|
|
4319 |
},
|
|
4320 |
|
d9344f
|
4321 |
destroy : function(s) {
|
S |
4322 |
var t = this;
|
|
4323 |
|
58fb65
|
4324 |
if (t.events)
|
A |
4325 |
t.events.destroy();
|
|
4326 |
|
|
4327 |
t.win = t.doc = t.root = t.events = null;
|
d9344f
|
4328 |
|
S |
4329 |
// Manual destroy then remove unload handler
|
|
4330 |
if (!s)
|
|
4331 |
tinymce.removeUnload(t.destroy);
|
18240a
|
4332 |
},
|
A |
4333 |
|
29da64
|
4334 |
createRng : function() {
|
A |
4335 |
var d = this.doc;
|
|
4336 |
|
|
4337 |
return d.createRange ? d.createRange() : new tinymce.dom.Range(this);
|
|
4338 |
},
|
|
4339 |
|
69d05c
|
4340 |
nodeIndex : function(node, normalized) {
|
a9251b
|
4341 |
var idx = 0, lastNodeType, lastNode, nodeType, nodeValueExists;
|
69d05c
|
4342 |
|
A |
4343 |
if (node) {
|
|
4344 |
for (lastNodeType = node.nodeType, node = node.previousSibling, lastNode = node; node; node = node.previousSibling) {
|
|
4345 |
nodeType = node.nodeType;
|
|
4346 |
|
2011be
|
4347 |
// Normalize text nodes
|
A |
4348 |
if (normalized && nodeType == 3) {
|
a9251b
|
4349 |
// ensure that text nodes that have been removed are handled correctly in Internet Explorer.
|
T |
4350 |
// (the nodeValue attribute will not exist, and will error here).
|
|
4351 |
nodeValueExists = false;
|
|
4352 |
try {nodeValueExists = node.nodeValue.length} catch (c) {}
|
|
4353 |
if (nodeType == lastNodeType || !nodeValueExists)
|
2011be
|
4354 |
continue;
|
A |
4355 |
}
|
|
4356 |
idx++;
|
69d05c
|
4357 |
lastNodeType = nodeType;
|
A |
4358 |
}
|
|
4359 |
}
|
|
4360 |
|
|
4361 |
return idx;
|
|
4362 |
},
|
|
4363 |
|
29da64
|
4364 |
split : function(pe, e, re) {
|
A |
4365 |
var t = this, r = t.createRng(), bef, aft, pa;
|
|
4366 |
|
69d05c
|
4367 |
// W3C valid browsers tend to leave empty nodes to the left/right side of the contents, this makes sense
|
A |
4368 |
// but we don't want that in our code since it serves no purpose for the end user
|
29da64
|
4369 |
// For example if this is chopped:
|
A |
4370 |
// <p>text 1<span><b>CHOP</b></span>text 2</p>
|
|
4371 |
// would produce:
|
|
4372 |
// <p>text 1<span></span></p><b>CHOP</b><p><span></span>text 2</p>
|
|
4373 |
// this function will then trim of empty edges and produce:
|
|
4374 |
// <p>text 1</p><b>CHOP</b><p>text 2</p>
|
69d05c
|
4375 |
function trim(node) {
|
a9251b
|
4376 |
var i, children = node.childNodes, type = node.nodeType;
|
29da64
|
4377 |
|
a9251b
|
4378 |
if (type == 1 && node.getAttribute('data-mce-type') == 'bookmark')
|
69d05c
|
4379 |
return;
|
29da64
|
4380 |
|
69d05c
|
4381 |
for (i = children.length - 1; i >= 0; i--)
|
A |
4382 |
trim(children[i]);
|
29da64
|
4383 |
|
a9251b
|
4384 |
if (type != 9) {
|
69d05c
|
4385 |
// Keep non whitespace text nodes
|
a9251b
|
4386 |
if (type == 3 && node.nodeValue.length > 0) {
|
T |
4387 |
// If parent element isn't a block or there isn't any useful contents for example "<p> </p>"
|
|
4388 |
if (!t.isBlock(node.parentNode) || tinymce.trim(node.nodeValue).length > 0)
|
|
4389 |
return;
|
|
4390 |
} else if (type == 1) {
|
69d05c
|
4391 |
// If the only child is a bookmark then move it up
|
A |
4392 |
children = node.childNodes;
|
a9251b
|
4393 |
if (children.length == 1 && children[0] && children[0].nodeType == 1 && children[0].getAttribute('data-mce-type') == 'bookmark')
|
69d05c
|
4394 |
node.parentNode.insertBefore(children[0], node);
|
58fb65
|
4395 |
|
69d05c
|
4396 |
// Keep non empty elements or img, hr etc
|
A |
4397 |
if (children.length || /^(br|hr|input|img)$/i.test(node.nodeName))
|
|
4398 |
return;
|
|
4399 |
}
|
|
4400 |
|
|
4401 |
t.remove(node);
|
58fb65
|
4402 |
}
|
A |
4403 |
|
69d05c
|
4404 |
return node;
|
58fb65
|
4405 |
};
|
A |
4406 |
|
29da64
|
4407 |
if (pe && e) {
|
A |
4408 |
// Get before chunk
|
69d05c
|
4409 |
r.setStart(pe.parentNode, t.nodeIndex(pe));
|
A |
4410 |
r.setEnd(e.parentNode, t.nodeIndex(e));
|
29da64
|
4411 |
bef = r.extractContents();
|
A |
4412 |
|
|
4413 |
// Get after chunk
|
|
4414 |
r = t.createRng();
|
69d05c
|
4415 |
r.setStart(e.parentNode, t.nodeIndex(e) + 1);
|
A |
4416 |
r.setEnd(pe.parentNode, t.nodeIndex(pe) + 1);
|
29da64
|
4417 |
aft = r.extractContents();
|
A |
4418 |
|
69d05c
|
4419 |
// Insert before chunk
|
29da64
|
4420 |
pa = pe.parentNode;
|
69d05c
|
4421 |
pa.insertBefore(trim(bef), pe);
|
29da64
|
4422 |
|
69d05c
|
4423 |
// Insert middle chunk
|
29da64
|
4424 |
if (re)
|
A |
4425 |
pa.replaceChild(re, e);
|
|
4426 |
else
|
|
4427 |
pa.insertBefore(e, pe);
|
|
4428 |
|
69d05c
|
4429 |
// Insert after chunk
|
A |
4430 |
pa.insertBefore(trim(aft), pe);
|
29da64
|
4431 |
t.remove(pe);
|
A |
4432 |
|
|
4433 |
return re || e;
|
|
4434 |
}
|
|
4435 |
},
|
|
4436 |
|
58fb65
|
4437 |
bind : function(target, name, func, scope) {
|
A |
4438 |
var t = this;
|
|
4439 |
|
|
4440 |
if (!t.events)
|
|
4441 |
t.events = new tinymce.dom.EventUtils();
|
|
4442 |
|
|
4443 |
return t.events.add(target, name, func, scope || this);
|
|
4444 |
},
|
|
4445 |
|
|
4446 |
unbind : function(target, name, func) {
|
|
4447 |
var t = this;
|
|
4448 |
|
|
4449 |
if (!t.events)
|
|
4450 |
t.events = new tinymce.dom.EventUtils();
|
|
4451 |
|
|
4452 |
return t.events.remove(target, name, func);
|
|
4453 |
},
|
|
4454 |
|
|
4455 |
|
|
4456 |
_findSib : function(node, selector, name) {
|
|
4457 |
var t = this, f = selector;
|
|
4458 |
|
|
4459 |
if (node) {
|
|
4460 |
// If expression make a function of it using is
|
|
4461 |
if (is(f, 'string')) {
|
|
4462 |
f = function(node) {
|
|
4463 |
return t.is(node, selector);
|
|
4464 |
};
|
|
4465 |
}
|
|
4466 |
|
|
4467 |
// Loop all siblings
|
|
4468 |
for (node = node[name]; node; node = node[name]) {
|
|
4469 |
if (f(node))
|
|
4470 |
return node;
|
|
4471 |
}
|
|
4472 |
}
|
|
4473 |
|
|
4474 |
return null;
|
|
4475 |
},
|
29da64
|
4476 |
|
18240a
|
4477 |
_isRes : function(c) {
|
A |
4478 |
// Is live resizble element
|
|
4479 |
return /^(top|left|bottom|right|width|height)/i.test(c) || /;\s*(top|left|bottom|right|width|height)/i.test(c);
|
d9344f
|
4480 |
}
|
S |
4481 |
|
|
4482 |
/*
|
|
4483 |
walk : function(n, f, s) {
|
|
4484 |
var d = this.doc, w;
|
|
4485 |
|
|
4486 |
if (d.createTreeWalker) {
|
|
4487 |
w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
|
|
4488 |
|
|
4489 |
while ((n = w.nextNode()) != null)
|
|
4490 |
f.call(s || this, n);
|
|
4491 |
} else
|
|
4492 |
tinymce.walk(n, f, 'childNodes', s);
|
|
4493 |
}
|
|
4494 |
*/
|
|
4495 |
|
|
4496 |
/*
|
|
4497 |
toRGB : function(s) {
|
|
4498 |
var c = /^\s*?#([0-9A-F]{2})([0-9A-F]{1,2})([0-9A-F]{2})?\s*?$/.exec(s);
|
|
4499 |
|
|
4500 |
if (c) {
|
|
4501 |
// #FFF -> #FFFFFF
|
|
4502 |
if (!is(c[3]))
|
|
4503 |
c[3] = c[2] = c[1];
|
|
4504 |
|
|
4505 |
return "rgb(" + parseInt(c[1], 16) + "," + parseInt(c[2], 16) + "," + parseInt(c[3], 16) + ")";
|
|
4506 |
}
|
|
4507 |
|
|
4508 |
return s;
|
|
4509 |
}
|
|
4510 |
*/
|
58fb65
|
4511 |
});
|
d9344f
|
4512 |
|
S |
4513 |
tinymce.DOM = new tinymce.dom.DOMUtils(document, {process_html : 0});
|
29da64
|
4514 |
})(tinymce);
|
69d05c
|
4515 |
|
29da64
|
4516 |
(function(ns) {
|
A |
4517 |
// Range constructor
|
|
4518 |
function Range(dom) {
|
69d05c
|
4519 |
var t = this,
|
A |
4520 |
doc = dom.doc,
|
|
4521 |
EXTRACT = 0,
|
|
4522 |
CLONE = 1,
|
|
4523 |
DELETE = 2,
|
|
4524 |
TRUE = true,
|
|
4525 |
FALSE = false,
|
|
4526 |
START_OFFSET = 'startOffset',
|
|
4527 |
START_CONTAINER = 'startContainer',
|
|
4528 |
END_CONTAINER = 'endContainer',
|
|
4529 |
END_OFFSET = 'endOffset',
|
|
4530 |
extend = tinymce.extend,
|
|
4531 |
nodeIndex = dom.nodeIndex;
|
29da64
|
4532 |
|
69d05c
|
4533 |
extend(t, {
|
29da64
|
4534 |
// Inital states
|
69d05c
|
4535 |
startContainer : doc,
|
29da64
|
4536 |
startOffset : 0,
|
69d05c
|
4537 |
endContainer : doc,
|
29da64
|
4538 |
endOffset : 0,
|
69d05c
|
4539 |
collapsed : TRUE,
|
A |
4540 |
commonAncestorContainer : doc,
|
29da64
|
4541 |
|
A |
4542 |
// Range constants
|
|
4543 |
START_TO_START : 0,
|
|
4544 |
START_TO_END : 1,
|
|
4545 |
END_TO_END : 2,
|
69d05c
|
4546 |
END_TO_START : 3,
|
A |
4547 |
|
|
4548 |
// Public methods
|
|
4549 |
setStart : setStart,
|
|
4550 |
setEnd : setEnd,
|
|
4551 |
setStartBefore : setStartBefore,
|
|
4552 |
setStartAfter : setStartAfter,
|
|
4553 |
setEndBefore : setEndBefore,
|
|
4554 |
setEndAfter : setEndAfter,
|
|
4555 |
collapse : collapse,
|
|
4556 |
selectNode : selectNode,
|
|
4557 |
selectNodeContents : selectNodeContents,
|
|
4558 |
compareBoundaryPoints : compareBoundaryPoints,
|
|
4559 |
deleteContents : deleteContents,
|
|
4560 |
extractContents : extractContents,
|
|
4561 |
cloneContents : cloneContents,
|
|
4562 |
insertNode : insertNode,
|
|
4563 |
surroundContents : surroundContents,
|
|
4564 |
cloneRange : cloneRange
|
29da64
|
4565 |
});
|
A |
4566 |
|
69d05c
|
4567 |
function setStart(n, o) {
|
A |
4568 |
_setEndPoint(TRUE, n, o);
|
|
4569 |
};
|
29da64
|
4570 |
|
69d05c
|
4571 |
function setEnd(n, o) {
|
A |
4572 |
_setEndPoint(FALSE, n, o);
|
|
4573 |
};
|
29da64
|
4574 |
|
69d05c
|
4575 |
function setStartBefore(n) {
|
A |
4576 |
setStart(n.parentNode, nodeIndex(n));
|
|
4577 |
};
|
29da64
|
4578 |
|
69d05c
|
4579 |
function setStartAfter(n) {
|
A |
4580 |
setStart(n.parentNode, nodeIndex(n) + 1);
|
|
4581 |
};
|
29da64
|
4582 |
|
69d05c
|
4583 |
function setEndBefore(n) {
|
A |
4584 |
setEnd(n.parentNode, nodeIndex(n));
|
|
4585 |
};
|
29da64
|
4586 |
|
69d05c
|
4587 |
function setEndAfter(n) {
|
A |
4588 |
setEnd(n.parentNode, nodeIndex(n) + 1);
|
|
4589 |
};
|
29da64
|
4590 |
|
69d05c
|
4591 |
function collapse(ts) {
|
29da64
|
4592 |
if (ts) {
|
69d05c
|
4593 |
t[END_CONTAINER] = t[START_CONTAINER];
|
A |
4594 |
t[END_OFFSET] = t[START_OFFSET];
|
29da64
|
4595 |
} else {
|
69d05c
|
4596 |
t[START_CONTAINER] = t[END_CONTAINER];
|
A |
4597 |
t[START_OFFSET] = t[END_OFFSET];
|
29da64
|
4598 |
}
|
A |
4599 |
|
69d05c
|
4600 |
t.collapsed = TRUE;
|
A |
4601 |
};
|
29da64
|
4602 |
|
69d05c
|
4603 |
function selectNode(n) {
|
A |
4604 |
setStartBefore(n);
|
|
4605 |
setEndAfter(n);
|
|
4606 |
};
|
29da64
|
4607 |
|
69d05c
|
4608 |
function selectNodeContents(n) {
|
A |
4609 |
setStart(n, 0);
|
|
4610 |
setEnd(n, n.nodeType === 1 ? n.childNodes.length : n.nodeValue.length);
|
|
4611 |
};
|
29da64
|
4612 |
|
69d05c
|
4613 |
function compareBoundaryPoints(h, r) {
|
a9251b
|
4614 |
var sc = t[START_CONTAINER], so = t[START_OFFSET], ec = t[END_CONTAINER], eo = t[END_OFFSET],
|
T |
4615 |
rsc = r.startContainer, rso = r.startOffset, rec = r.endContainer, reo = r.endOffset;
|
29da64
|
4616 |
|
A |
4617 |
// Check START_TO_START
|
|
4618 |
if (h === 0)
|
a9251b
|
4619 |
return _compareBoundaryPoints(sc, so, rsc, rso);
|
T |
4620 |
|
29da64
|
4621 |
// Check START_TO_END
|
A |
4622 |
if (h === 1)
|
a9251b
|
4623 |
return _compareBoundaryPoints(ec, eo, rsc, rso);
|
T |
4624 |
|
29da64
|
4625 |
// Check END_TO_END
|
A |
4626 |
if (h === 2)
|
a9251b
|
4627 |
return _compareBoundaryPoints(ec, eo, rec, reo);
|
T |
4628 |
|
29da64
|
4629 |
// Check END_TO_START
|
a9251b
|
4630 |
if (h === 3)
|
T |
4631 |
return _compareBoundaryPoints(sc, so, rec, reo);
|
69d05c
|
4632 |
};
|
29da64
|
4633 |
|
69d05c
|
4634 |
function deleteContents() {
|
A |
4635 |
_traverse(DELETE);
|
|
4636 |
};
|
29da64
|
4637 |
|
69d05c
|
4638 |
function extractContents() {
|
A |
4639 |
return _traverse(EXTRACT);
|
|
4640 |
};
|
29da64
|
4641 |
|
69d05c
|
4642 |
function cloneContents() {
|
A |
4643 |
return _traverse(CLONE);
|
|
4644 |
};
|
29da64
|
4645 |
|
69d05c
|
4646 |
function insertNode(n) {
|
A |
4647 |
var startContainer = this[START_CONTAINER],
|
|
4648 |
startOffset = this[START_OFFSET], nn, o;
|
29da64
|
4649 |
|
A |
4650 |
// Node is TEXT_NODE or CDATA
|
69d05c
|
4651 |
if ((startContainer.nodeType === 3 || startContainer.nodeType === 4) && startContainer.nodeValue) {
|
A |
4652 |
if (!startOffset) {
|
|
4653 |
// At the start of text
|
|
4654 |
startContainer.parentNode.insertBefore(n, startContainer);
|
|
4655 |
} else if (startOffset >= startContainer.nodeValue.length) {
|
|
4656 |
// At the end of text
|
|
4657 |
dom.insertAfter(n, startContainer);
|
|
4658 |
} else {
|
|
4659 |
// Middle, need to split
|
|
4660 |
nn = startContainer.splitText(startOffset);
|
|
4661 |
startContainer.parentNode.insertBefore(n, nn);
|
|
4662 |
}
|
29da64
|
4663 |
} else {
|
A |
4664 |
// Insert element node
|
69d05c
|
4665 |
if (startContainer.childNodes.length > 0)
|
A |
4666 |
o = startContainer.childNodes[startOffset];
|
29da64
|
4667 |
|
69d05c
|
4668 |
if (o)
|
A |
4669 |
startContainer.insertBefore(n, o);
|
|
4670 |
else
|
|
4671 |
startContainer.appendChild(n);
|
29da64
|
4672 |
}
|
69d05c
|
4673 |
};
|
29da64
|
4674 |
|
69d05c
|
4675 |
function surroundContents(n) {
|
A |
4676 |
var f = t.extractContents();
|
29da64
|
4677 |
|
A |
4678 |
t.insertNode(n);
|
|
4679 |
n.appendChild(f);
|
|
4680 |
t.selectNode(n);
|
69d05c
|
4681 |
};
|
29da64
|
4682 |
|
69d05c
|
4683 |
function cloneRange() {
|
A |
4684 |
return extend(new Range(dom), {
|
|
4685 |
startContainer : t[START_CONTAINER],
|
|
4686 |
startOffset : t[START_OFFSET],
|
|
4687 |
endContainer : t[END_CONTAINER],
|
|
4688 |
endOffset : t[END_OFFSET],
|
29da64
|
4689 |
collapsed : t.collapsed,
|
A |
4690 |
commonAncestorContainer : t.commonAncestorContainer
|
|
4691 |
});
|
69d05c
|
4692 |
};
|
29da64
|
4693 |
|
69d05c
|
4694 |
// Private methods
|
29da64
|
4695 |
|
69d05c
|
4696 |
function _getSelectedNode(container, offset) {
|
A |
4697 |
var child;
|
29da64
|
4698 |
|
69d05c
|
4699 |
if (container.nodeType == 3 /* TEXT_NODE */)
|
A |
4700 |
return container;
|
|
4701 |
|
|
4702 |
if (offset < 0)
|
|
4703 |
return container;
|
|
4704 |
|
|
4705 |
child = container.firstChild;
|
|
4706 |
while (child && offset > 0) {
|
|
4707 |
--offset;
|
|
4708 |
child = child.nextSibling;
|
|
4709 |
}
|
|
4710 |
|
|
4711 |
if (child)
|
|
4712 |
return child;
|
|
4713 |
|
|
4714 |
return container;
|
|
4715 |
};
|
|
4716 |
|
|
4717 |
function _isCollapsed() {
|
|
4718 |
return (t[START_CONTAINER] == t[END_CONTAINER] && t[START_OFFSET] == t[END_OFFSET]);
|
|
4719 |
};
|
|
4720 |
|
|
4721 |
function _compareBoundaryPoints(containerA, offsetA, containerB, offsetB) {
|
29da64
|
4722 |
var c, offsetC, n, cmnRoot, childA, childB;
|
a9251b
|
4723 |
|
69d05c
|
4724 |
// In the first case the boundary-points have the same container. A is before B
|
A |
4725 |
// if its offset is less than the offset of B, A is equal to B if its offset is
|
|
4726 |
// equal to the offset of B, and A is after B if its offset is greater than the
|
29da64
|
4727 |
// offset of B.
|
A |
4728 |
if (containerA == containerB) {
|
69d05c
|
4729 |
if (offsetA == offsetB)
|
29da64
|
4730 |
return 0; // equal
|
69d05c
|
4731 |
|
A |
4732 |
if (offsetA < offsetB)
|
29da64
|
4733 |
return -1; // before
|
69d05c
|
4734 |
|
A |
4735 |
return 1; // after
|
29da64
|
4736 |
}
|
A |
4737 |
|
69d05c
|
4738 |
// In the second case a child node C of the container of A is an ancestor
|
A |
4739 |
// container of B. In this case, A is before B if the offset of A is less than or
|
29da64
|
4740 |
// equal to the index of the child node C and A is after B otherwise.
|
A |
4741 |
c = containerB;
|
69d05c
|
4742 |
while (c && c.parentNode != containerA)
|
29da64
|
4743 |
c = c.parentNode;
|
69d05c
|
4744 |
|
29da64
|
4745 |
if (c) {
|
A |
4746 |
offsetC = 0;
|
|
4747 |
n = containerA.firstChild;
|
|
4748 |
|
|
4749 |
while (n != c && offsetC < offsetA) {
|
|
4750 |
offsetC++;
|
|
4751 |
n = n.nextSibling;
|
|
4752 |
}
|
|
4753 |
|
69d05c
|
4754 |
if (offsetA <= offsetC)
|
29da64
|
4755 |
return -1; // before
|
69d05c
|
4756 |
|
A |
4757 |
return 1; // after
|
29da64
|
4758 |
}
|
A |
4759 |
|
69d05c
|
4760 |
// In the third case a child node C of the container of B is an ancestor container
|
A |
4761 |
// of A. In this case, A is before B if the index of the child node C is less than
|
29da64
|
4762 |
// the offset of B and A is after B otherwise.
|
A |
4763 |
c = containerA;
|
|
4764 |
while (c && c.parentNode != containerB) {
|
|
4765 |
c = c.parentNode;
|
|
4766 |
}
|
|
4767 |
|
|
4768 |
if (c) {
|
|
4769 |
offsetC = 0;
|
|
4770 |
n = containerB.firstChild;
|
|
4771 |
|
|
4772 |
while (n != c && offsetC < offsetB) {
|
|
4773 |
offsetC++;
|
|
4774 |
n = n.nextSibling;
|
|
4775 |
}
|
|
4776 |
|
69d05c
|
4777 |
if (offsetC < offsetB)
|
29da64
|
4778 |
return -1; // before
|
69d05c
|
4779 |
|
A |
4780 |
return 1; // after
|
29da64
|
4781 |
}
|
A |
4782 |
|
69d05c
|
4783 |
// In the fourth case, none of three other cases hold: the containers of A and B
|
A |
4784 |
// are siblings or descendants of sibling nodes. In this case, A is before B if
|
29da64
|
4785 |
// the container of A is before the container of B in a pre-order traversal of the
|
A |
4786 |
// Ranges' context tree and A is after B otherwise.
|
69d05c
|
4787 |
cmnRoot = dom.findCommonAncestor(containerA, containerB);
|
29da64
|
4788 |
childA = containerA;
|
A |
4789 |
|
69d05c
|
4790 |
while (childA && childA.parentNode != cmnRoot)
|
A |
4791 |
childA = childA.parentNode;
|
29da64
|
4792 |
|
69d05c
|
4793 |
if (!childA)
|
29da64
|
4794 |
childA = cmnRoot;
|
A |
4795 |
|
|
4796 |
childB = containerB;
|
69d05c
|
4797 |
while (childB && childB.parentNode != cmnRoot)
|
29da64
|
4798 |
childB = childB.parentNode;
|
A |
4799 |
|
69d05c
|
4800 |
if (!childB)
|
29da64
|
4801 |
childB = cmnRoot;
|
A |
4802 |
|
69d05c
|
4803 |
if (childA == childB)
|
29da64
|
4804 |
return 0; // equal
|
A |
4805 |
|
|
4806 |
n = cmnRoot.firstChild;
|
|
4807 |
while (n) {
|
69d05c
|
4808 |
if (n == childA)
|
29da64
|
4809 |
return -1; // before
|
A |
4810 |
|
69d05c
|
4811 |
if (n == childB)
|
29da64
|
4812 |
return 1; // after
|
A |
4813 |
|
|
4814 |
n = n.nextSibling;
|
|
4815 |
}
|
69d05c
|
4816 |
};
|
29da64
|
4817 |
|
69d05c
|
4818 |
function _setEndPoint(st, n, o) {
|
A |
4819 |
var ec, sc;
|
29da64
|
4820 |
|
A |
4821 |
if (st) {
|
69d05c
|
4822 |
t[START_CONTAINER] = n;
|
A |
4823 |
t[START_OFFSET] = o;
|
29da64
|
4824 |
} else {
|
69d05c
|
4825 |
t[END_CONTAINER] = n;
|
A |
4826 |
t[END_OFFSET] = o;
|
29da64
|
4827 |
}
|
A |
4828 |
|
69d05c
|
4829 |
// If one boundary-point of a Range is set to have a root container
|
A |
4830 |
// other than the current one for the Range, the Range is collapsed to
|
29da64
|
4831 |
// the new position. This enforces the restriction that both boundary-
|
A |
4832 |
// points of a Range must have the same root container.
|
69d05c
|
4833 |
ec = t[END_CONTAINER];
|
29da64
|
4834 |
while (ec.parentNode)
|
A |
4835 |
ec = ec.parentNode;
|
|
4836 |
|
69d05c
|
4837 |
sc = t[START_CONTAINER];
|
29da64
|
4838 |
while (sc.parentNode)
|
A |
4839 |
sc = sc.parentNode;
|
|
4840 |
|
69d05c
|
4841 |
if (sc == ec) {
|
A |
4842 |
// The start position of a Range is guaranteed to never be after the
|
|
4843 |
// end position. To enforce this restriction, if the start is set to
|
|
4844 |
// be at a position after the end, the Range is collapsed to that
|
29da64
|
4845 |
// position.
|
69d05c
|
4846 |
if (_compareBoundaryPoints(t[START_CONTAINER], t[START_OFFSET], t[END_CONTAINER], t[END_OFFSET]) > 0)
|
29da64
|
4847 |
t.collapse(st);
|
69d05c
|
4848 |
} else
|
A |
4849 |
t.collapse(st);
|
29da64
|
4850 |
|
69d05c
|
4851 |
t.collapsed = _isCollapsed();
|
A |
4852 |
t.commonAncestorContainer = dom.findCommonAncestor(t[START_CONTAINER], t[END_CONTAINER]);
|
|
4853 |
};
|
29da64
|
4854 |
|
69d05c
|
4855 |
function _traverse(how) {
|
A |
4856 |
var c, endContainerDepth = 0, startContainerDepth = 0, p, depthDiff, startNode, endNode, sp, ep;
|
29da64
|
4857 |
|
69d05c
|
4858 |
if (t[START_CONTAINER] == t[END_CONTAINER])
|
A |
4859 |
return _traverseSameContainer(how);
|
29da64
|
4860 |
|
69d05c
|
4861 |
for (c = t[END_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) {
|
A |
4862 |
if (p == t[START_CONTAINER])
|
|
4863 |
return _traverseCommonStartContainer(c, how);
|
29da64
|
4864 |
|
A |
4865 |
++endContainerDepth;
|
|
4866 |
}
|
|
4867 |
|
69d05c
|
4868 |
for (c = t[START_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) {
|
A |
4869 |
if (p == t[END_CONTAINER])
|
|
4870 |
return _traverseCommonEndContainer(c, how);
|
29da64
|
4871 |
|
A |
4872 |
++startContainerDepth;
|
|
4873 |
}
|
|
4874 |
|
|
4875 |
depthDiff = startContainerDepth - endContainerDepth;
|
|
4876 |
|
69d05c
|
4877 |
startNode = t[START_CONTAINER];
|
29da64
|
4878 |
while (depthDiff > 0) {
|
A |
4879 |
startNode = startNode.parentNode;
|
|
4880 |
depthDiff--;
|
|
4881 |
}
|
|
4882 |
|
69d05c
|
4883 |
endNode = t[END_CONTAINER];
|
29da64
|
4884 |
while (depthDiff < 0) {
|
A |
4885 |
endNode = endNode.parentNode;
|
|
4886 |
depthDiff++;
|
|
4887 |
}
|
|
4888 |
|
|
4889 |
// ascend the ancestor hierarchy until we have a common parent.
|
|
4890 |
for (sp = startNode.parentNode, ep = endNode.parentNode; sp != ep; sp = sp.parentNode, ep = ep.parentNode) {
|
|
4891 |
startNode = sp;
|
|
4892 |
endNode = ep;
|
|
4893 |
}
|
|
4894 |
|
69d05c
|
4895 |
return _traverseCommonAncestors(startNode, endNode, how);
|
A |
4896 |
};
|
29da64
|
4897 |
|
69d05c
|
4898 |
function _traverseSameContainer(how) {
|
A |
4899 |
var frag, s, sub, n, cnt, sibling, xferNode;
|
29da64
|
4900 |
|
A |
4901 |
if (how != DELETE)
|
69d05c
|
4902 |
frag = doc.createDocumentFragment();
|
29da64
|
4903 |
|
A |
4904 |
// If selection is empty, just return the fragment
|
69d05c
|
4905 |
if (t[START_OFFSET] == t[END_OFFSET])
|
29da64
|
4906 |
return frag;
|
A |
4907 |
|
|
4908 |
// Text node needs special case handling
|
69d05c
|
4909 |
if (t[START_CONTAINER].nodeType == 3 /* TEXT_NODE */) {
|
29da64
|
4910 |
// get the substring
|
69d05c
|
4911 |
s = t[START_CONTAINER].nodeValue;
|
A |
4912 |
sub = s.substring(t[START_OFFSET], t[END_OFFSET]);
|
29da64
|
4913 |
|
A |
4914 |
// set the original text node to its new value
|
|
4915 |
if (how != CLONE) {
|
69d05c
|
4916 |
t[START_CONTAINER].deleteData(t[START_OFFSET], t[END_OFFSET] - t[START_OFFSET]);
|
29da64
|
4917 |
|
A |
4918 |
// Nothing is partially selected, so collapse to start point
|
69d05c
|
4919 |
t.collapse(TRUE);
|
29da64
|
4920 |
}
|
A |
4921 |
|
|
4922 |
if (how == DELETE)
|
69d05c
|
4923 |
return;
|
29da64
|
4924 |
|
69d05c
|
4925 |
frag.appendChild(doc.createTextNode(sub));
|
29da64
|
4926 |
return frag;
|
A |
4927 |
}
|
|
4928 |
|
|
4929 |
// Copy nodes between the start/end offsets.
|
69d05c
|
4930 |
n = _getSelectedNode(t[START_CONTAINER], t[START_OFFSET]);
|
A |
4931 |
cnt = t[END_OFFSET] - t[START_OFFSET];
|
29da64
|
4932 |
|
A |
4933 |
while (cnt > 0) {
|
|
4934 |
sibling = n.nextSibling;
|
69d05c
|
4935 |
xferNode = _traverseFullySelected(n, how);
|
29da64
|
4936 |
|
A |
4937 |
if (frag)
|
|
4938 |
frag.appendChild( xferNode );
|
|
4939 |
|
|
4940 |
--cnt;
|
|
4941 |
n = sibling;
|
|
4942 |
}
|
|
4943 |
|
|
4944 |
// Nothing is partially selected, so collapse to start point
|
|
4945 |
if (how != CLONE)
|
69d05c
|
4946 |
t.collapse(TRUE);
|
29da64
|
4947 |
|
A |
4948 |
return frag;
|
69d05c
|
4949 |
};
|
29da64
|
4950 |
|
69d05c
|
4951 |
function _traverseCommonStartContainer(endAncestor, how) {
|
A |
4952 |
var frag, n, endIdx, cnt, sibling, xferNode;
|
29da64
|
4953 |
|
A |
4954 |
if (how != DELETE)
|
69d05c
|
4955 |
frag = doc.createDocumentFragment();
|
29da64
|
4956 |
|
69d05c
|
4957 |
n = _traverseRightBoundary(endAncestor, how);
|
29da64
|
4958 |
|
A |
4959 |
if (frag)
|
|
4960 |
frag.appendChild(n);
|
|
4961 |
|
69d05c
|
4962 |
endIdx = nodeIndex(endAncestor);
|
A |
4963 |
cnt = endIdx - t[START_OFFSET];
|
29da64
|
4964 |
|
A |
4965 |
if (cnt <= 0) {
|
69d05c
|
4966 |
// Collapse to just before the endAncestor, which
|
29da64
|
4967 |
// is partially selected.
|
A |
4968 |
if (how != CLONE) {
|
|
4969 |
t.setEndBefore(endAncestor);
|
69d05c
|
4970 |
t.collapse(FALSE);
|
29da64
|
4971 |
}
|
A |
4972 |
|
|
4973 |
return frag;
|
|
4974 |
}
|
|
4975 |
|
|
4976 |
n = endAncestor.previousSibling;
|
|
4977 |
while (cnt > 0) {
|
|
4978 |
sibling = n.previousSibling;
|
69d05c
|
4979 |
xferNode = _traverseFullySelected(n, how);
|
29da64
|
4980 |
|
A |
4981 |
if (frag)
|
|
4982 |
frag.insertBefore(xferNode, frag.firstChild);
|
|
4983 |
|
|
4984 |
--cnt;
|
|
4985 |
n = sibling;
|
|
4986 |
}
|
|
4987 |
|
69d05c
|
4988 |
// Collapse to just before the endAncestor, which
|
29da64
|
4989 |
// is partially selected.
|
A |
4990 |
if (how != CLONE) {
|
|
4991 |
t.setEndBefore(endAncestor);
|
69d05c
|
4992 |
t.collapse(FALSE);
|
29da64
|
4993 |
}
|
A |
4994 |
|
|
4995 |
return frag;
|
69d05c
|
4996 |
};
|
29da64
|
4997 |
|
69d05c
|
4998 |
function _traverseCommonEndContainer(startAncestor, how) {
|
A |
4999 |
var frag, startIdx, n, cnt, sibling, xferNode;
|
29da64
|
5000 |
|
A |
5001 |
if (how != DELETE)
|
69d05c
|
5002 |
frag = doc.createDocumentFragment();
|
29da64
|
5003 |
|
69d05c
|
5004 |
n = _traverseLeftBoundary(startAncestor, how);
|
29da64
|
5005 |
if (frag)
|
A |
5006 |
frag.appendChild(n);
|
|
5007 |
|
69d05c
|
5008 |
startIdx = nodeIndex(startAncestor);
|
a9251b
|
5009 |
++startIdx; // Because we already traversed it
|
29da64
|
5010 |
|
69d05c
|
5011 |
cnt = t[END_OFFSET] - startIdx;
|
29da64
|
5012 |
n = startAncestor.nextSibling;
|
A |
5013 |
while (cnt > 0) {
|
|
5014 |
sibling = n.nextSibling;
|
69d05c
|
5015 |
xferNode = _traverseFullySelected(n, how);
|
29da64
|
5016 |
|
A |
5017 |
if (frag)
|
|
5018 |
frag.appendChild(xferNode);
|
|
5019 |
|
|
5020 |
--cnt;
|
|
5021 |
n = sibling;
|
|
5022 |
}
|
|
5023 |
|
|
5024 |
if (how != CLONE) {
|
|
5025 |
t.setStartAfter(startAncestor);
|
69d05c
|
5026 |
t.collapse(TRUE);
|
29da64
|
5027 |
}
|
A |
5028 |
|
|
5029 |
return frag;
|
69d05c
|
5030 |
};
|
29da64
|
5031 |
|
69d05c
|
5032 |
function _traverseCommonAncestors(startAncestor, endAncestor, how) {
|
A |
5033 |
var n, frag, commonParent, startOffset, endOffset, cnt, sibling, nextSibling;
|
29da64
|
5034 |
|
A |
5035 |
if (how != DELETE)
|
69d05c
|
5036 |
frag = doc.createDocumentFragment();
|
29da64
|
5037 |
|
69d05c
|
5038 |
n = _traverseLeftBoundary(startAncestor, how);
|
29da64
|
5039 |
if (frag)
|
A |
5040 |
frag.appendChild(n);
|
|
5041 |
|
|
5042 |
commonParent = startAncestor.parentNode;
|
69d05c
|
5043 |
startOffset = nodeIndex(startAncestor);
|
A |
5044 |
endOffset = nodeIndex(endAncestor);
|
29da64
|
5045 |
++startOffset;
|
A |
5046 |
|
|
5047 |
cnt = endOffset - startOffset;
|
|
5048 |
sibling = startAncestor.nextSibling;
|
|
5049 |
|
|
5050 |
while (cnt > 0) {
|
|
5051 |
nextSibling = sibling.nextSibling;
|
69d05c
|
5052 |
n = _traverseFullySelected(sibling, how);
|
29da64
|
5053 |
|
A |
5054 |
if (frag)
|
|
5055 |
frag.appendChild(n);
|
|
5056 |
|
|
5057 |
sibling = nextSibling;
|
|
5058 |
--cnt;
|
|
5059 |
}
|
|
5060 |
|
69d05c
|
5061 |
n = _traverseRightBoundary(endAncestor, how);
|
29da64
|
5062 |
|
A |
5063 |
if (frag)
|
|
5064 |
frag.appendChild(n);
|
|
5065 |
|
|
5066 |
if (how != CLONE) {
|
|
5067 |
t.setStartAfter(startAncestor);
|
69d05c
|
5068 |
t.collapse(TRUE);
|
29da64
|
5069 |
}
|
A |
5070 |
|
|
5071 |
return frag;
|
69d05c
|
5072 |
};
|
29da64
|
5073 |
|
69d05c
|
5074 |
function _traverseRightBoundary(root, how) {
|
A |
5075 |
var next = _getSelectedNode(t[END_CONTAINER], t[END_OFFSET] - 1), parent, clonedParent, prevSibling, clonedChild, clonedGrandParent, isFullySelected = next != t[END_CONTAINER];
|
29da64
|
5076 |
|
A |
5077 |
if (next == root)
|
69d05c
|
5078 |
return _traverseNode(next, isFullySelected, FALSE, how);
|
29da64
|
5079 |
|
A |
5080 |
parent = next.parentNode;
|
69d05c
|
5081 |
clonedParent = _traverseNode(parent, FALSE, FALSE, how);
|
29da64
|
5082 |
|
69d05c
|
5083 |
while (parent) {
|
A |
5084 |
while (next) {
|
29da64
|
5085 |
prevSibling = next.previousSibling;
|
69d05c
|
5086 |
clonedChild = _traverseNode(next, isFullySelected, FALSE, how);
|
29da64
|
5087 |
|
A |
5088 |
if (how != DELETE)
|
|
5089 |
clonedParent.insertBefore(clonedChild, clonedParent.firstChild);
|
|
5090 |
|
69d05c
|
5091 |
isFullySelected = TRUE;
|
29da64
|
5092 |
next = prevSibling;
|
A |
5093 |
}
|
|
5094 |
|
|
5095 |
if (parent == root)
|
|
5096 |
return clonedParent;
|
|
5097 |
|
|
5098 |
next = parent.previousSibling;
|
|
5099 |
parent = parent.parentNode;
|
|
5100 |
|
69d05c
|
5101 |
clonedGrandParent = _traverseNode(parent, FALSE, FALSE, how);
|
29da64
|
5102 |
|
A |
5103 |
if (how != DELETE)
|
|
5104 |
clonedGrandParent.appendChild(clonedParent);
|
|
5105 |
|
|
5106 |
clonedParent = clonedGrandParent;
|
|
5107 |
}
|
69d05c
|
5108 |
};
|
29da64
|
5109 |
|
69d05c
|
5110 |
function _traverseLeftBoundary(root, how) {
|
A |
5111 |
var next = _getSelectedNode(t[START_CONTAINER], t[START_OFFSET]), isFullySelected = next != t[START_CONTAINER], parent, clonedParent, nextSibling, clonedChild, clonedGrandParent;
|
29da64
|
5112 |
|
A |
5113 |
if (next == root)
|
69d05c
|
5114 |
return _traverseNode(next, isFullySelected, TRUE, how);
|
29da64
|
5115 |
|
A |
5116 |
parent = next.parentNode;
|
69d05c
|
5117 |
clonedParent = _traverseNode(parent, FALSE, TRUE, how);
|
29da64
|
5118 |
|
69d05c
|
5119 |
while (parent) {
|
A |
5120 |
while (next) {
|
29da64
|
5121 |
nextSibling = next.nextSibling;
|
69d05c
|
5122 |
clonedChild = _traverseNode(next, isFullySelected, TRUE, how);
|
29da64
|
5123 |
|
A |
5124 |
if (how != DELETE)
|
|
5125 |
clonedParent.appendChild(clonedChild);
|
|
5126 |
|
69d05c
|
5127 |
isFullySelected = TRUE;
|
29da64
|
5128 |
next = nextSibling;
|
A |
5129 |
}
|
|
5130 |
|
|
5131 |
if (parent == root)
|
|
5132 |
return clonedParent;
|
|
5133 |
|
|
5134 |
next = parent.nextSibling;
|
|
5135 |
parent = parent.parentNode;
|
|
5136 |
|
69d05c
|
5137 |
clonedGrandParent = _traverseNode(parent, FALSE, TRUE, how);
|
29da64
|
5138 |
|
A |
5139 |
if (how != DELETE)
|
|
5140 |
clonedGrandParent.appendChild(clonedParent);
|
|
5141 |
|
|
5142 |
clonedParent = clonedGrandParent;
|
|
5143 |
}
|
69d05c
|
5144 |
};
|
29da64
|
5145 |
|
69d05c
|
5146 |
function _traverseNode(n, isFullySelected, isLeft, how) {
|
A |
5147 |
var txtValue, newNodeValue, oldNodeValue, offset, newNode;
|
29da64
|
5148 |
|
A |
5149 |
if (isFullySelected)
|
69d05c
|
5150 |
return _traverseFullySelected(n, how);
|
29da64
|
5151 |
|
A |
5152 |
if (n.nodeType == 3 /* TEXT_NODE */) {
|
|
5153 |
txtValue = n.nodeValue;
|
|
5154 |
|
|
5155 |
if (isLeft) {
|
69d05c
|
5156 |
offset = t[START_OFFSET];
|
29da64
|
5157 |
newNodeValue = txtValue.substring(offset);
|
A |
5158 |
oldNodeValue = txtValue.substring(0, offset);
|
|
5159 |
} else {
|
69d05c
|
5160 |
offset = t[END_OFFSET];
|
29da64
|
5161 |
newNodeValue = txtValue.substring(0, offset);
|
A |
5162 |
oldNodeValue = txtValue.substring(offset);
|
|
5163 |
}
|
|
5164 |
|
|
5165 |
if (how != CLONE)
|
|
5166 |
n.nodeValue = oldNodeValue;
|
|
5167 |
|
|
5168 |
if (how == DELETE)
|
69d05c
|
5169 |
return;
|
29da64
|
5170 |
|
69d05c
|
5171 |
newNode = n.cloneNode(FALSE);
|
29da64
|
5172 |
newNode.nodeValue = newNodeValue;
|
A |
5173 |
|
|
5174 |
return newNode;
|
|
5175 |
}
|
|
5176 |
|
|
5177 |
if (how == DELETE)
|
69d05c
|
5178 |
return;
|
29da64
|
5179 |
|
69d05c
|
5180 |
return n.cloneNode(FALSE);
|
A |
5181 |
};
|
29da64
|
5182 |
|
69d05c
|
5183 |
function _traverseFullySelected(n, how) {
|
29da64
|
5184 |
if (how != DELETE)
|
69d05c
|
5185 |
return how == CLONE ? n.cloneNode(TRUE) : n;
|
29da64
|
5186 |
|
A |
5187 |
n.parentNode.removeChild(n);
|
69d05c
|
5188 |
};
|
A |
5189 |
};
|
29da64
|
5190 |
|
A |
5191 |
ns.Range = Range;
|
|
5192 |
})(tinymce.dom);
|
69d05c
|
5193 |
|
29da64
|
5194 |
(function() {
|
A |
5195 |
function Selection(selection) {
|
69d05c
|
5196 |
var t = this, invisibleChar = '\uFEFF', range, lastIERng, dom = selection.dom, TRUE = true, FALSE = false;
|
29da64
|
5197 |
|
69d05c
|
5198 |
// Returns a W3C DOM compatible range object by using the IE Range API
|
29da64
|
5199 |
function getRange() {
|
2011be
|
5200 |
var ieRange = selection.getRng(), domRange = dom.createRng(), element, collapsed;
|
29da64
|
5201 |
|
A |
5202 |
// If selection is outside the current document just return an empty range
|
|
5203 |
element = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
|
|
5204 |
if (element.ownerDocument != dom.doc)
|
|
5205 |
return domRange;
|
|
5206 |
|
a9251b
|
5207 |
collapsed = selection.isCollapsed();
|
T |
5208 |
|
29da64
|
5209 |
// Handle control selection or text selection of a image
|
A |
5210 |
if (ieRange.item || !element.hasChildNodes()) {
|
a9251b
|
5211 |
if (collapsed) {
|
T |
5212 |
domRange.setStart(element, 0);
|
|
5213 |
domRange.setEnd(element, 0);
|
|
5214 |
} else {
|
|
5215 |
domRange.setStart(element.parentNode, dom.nodeIndex(element));
|
|
5216 |
domRange.setEnd(domRange.startContainer, domRange.startOffset + 1);
|
|
5217 |
}
|
29da64
|
5218 |
|
A |
5219 |
return domRange;
|
|
5220 |
}
|
|
5221 |
|
2011be
|
5222 |
function findEndPoint(start) {
|
A |
5223 |
var marker, container, offset, nodes, startIndex = 0, endIndex, index, parent, checkRng, position;
|
29da64
|
5224 |
|
2011be
|
5225 |
// Setup temp range and collapse it
|
A |
5226 |
checkRng = ieRange.duplicate();
|
|
5227 |
checkRng.collapse(start);
|
29da64
|
5228 |
|
2011be
|
5229 |
// Create marker and insert it at the end of the endpoints parent
|
A |
5230 |
marker = dom.create('a');
|
|
5231 |
parent = checkRng.parentElement();
|
69d05c
|
5232 |
|
2011be
|
5233 |
// If parent doesn't have any children then set the container to that parent and the index to 0
|
A |
5234 |
if (!parent.hasChildNodes()) {
|
|
5235 |
domRange[start ? 'setStart' : 'setEnd'](parent, 0);
|
|
5236 |
return;
|
|
5237 |
}
|
69d05c
|
5238 |
|
2011be
|
5239 |
parent.appendChild(marker);
|
A |
5240 |
checkRng.moveToElementText(marker);
|
|
5241 |
position = ieRange.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', checkRng);
|
|
5242 |
if (position > 0) {
|
|
5243 |
// The position is after the end of the parent element.
|
|
5244 |
// This is the case where IE puts the caret to the left edge of a table.
|
|
5245 |
domRange[start ? 'setStartAfter' : 'setEndAfter'](parent);
|
|
5246 |
dom.remove(marker);
|
|
5247 |
return;
|
|
5248 |
}
|
|
5249 |
|
|
5250 |
// Setup node list and endIndex
|
|
5251 |
nodes = tinymce.grep(parent.childNodes);
|
|
5252 |
endIndex = nodes.length - 1;
|
|
5253 |
// Perform a binary search for the position
|
|
5254 |
while (startIndex <= endIndex) {
|
|
5255 |
index = Math.floor((startIndex + endIndex) / 2);
|
|
5256 |
|
|
5257 |
// Insert marker and check it's position relative to the selection
|
|
5258 |
parent.insertBefore(marker, nodes[index]);
|
|
5259 |
checkRng.moveToElementText(marker);
|
|
5260 |
position = ieRange.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', checkRng);
|
|
5261 |
if (position > 0) {
|
|
5262 |
// Marker is to the right
|
|
5263 |
startIndex = index + 1;
|
|
5264 |
} else if (position < 0) {
|
|
5265 |
// Marker is to the left
|
|
5266 |
endIndex = index - 1;
|
|
5267 |
} else {
|
|
5268 |
// Maker is where we are
|
|
5269 |
found = true;
|
|
5270 |
break;
|
|
5271 |
}
|
|
5272 |
}
|
|
5273 |
|
|
5274 |
// Setup container
|
|
5275 |
container = position > 0 || index == 0 ? marker.nextSibling : marker.previousSibling;
|
|
5276 |
|
|
5277 |
// Handle element selection
|
|
5278 |
if (container.nodeType == 1) {
|
69d05c
|
5279 |
dom.remove(marker);
|
A |
5280 |
|
2011be
|
5281 |
// Find offset and container
|
A |
5282 |
offset = dom.nodeIndex(container);
|
|
5283 |
container = container.parentNode;
|
|
5284 |
|
|
5285 |
// Move the offset if we are setting the end or the position is after an element
|
|
5286 |
if (!start || index > 0)
|
|
5287 |
offset++;
|
69d05c
|
5288 |
} else {
|
2011be
|
5289 |
// Calculate offset within text node
|
A |
5290 |
if (position > 0 || index == 0) {
|
|
5291 |
checkRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', ieRange);
|
|
5292 |
offset = checkRng.text.length;
|
69d05c
|
5293 |
} else {
|
2011be
|
5294 |
checkRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', ieRange);
|
A |
5295 |
offset = container.nodeValue.length - checkRng.text.length;
|
69d05c
|
5296 |
}
|
A |
5297 |
|
|
5298 |
dom.remove(marker);
|
|
5299 |
}
|
|
5300 |
|
2011be
|
5301 |
domRange[start ? 'setStart' : 'setEnd'](container, offset);
|
69d05c
|
5302 |
};
|
A |
5303 |
|
2011be
|
5304 |
// Find start point
|
A |
5305 |
findEndPoint(true);
|
69d05c
|
5306 |
|
2011be
|
5307 |
// Find end point if needed
|
69d05c
|
5308 |
if (!collapsed)
|
2011be
|
5309 |
findEndPoint();
|
29da64
|
5310 |
|
A |
5311 |
return domRange;
|
|
5312 |
};
|
|
5313 |
|
|
5314 |
this.addRange = function(rng) {
|
a9251b
|
5315 |
var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, doc = selection.dom.doc, body = doc.body;
|
69d05c
|
5316 |
|
a9251b
|
5317 |
function setEndPoint(start) {
|
T |
5318 |
var container, offset, marker, tmpRng, nodes;
|
|
5319 |
|
|
5320 |
marker = dom.create('a');
|
|
5321 |
container = start ? startContainer : endContainer;
|
|
5322 |
offset = start ? startOffset : endOffset;
|
|
5323 |
tmpRng = ieRng.duplicate();
|
|
5324 |
|
|
5325 |
if (container == doc || container == doc.documentElement) {
|
|
5326 |
container = body;
|
|
5327 |
offset = 0;
|
|
5328 |
}
|
|
5329 |
|
|
5330 |
if (container.nodeType == 3) {
|
|
5331 |
container.parentNode.insertBefore(marker, container);
|
|
5332 |
tmpRng.moveToElementText(marker);
|
|
5333 |
tmpRng.moveStart('character', offset);
|
|
5334 |
dom.remove(marker);
|
|
5335 |
ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
|
|
5336 |
} else {
|
|
5337 |
nodes = container.childNodes;
|
|
5338 |
|
|
5339 |
if (nodes.length) {
|
|
5340 |
if (offset >= nodes.length) {
|
|
5341 |
dom.insertAfter(marker, nodes[nodes.length - 1]);
|
|
5342 |
} else {
|
|
5343 |
container.insertBefore(marker, nodes[offset]);
|
|
5344 |
}
|
|
5345 |
|
|
5346 |
tmpRng.moveToElementText(marker);
|
|
5347 |
} else {
|
|
5348 |
// Empty node selection for example <div>|</div>
|
|
5349 |
marker = doc.createTextNode(invisibleChar);
|
|
5350 |
container.appendChild(marker);
|
|
5351 |
tmpRng.moveToElementText(marker.parentNode);
|
|
5352 |
tmpRng.collapse(TRUE);
|
|
5353 |
}
|
|
5354 |
|
|
5355 |
ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
|
|
5356 |
dom.remove(marker);
|
|
5357 |
}
|
|
5358 |
}
|
|
5359 |
|
|
5360 |
// Destroy cached range
|
69d05c
|
5361 |
this.destroy();
|
29da64
|
5362 |
|
A |
5363 |
// Setup some shorter versions
|
a9251b
|
5364 |
startContainer = rng.startContainer;
|
T |
5365 |
startOffset = rng.startOffset;
|
|
5366 |
endContainer = rng.endContainer;
|
|
5367 |
endOffset = rng.endOffset;
|
29da64
|
5368 |
ieRng = body.createTextRange();
|
A |
5369 |
|
a9251b
|
5370 |
// If single element selection then try making a control selection out of it
|
T |
5371 |
if (startContainer == endContainer && startContainer.nodeType == 1 && startOffset == endOffset - 1) {
|
|
5372 |
if (startOffset == endOffset - 1) {
|
|
5373 |
try {
|
|
5374 |
ctrlRng = body.createControlRange();
|
|
5375 |
ctrlRng.addElement(startContainer.childNodes[startOffset]);
|
|
5376 |
ctrlRng.select();
|
|
5377 |
return;
|
|
5378 |
} catch (ex) {
|
|
5379 |
// Ignore
|
29da64
|
5380 |
}
|
A |
5381 |
}
|
|
5382 |
}
|
|
5383 |
|
a9251b
|
5384 |
// Set start/end point of selection
|
T |
5385 |
setEndPoint(true);
|
|
5386 |
setEndPoint();
|
29da64
|
5387 |
|
a9251b
|
5388 |
// Select the new range and scroll it into view
|
69d05c
|
5389 |
ieRng.select();
|
29da64
|
5390 |
};
|
A |
5391 |
|
|
5392 |
this.getRangeAt = function() {
|
|
5393 |
// Setup new range if the cache is empty
|
2011be
|
5394 |
if (!range || !tinymce.dom.RangeUtils.compareRanges(lastIERng, selection.getRng())) {
|
29da64
|
5395 |
range = getRange();
|
A |
5396 |
|
|
5397 |
// Store away text range for next call
|
|
5398 |
lastIERng = selection.getRng();
|
2011be
|
5399 |
}
|
A |
5400 |
|
|
5401 |
// IE will say that the range is equal then produce an invalid argument exception
|
|
5402 |
// if you perform specific operations in a keyup event. For example Ctrl+Del.
|
|
5403 |
// This hack will invalidate the range cache if the exception occurs
|
|
5404 |
try {
|
|
5405 |
range.startContainer.nextSibling;
|
|
5406 |
} catch (ex) {
|
|
5407 |
range = getRange();
|
|
5408 |
lastIERng = null;
|
29da64
|
5409 |
}
|
A |
5410 |
|
|
5411 |
// Return cached range
|
|
5412 |
return range;
|
|
5413 |
};
|
|
5414 |
|
|
5415 |
this.destroy = function() {
|
|
5416 |
// Destroy cached range and last IE range to avoid memory leaks
|
|
5417 |
lastIERng = range = null;
|
|
5418 |
};
|
|
5419 |
};
|
|
5420 |
|
|
5421 |
// Expose the selection object
|
|
5422 |
tinymce.dom.TridentSelection = Selection;
|
d9344f
|
5423 |
})();
|
69d05c
|
5424 |
|
d9344f
|
5425 |
|
29da64
|
5426 |
/*
|
A |
5427 |
* Sizzle CSS Selector Engine - v1.0
|
|
5428 |
* Copyright 2009, The Dojo Foundation
|
|
5429 |
* Released under the MIT, BSD, and GPL Licenses.
|
|
5430 |
* More information: http://sizzlejs.com/
|
|
5431 |
*/
|
|
5432 |
(function(){
|
d9344f
|
5433 |
|
2011be
|
5434 |
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
|
29da64
|
5435 |
done = 0,
|
A |
5436 |
toString = Object.prototype.toString,
|
2011be
|
5437 |
hasDuplicate = false,
|
A |
5438 |
baseHasDuplicate = true;
|
|
5439 |
|
|
5440 |
// Here we check if the JavaScript engine is using some sort of
|
|
5441 |
// optimization where it does not always call our comparision
|
|
5442 |
// function. If that is the case, discard the hasDuplicate value.
|
|
5443 |
// Thus far that includes Google Chrome.
|
|
5444 |
[0, 0].sort(function(){
|
|
5445 |
baseHasDuplicate = false;
|
|
5446 |
return 0;
|
|
5447 |
});
|
29da64
|
5448 |
|
A |
5449 |
var Sizzle = function(selector, context, results, seed) {
|
|
5450 |
results = results || [];
|
2011be
|
5451 |
context = context || document;
|
A |
5452 |
|
|
5453 |
var origContext = context;
|
29da64
|
5454 |
|
A |
5455 |
if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
|
|
5456 |
return [];
|
|
5457 |
}
|
|
5458 |
|
|
5459 |
if ( !selector || typeof selector !== "string" ) {
|
|
5460 |
return results;
|
|
5461 |
}
|
|
5462 |
|
2011be
|
5463 |
var parts = [], m, set, checkSet, extra, prune = true, contextXML = Sizzle.isXML(context),
|
A |
5464 |
soFar = selector, ret, cur, pop, i;
|
29da64
|
5465 |
|
A |
5466 |
// Reset the position of the chunker regexp (start from head)
|
2011be
|
5467 |
do {
|
A |
5468 |
chunker.exec("");
|
|
5469 |
m = chunker.exec(soFar);
|
|
5470 |
|
|
5471 |
if ( m ) {
|
|
5472 |
soFar = m[3];
|
29da64
|
5473 |
|
2011be
|
5474 |
parts.push( m[1] );
|
A |
5475 |
|
|
5476 |
if ( m[2] ) {
|
|
5477 |
extra = m[3];
|
|
5478 |
break;
|
|
5479 |
}
|
29da64
|
5480 |
}
|
2011be
|
5481 |
} while ( m );
|
29da64
|
5482 |
|
A |
5483 |
if ( parts.length > 1 && origPOS.exec( selector ) ) {
|
|
5484 |
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
|
|
5485 |
set = posProcess( parts[0] + parts[1], context );
|
|
5486 |
} else {
|
|
5487 |
set = Expr.relative[ parts[0] ] ?
|
|
5488 |
[ context ] :
|
|
5489 |
Sizzle( parts.shift(), context );
|
|
5490 |
|
|
5491 |
while ( parts.length ) {
|
|
5492 |
selector = parts.shift();
|
|
5493 |
|
2011be
|
5494 |
if ( Expr.relative[ selector ] ) {
|
29da64
|
5495 |
selector += parts.shift();
|
2011be
|
5496 |
}
|
A |
5497 |
|
29da64
|
5498 |
set = posProcess( selector, set );
|
A |
5499 |
}
|
|
5500 |
}
|
|
5501 |
} else {
|
|
5502 |
// Take a shortcut and set the context if the root selector is an ID
|
|
5503 |
// (but not if it'll be faster if the inner selector is an ID)
|
|
5504 |
if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
|
|
5505 |
Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
|
2011be
|
5506 |
ret = Sizzle.find( parts.shift(), context, contextXML );
|
29da64
|
5507 |
context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
|
A |
5508 |
}
|
|
5509 |
|
|
5510 |
if ( context ) {
|
2011be
|
5511 |
ret = seed ?
|
29da64
|
5512 |
{ expr: parts.pop(), set: makeArray(seed) } :
|
A |
5513 |
Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
|
|
5514 |
set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
|
|
5515 |
|
|
5516 |
if ( parts.length > 0 ) {
|
|
5517 |
checkSet = makeArray(set);
|
|
5518 |
} else {
|
|
5519 |
prune = false;
|
|
5520 |
}
|
|
5521 |
|
|
5522 |
while ( parts.length ) {
|
2011be
|
5523 |
cur = parts.pop();
|
A |
5524 |
pop = cur;
|
29da64
|
5525 |
|
A |
5526 |
if ( !Expr.relative[ cur ] ) {
|
|
5527 |
cur = "";
|
|
5528 |
} else {
|
|
5529 |
pop = parts.pop();
|
|
5530 |
}
|
|
5531 |
|
|
5532 |
if ( pop == null ) {
|
|
5533 |
pop = context;
|
|
5534 |
}
|
|
5535 |
|
|
5536 |
Expr.relative[ cur ]( checkSet, pop, contextXML );
|
|
5537 |
}
|
|
5538 |
} else {
|
|
5539 |
checkSet = parts = [];
|
|
5540 |
}
|
|
5541 |
}
|
|
5542 |
|
|
5543 |
if ( !checkSet ) {
|
|
5544 |
checkSet = set;
|
|
5545 |
}
|
|
5546 |
|
|
5547 |
if ( !checkSet ) {
|
2011be
|
5548 |
Sizzle.error( cur || selector );
|
29da64
|
5549 |
}
|
A |
5550 |
|
|
5551 |
if ( toString.call(checkSet) === "[object Array]" ) {
|
|
5552 |
if ( !prune ) {
|
|
5553 |
results.push.apply( results, checkSet );
|
|
5554 |
} else if ( context && context.nodeType === 1 ) {
|
2011be
|
5555 |
for ( i = 0; checkSet[i] != null; i++ ) {
|
A |
5556 |
if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
|
29da64
|
5557 |
results.push( set[i] );
|
A |
5558 |
}
|
|
5559 |
}
|
|
5560 |
} else {
|
2011be
|
5561 |
for ( i = 0; checkSet[i] != null; i++ ) {
|
29da64
|
5562 |
if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
|
A |
5563 |
results.push( set[i] );
|
|
5564 |
}
|
|
5565 |
}
|
|
5566 |
}
|
|
5567 |
} else {
|
|
5568 |
makeArray( checkSet, results );
|
|
5569 |
}
|
|
5570 |
|
|
5571 |
if ( extra ) {
|
|
5572 |
Sizzle( extra, origContext, results, seed );
|
|
5573 |
Sizzle.uniqueSort( results );
|
|
5574 |
}
|
|
5575 |
|
|
5576 |
return results;
|
|
5577 |
};
|
|
5578 |
|
|
5579 |
Sizzle.uniqueSort = function(results){
|
|
5580 |
if ( sortOrder ) {
|
2011be
|
5581 |
hasDuplicate = baseHasDuplicate;
|
29da64
|
5582 |
results.sort(sortOrder);
|
A |
5583 |
|
|
5584 |
if ( hasDuplicate ) {
|
|
5585 |
for ( var i = 1; i < results.length; i++ ) {
|
|
5586 |
if ( results[i] === results[i-1] ) {
|
|
5587 |
results.splice(i--, 1);
|
|
5588 |
}
|
|
5589 |
}
|
|
5590 |
}
|
|
5591 |
}
|
2011be
|
5592 |
|
A |
5593 |
return results;
|
29da64
|
5594 |
};
|
A |
5595 |
|
|
5596 |
Sizzle.matches = function(expr, set){
|
|
5597 |
return Sizzle(expr, null, null, set);
|
|
5598 |
};
|
|
5599 |
|
|
5600 |
Sizzle.find = function(expr, context, isXML){
|
2011be
|
5601 |
var set;
|
29da64
|
5602 |
|
A |
5603 |
if ( !expr ) {
|
|
5604 |
return [];
|
|
5605 |
}
|
|
5606 |
|
|
5607 |
for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
|
|
5608 |
var type = Expr.order[i], match;
|
|
5609 |
|
2011be
|
5610 |
if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
|
A |
5611 |
var left = match[1];
|
|
5612 |
match.splice(1,1);
|
29da64
|
5613 |
|
A |
5614 |
if ( left.substr( left.length - 1 ) !== "\\" ) {
|
|
5615 |
match[1] = (match[1] || "").replace(/\\/g, "");
|
|
5616 |
set = Expr.find[ type ]( match, context, isXML );
|
|
5617 |
if ( set != null ) {
|
|
5618 |
expr = expr.replace( Expr.match[ type ], "" );
|
|
5619 |
break;
|
|
5620 |
}
|
|
5621 |
}
|
|
5622 |
}
|
|
5623 |
}
|
|
5624 |
|
|
5625 |
if ( !set ) {
|
|
5626 |
set = context.getElementsByTagName("*");
|
|
5627 |
}
|
|
5628 |
|
|
5629 |
return {set: set, expr: expr};
|
|
5630 |
};
|
|
5631 |
|
|
5632 |
Sizzle.filter = function(expr, set, inplace, not){
|
|
5633 |
var old = expr, result = [], curLoop = set, match, anyFound,
|
2011be
|
5634 |
isXMLFilter = set && set[0] && Sizzle.isXML(set[0]);
|
29da64
|
5635 |
|
A |
5636 |
while ( expr && set.length ) {
|
|
5637 |
for ( var type in Expr.filter ) {
|
2011be
|
5638 |
if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
|
A |
5639 |
var filter = Expr.filter[ type ], found, item, left = match[1];
|
29da64
|
5640 |
anyFound = false;
|
A |
5641 |
|
2011be
|
5642 |
match.splice(1,1);
|
A |
5643 |
|
|
5644 |
if ( left.substr( left.length - 1 ) === "\\" ) {
|
|
5645 |
continue;
|
|
5646 |
}
|
|
5647 |
|
|
5648 |
if ( curLoop === result ) {
|
29da64
|
5649 |
result = [];
|
A |
5650 |
}
|
|
5651 |
|
|
5652 |
if ( Expr.preFilter[ type ] ) {
|
|
5653 |
match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
|
|
5654 |
|
|
5655 |
if ( !match ) {
|
|
5656 |
anyFound = found = true;
|
|
5657 |
} else if ( match === true ) {
|
|
5658 |
continue;
|
|
5659 |
}
|
|
5660 |
}
|
|
5661 |
|
|
5662 |
if ( match ) {
|
|
5663 |
for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
|
|
5664 |
if ( item ) {
|
|
5665 |
found = filter( item, match, i, curLoop );
|
|
5666 |
var pass = not ^ !!found;
|
|
5667 |
|
|
5668 |
if ( inplace && found != null ) {
|
|
5669 |
if ( pass ) {
|
|
5670 |
anyFound = true;
|
|
5671 |
} else {
|
|
5672 |
curLoop[i] = false;
|
|
5673 |
}
|
|
5674 |
} else if ( pass ) {
|
|
5675 |
result.push( item );
|
|
5676 |
anyFound = true;
|
|
5677 |
}
|
|
5678 |
}
|
|
5679 |
}
|
|
5680 |
}
|
|
5681 |
|
|
5682 |
if ( found !== undefined ) {
|
|
5683 |
if ( !inplace ) {
|
|
5684 |
curLoop = result;
|
|
5685 |
}
|
|
5686 |
|
|
5687 |
expr = expr.replace( Expr.match[ type ], "" );
|
|
5688 |
|
|
5689 |
if ( !anyFound ) {
|
|
5690 |
return [];
|
|
5691 |
}
|
|
5692 |
|
|
5693 |
break;
|
|
5694 |
}
|
|
5695 |
}
|
|
5696 |
}
|
|
5697 |
|
|
5698 |
// Improper expression
|
2011be
|
5699 |
if ( expr === old ) {
|
29da64
|
5700 |
if ( anyFound == null ) {
|
2011be
|
5701 |
Sizzle.error( expr );
|
29da64
|
5702 |
} else {
|
A |
5703 |
break;
|
|
5704 |
}
|
|
5705 |
}
|
|
5706 |
|
|
5707 |
old = expr;
|
|
5708 |
}
|
|
5709 |
|
|
5710 |
return curLoop;
|
|
5711 |
};
|
|
5712 |
|
2011be
|
5713 |
Sizzle.error = function( msg ) {
|
A |
5714 |
throw "Syntax error, unrecognized expression: " + msg;
|
|
5715 |
};
|
|
5716 |
|
29da64
|
5717 |
var Expr = Sizzle.selectors = {
|
A |
5718 |
order: [ "ID", "NAME", "TAG" ],
|
|
5719 |
match: {
|
2011be
|
5720 |
ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
|
A |
5721 |
CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
|
|
5722 |
NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
|
|
5723 |
ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
|
|
5724 |
TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
|
|
5725 |
CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
|
|
5726 |
POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
|
|
5727 |
PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
|
29da64
|
5728 |
},
|
2011be
|
5729 |
leftMatch: {},
|
29da64
|
5730 |
attrMap: {
|
A |
5731 |
"class": "className",
|
|
5732 |
"for": "htmlFor"
|
|
5733 |
},
|
|
5734 |
attrHandle: {
|
|
5735 |
href: function(elem){
|
|
5736 |
return elem.getAttribute("href");
|
|
5737 |
}
|
|
5738 |
},
|
|
5739 |
relative: {
|
2011be
|
5740 |
"+": function(checkSet, part){
|
29da64
|
5741 |
var isPartStr = typeof part === "string",
|
A |
5742 |
isTag = isPartStr && !/\W/.test(part),
|
|
5743 |
isPartStrNotTag = isPartStr && !isTag;
|
|
5744 |
|
2011be
|
5745 |
if ( isTag ) {
|
A |
5746 |
part = part.toLowerCase();
|
29da64
|
5747 |
}
|
A |
5748 |
|
|
5749 |
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
|
|
5750 |
if ( (elem = checkSet[i]) ) {
|
|
5751 |
while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
|
|
5752 |
|
2011be
|
5753 |
checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
|
29da64
|
5754 |
elem || false :
|
A |
5755 |
elem === part;
|
|
5756 |
}
|
|
5757 |
}
|
|
5758 |
|
|
5759 |
if ( isPartStrNotTag ) {
|
|
5760 |
Sizzle.filter( part, checkSet, true );
|
|
5761 |
}
|
|
5762 |
},
|
2011be
|
5763 |
">": function(checkSet, part){
|
A |
5764 |
var isPartStr = typeof part === "string",
|
|
5765 |
elem, i = 0, l = checkSet.length;
|
29da64
|
5766 |
|
A |
5767 |
if ( isPartStr && !/\W/.test(part) ) {
|
2011be
|
5768 |
part = part.toLowerCase();
|
29da64
|
5769 |
|
2011be
|
5770 |
for ( ; i < l; i++ ) {
|
A |
5771 |
elem = checkSet[i];
|
29da64
|
5772 |
if ( elem ) {
|
A |
5773 |
var parent = elem.parentNode;
|
2011be
|
5774 |
checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
|
29da64
|
5775 |
}
|
A |
5776 |
}
|
|
5777 |
} else {
|
2011be
|
5778 |
for ( ; i < l; i++ ) {
|
A |
5779 |
elem = checkSet[i];
|
29da64
|
5780 |
if ( elem ) {
|
A |
5781 |
checkSet[i] = isPartStr ?
|
|
5782 |
elem.parentNode :
|
|
5783 |
elem.parentNode === part;
|
|
5784 |
}
|
|
5785 |
}
|
|
5786 |
|
|
5787 |
if ( isPartStr ) {
|
|
5788 |
Sizzle.filter( part, checkSet, true );
|
|
5789 |
}
|
|
5790 |
}
|
|
5791 |
},
|
|
5792 |
"": function(checkSet, part, isXML){
|
2011be
|
5793 |
var doneName = done++, checkFn = dirCheck, nodeCheck;
|
29da64
|
5794 |
|
2011be
|
5795 |
if ( typeof part === "string" && !/\W/.test(part) ) {
|
A |
5796 |
part = part.toLowerCase();
|
|
5797 |
nodeCheck = part;
|
29da64
|
5798 |
checkFn = dirNodeCheck;
|
A |
5799 |
}
|
|
5800 |
|
|
5801 |
checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
|
|
5802 |
},
|
|
5803 |
"~": function(checkSet, part, isXML){
|
2011be
|
5804 |
var doneName = done++, checkFn = dirCheck, nodeCheck;
|
29da64
|
5805 |
|
2011be
|
5806 |
if ( typeof part === "string" && !/\W/.test(part) ) {
|
A |
5807 |
part = part.toLowerCase();
|
|
5808 |
nodeCheck = part;
|
29da64
|
5809 |
checkFn = dirNodeCheck;
|
A |
5810 |
}
|
|
5811 |
|
|
5812 |
checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
|
|
5813 |
}
|
|
5814 |
},
|
|
5815 |
find: {
|
|
5816 |
ID: function(match, context, isXML){
|
|
5817 |
if ( typeof context.getElementById !== "undefined" && !isXML ) {
|
|
5818 |
var m = context.getElementById(match[1]);
|
|
5819 |
return m ? [m] : [];
|
|
5820 |
}
|
|
5821 |
},
|
2011be
|
5822 |
NAME: function(match, context){
|
29da64
|
5823 |
if ( typeof context.getElementsByName !== "undefined" ) {
|
A |
5824 |
var ret = [], results = context.getElementsByName(match[1]);
|
|
5825 |
|
|
5826 |
for ( var i = 0, l = results.length; i < l; i++ ) {
|
|
5827 |
if ( results[i].getAttribute("name") === match[1] ) {
|
|
5828 |
ret.push( results[i] );
|
|
5829 |
}
|
|
5830 |
}
|
|
5831 |
|
|
5832 |
return ret.length === 0 ? null : ret;
|
|
5833 |
}
|
|
5834 |
},
|
|
5835 |
TAG: function(match, context){
|
|
5836 |
return context.getElementsByTagName(match[1]);
|
|
5837 |
}
|
|
5838 |
},
|
|
5839 |
preFilter: {
|
|
5840 |
CLASS: function(match, curLoop, inplace, result, not, isXML){
|
|
5841 |
match = " " + match[1].replace(/\\/g, "") + " ";
|
|
5842 |
|
|
5843 |
if ( isXML ) {
|
|
5844 |
return match;
|
|
5845 |
}
|
|
5846 |
|
|
5847 |
for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
|
|
5848 |
if ( elem ) {
|
2011be
|
5849 |
if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
|
A |
5850 |
if ( !inplace ) {
|
29da64
|
5851 |
result.push( elem );
|
2011be
|
5852 |
}
|
29da64
|
5853 |
} else if ( inplace ) {
|
A |
5854 |
curLoop[i] = false;
|
|
5855 |
}
|
|
5856 |
}
|
|
5857 |
}
|
|
5858 |
|
|
5859 |
return false;
|
|
5860 |
},
|
|
5861 |
ID: function(match){
|
|
5862 |
return match[1].replace(/\\/g, "");
|
|
5863 |
},
|
|
5864 |
TAG: function(match, curLoop){
|
2011be
|
5865 |
return match[1].toLowerCase();
|
29da64
|
5866 |
},
|
A |
5867 |
CHILD: function(match){
|
2011be
|
5868 |
if ( match[1] === "nth" ) {
|
29da64
|
5869 |
// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
|
A |
5870 |
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
|
2011be
|
5871 |
match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
|
29da64
|
5872 |
!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
|
A |
5873 |
|
|
5874 |
// calculate the numbers (first)n+(last) including if they are negative
|
|
5875 |
match[2] = (test[1] + (test[2] || 1)) - 0;
|
|
5876 |
match[3] = test[3] - 0;
|
|
5877 |
}
|
|
5878 |
|
|
5879 |
// TODO: Move to normal caching system
|
|
5880 |
match[0] = done++;
|
|
5881 |
|
|
5882 |
return match;
|
|
5883 |
},
|
|
5884 |
ATTR: function(match, curLoop, inplace, result, not, isXML){
|
|
5885 |
var name = match[1].replace(/\\/g, "");
|
|
5886 |
|
|
5887 |
if ( !isXML && Expr.attrMap[name] ) {
|
|
5888 |
match[1] = Expr.attrMap[name];
|
|
5889 |
}
|
|
5890 |
|
|
5891 |
if ( match[2] === "~=" ) {
|
|
5892 |
match[4] = " " + match[4] + " ";
|
|
5893 |
}
|
|
5894 |
|
|
5895 |
return match;
|
|
5896 |
},
|
|
5897 |
PSEUDO: function(match, curLoop, inplace, result, not){
|
|
5898 |
if ( match[1] === "not" ) {
|
|
5899 |
// If we're dealing with a complex expression, or a simple one
|
2011be
|
5900 |
if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
|
29da64
|
5901 |
match[3] = Sizzle(match[3], null, null, curLoop);
|
A |
5902 |
} else {
|
|
5903 |
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
|
|
5904 |
if ( !inplace ) {
|
|
5905 |
result.push.apply( result, ret );
|
|
5906 |
}
|
|
5907 |
return false;
|
|
5908 |
}
|
|
5909 |
} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
|
|
5910 |
return true;
|
|
5911 |
}
|
|
5912 |
|
|
5913 |
return match;
|
|
5914 |
},
|
|
5915 |
POS: function(match){
|
|
5916 |
match.unshift( true );
|
|
5917 |
return match;
|
|
5918 |
}
|
|
5919 |
},
|
|
5920 |
filters: {
|
|
5921 |
enabled: function(elem){
|
|
5922 |
return elem.disabled === false && elem.type !== "hidden";
|
|
5923 |
},
|
|
5924 |
disabled: function(elem){
|
|
5925 |
return elem.disabled === true;
|
|
5926 |
},
|
|
5927 |
checked: function(elem){
|
|
5928 |
return elem.checked === true;
|
|
5929 |
},
|
|
5930 |
selected: function(elem){
|
|
5931 |
// Accessing this property makes selected-by-default
|
|
5932 |
// options in Safari work properly
|
|
5933 |
elem.parentNode.selectedIndex;
|
|
5934 |
return elem.selected === true;
|
|
5935 |
},
|
|
5936 |
parent: function(elem){
|
|
5937 |
return !!elem.firstChild;
|
|
5938 |
},
|
|
5939 |
empty: function(elem){
|
|
5940 |
return !elem.firstChild;
|
|
5941 |
},
|
|
5942 |
has: function(elem, i, match){
|
|
5943 |
return !!Sizzle( match[3], elem ).length;
|
|
5944 |
},
|
|
5945 |
header: function(elem){
|
2011be
|
5946 |
return (/h\d/i).test( elem.nodeName );
|
29da64
|
5947 |
},
|
A |
5948 |
text: function(elem){
|
|
5949 |
return "text" === elem.type;
|
|
5950 |
},
|
|
5951 |
radio: function(elem){
|
|
5952 |
return "radio" === elem.type;
|
|
5953 |
},
|
|
5954 |
checkbox: function(elem){
|
|
5955 |
return "checkbox" === elem.type;
|
|
5956 |
},
|
|
5957 |
file: function(elem){
|
|
5958 |
return "file" === elem.type;
|
|
5959 |
},
|
|
5960 |
password: function(elem){
|
|
5961 |
return "password" === elem.type;
|
|
5962 |
},
|
|
5963 |
submit: function(elem){
|
|
5964 |
return "submit" === elem.type;
|
|
5965 |
},
|
|
5966 |
image: function(elem){
|
|
5967 |
return "image" === elem.type;
|
|
5968 |
},
|
|
5969 |
reset: function(elem){
|
|
5970 |
return "reset" === elem.type;
|
|
5971 |
},
|
|
5972 |
button: function(elem){
|
2011be
|
5973 |
return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
|
29da64
|
5974 |
},
|
A |
5975 |
input: function(elem){
|
2011be
|
5976 |
return (/input|select|textarea|button/i).test(elem.nodeName);
|
29da64
|
5977 |
}
|
A |
5978 |
},
|
|
5979 |
setFilters: {
|
|
5980 |
first: function(elem, i){
|
|
5981 |
return i === 0;
|
|
5982 |
},
|
|
5983 |
last: function(elem, i, match, array){
|
|
5984 |
return i === array.length - 1;
|
|
5985 |
},
|
|
5986 |
even: function(elem, i){
|
|
5987 |
return i % 2 === 0;
|
|
5988 |
},
|
|
5989 |
odd: function(elem, i){
|
|
5990 |
return i % 2 === 1;
|
|
5991 |
},
|
|
5992 |
lt: function(elem, i, match){
|
|
5993 |
return i < match[3] - 0;
|
|
5994 |
},
|
|
5995 |
gt: function(elem, i, match){
|
|
5996 |
return i > match[3] - 0;
|
|
5997 |
},
|
|
5998 |
nth: function(elem, i, match){
|
2011be
|
5999 |
return match[3] - 0 === i;
|
29da64
|
6000 |
},
|
A |
6001 |
eq: function(elem, i, match){
|
2011be
|
6002 |
return match[3] - 0 === i;
|
29da64
|
6003 |
}
|
A |
6004 |
},
|
|
6005 |
filter: {
|
|
6006 |
PSEUDO: function(elem, match, i, array){
|
|
6007 |
var name = match[1], filter = Expr.filters[ name ];
|
|
6008 |
|
|
6009 |
if ( filter ) {
|
|
6010 |
return filter( elem, i, match, array );
|
|
6011 |
} else if ( name === "contains" ) {
|
2011be
|
6012 |
return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
|
29da64
|
6013 |
} else if ( name === "not" ) {
|
A |
6014 |
var not = match[3];
|
|
6015 |
|
2011be
|
6016 |
for ( var j = 0, l = not.length; j < l; j++ ) {
|
A |
6017 |
if ( not[j] === elem ) {
|
29da64
|
6018 |
return false;
|
A |
6019 |
}
|
|
6020 |
}
|
|
6021 |
|
|
6022 |
return true;
|
2011be
|
6023 |
} else {
|
A |
6024 |
Sizzle.error( "Syntax error, unrecognized expression: " + name );
|
29da64
|
6025 |
}
|
A |
6026 |
},
|
|
6027 |
CHILD: function(elem, match){
|
|
6028 |
var type = match[1], node = elem;
|
|
6029 |
switch (type) {
|
|
6030 |
case 'only':
|
|
6031 |
case 'first':
|
2011be
|
6032 |
while ( (node = node.previousSibling) ) {
|
A |
6033 |
if ( node.nodeType === 1 ) {
|
|
6034 |
return false;
|
|
6035 |
}
|
29da64
|
6036 |
}
|
2011be
|
6037 |
if ( type === "first" ) {
|
A |
6038 |
return true;
|
|
6039 |
}
|
29da64
|
6040 |
node = elem;
|
A |
6041 |
case 'last':
|
2011be
|
6042 |
while ( (node = node.nextSibling) ) {
|
A |
6043 |
if ( node.nodeType === 1 ) {
|
|
6044 |
return false;
|
|
6045 |
}
|
29da64
|
6046 |
}
|
A |
6047 |
return true;
|
|
6048 |
case 'nth':
|
|
6049 |
var first = match[2], last = match[3];
|
|
6050 |
|
2011be
|
6051 |
if ( first === 1 && last === 0 ) {
|
29da64
|
6052 |
return true;
|
A |
6053 |
}
|
|
6054 |
|
|
6055 |
var doneName = match[0],
|
|
6056 |
parent = elem.parentNode;
|
|
6057 |
|
|
6058 |
if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
|
|
6059 |
var count = 0;
|
|
6060 |
for ( node = parent.firstChild; node; node = node.nextSibling ) {
|
|
6061 |
if ( node.nodeType === 1 ) {
|
|
6062 |
node.nodeIndex = ++count;
|
|
6063 |
}
|
|
6064 |
}
|
|
6065 |
parent.sizcache = doneName;
|
|
6066 |
}
|
|
6067 |
|
|
6068 |
var diff = elem.nodeIndex - last;
|
2011be
|
6069 |
if ( first === 0 ) {
|
A |
6070 |
return diff === 0;
|
29da64
|
6071 |
} else {
|
2011be
|
6072 |
return ( diff % first === 0 && diff / first >= 0 );
|
29da64
|
6073 |
}
|
A |
6074 |
}
|
|
6075 |
},
|
|
6076 |
ID: function(elem, match){
|
|
6077 |
return elem.nodeType === 1 && elem.getAttribute("id") === match;
|
|
6078 |
},
|
|
6079 |
TAG: function(elem, match){
|
2011be
|
6080 |
return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
|
29da64
|
6081 |
},
|
A |
6082 |
CLASS: function(elem, match){
|
|
6083 |
return (" " + (elem.className || elem.getAttribute("class")) + " ")
|
|
6084 |
.indexOf( match ) > -1;
|
|
6085 |
},
|
|
6086 |
ATTR: function(elem, match){
|
|
6087 |
var name = match[1],
|
|
6088 |
result = Expr.attrHandle[ name ] ?
|
|
6089 |
Expr.attrHandle[ name ]( elem ) :
|
|
6090 |
elem[ name ] != null ?
|
|
6091 |
elem[ name ] :
|
|
6092 |
elem.getAttribute( name ),
|
|
6093 |
value = result + "",
|
|
6094 |
type = match[2],
|
|
6095 |
check = match[4];
|
|
6096 |
|
|
6097 |
return result == null ?
|
|
6098 |
type === "!=" :
|
|
6099 |
type === "=" ?
|
|
6100 |
value === check :
|
|
6101 |
type === "*=" ?
|
|
6102 |
value.indexOf(check) >= 0 :
|
|
6103 |
type === "~=" ?
|
|
6104 |
(" " + value + " ").indexOf(check) >= 0 :
|
|
6105 |
!check ?
|
|
6106 |
value && result !== false :
|
|
6107 |
type === "!=" ?
|
2011be
|
6108 |
value !== check :
|
29da64
|
6109 |
type === "^=" ?
|
A |
6110 |
value.indexOf(check) === 0 :
|
|
6111 |
type === "$=" ?
|
|
6112 |
value.substr(value.length - check.length) === check :
|
|
6113 |
type === "|=" ?
|
|
6114 |
value === check || value.substr(0, check.length + 1) === check + "-" :
|
|
6115 |
false;
|
|
6116 |
},
|
|
6117 |
POS: function(elem, match, i, array){
|
|
6118 |
var name = match[2], filter = Expr.setFilters[ name ];
|
|
6119 |
|
|
6120 |
if ( filter ) {
|
|
6121 |
return filter( elem, i, match, array );
|
|
6122 |
}
|
|
6123 |
}
|
|
6124 |
}
|
|
6125 |
};
|
|
6126 |
|
2011be
|
6127 |
var origPOS = Expr.match.POS,
|
A |
6128 |
fescape = function(all, num){
|
|
6129 |
return "\\" + (num - 0 + 1);
|
|
6130 |
};
|
29da64
|
6131 |
|
A |
6132 |
for ( var type in Expr.match ) {
|
2011be
|
6133 |
Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
|
A |
6134 |
Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
|
29da64
|
6135 |
}
|
A |
6136 |
|
|
6137 |
var makeArray = function(array, results) {
|
2011be
|
6138 |
array = Array.prototype.slice.call( array, 0 );
|
29da64
|
6139 |
|
A |
6140 |
if ( results ) {
|
|
6141 |
results.push.apply( results, array );
|
|
6142 |
return results;
|
|
6143 |
}
|
|
6144 |
|
|
6145 |
return array;
|
|
6146 |
};
|
|
6147 |
|
|
6148 |
// Perform a simple check to determine if the browser is capable of
|
|
6149 |
// converting a NodeList to an array using builtin methods.
|
2011be
|
6150 |
// Also verifies that the returned array holds DOM nodes
|
A |
6151 |
// (which is not the case in the Blackberry browser)
|
29da64
|
6152 |
try {
|
2011be
|
6153 |
Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
|
29da64
|
6154 |
|
A |
6155 |
// Provide a fallback method if it does not work
|
|
6156 |
} catch(e){
|
|
6157 |
makeArray = function(array, results) {
|
2011be
|
6158 |
var ret = results || [], i = 0;
|
29da64
|
6159 |
|
A |
6160 |
if ( toString.call(array) === "[object Array]" ) {
|
|
6161 |
Array.prototype.push.apply( ret, array );
|
|
6162 |
} else {
|
|
6163 |
if ( typeof array.length === "number" ) {
|
2011be
|
6164 |
for ( var l = array.length; i < l; i++ ) {
|
29da64
|
6165 |
ret.push( array[i] );
|
A |
6166 |
}
|
|
6167 |
} else {
|
2011be
|
6168 |
for ( ; array[i]; i++ ) {
|
29da64
|
6169 |
ret.push( array[i] );
|
A |
6170 |
}
|
|
6171 |
}
|
|
6172 |
}
|
|
6173 |
|
|
6174 |
return ret;
|
|
6175 |
};
|
|
6176 |
}
|
|
6177 |
|
|
6178 |
var sortOrder;
|
|
6179 |
|
|
6180 |
if ( document.documentElement.compareDocumentPosition ) {
|
|
6181 |
sortOrder = function( a, b ) {
|
2011be
|
6182 |
if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
|
A |
6183 |
if ( a == b ) {
|
|
6184 |
hasDuplicate = true;
|
|
6185 |
}
|
|
6186 |
return a.compareDocumentPosition ? -1 : 1;
|
|
6187 |
}
|
|
6188 |
|
29da64
|
6189 |
var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
|
A |
6190 |
if ( ret === 0 ) {
|
|
6191 |
hasDuplicate = true;
|
|
6192 |
}
|
|
6193 |
return ret;
|
|
6194 |
};
|
|
6195 |
} else if ( "sourceIndex" in document.documentElement ) {
|
|
6196 |
sortOrder = function( a, b ) {
|
2011be
|
6197 |
if ( !a.sourceIndex || !b.sourceIndex ) {
|
A |
6198 |
if ( a == b ) {
|
|
6199 |
hasDuplicate = true;
|
|
6200 |
}
|
|
6201 |
return a.sourceIndex ? -1 : 1;
|
|
6202 |
}
|
|
6203 |
|
29da64
|
6204 |
var ret = a.sourceIndex - b.sourceIndex;
|
A |
6205 |
if ( ret === 0 ) {
|
|
6206 |
hasDuplicate = true;
|
|
6207 |
}
|
|
6208 |
return ret;
|
|
6209 |
};
|
|
6210 |
} else if ( document.createRange ) {
|
|
6211 |
sortOrder = function( a, b ) {
|
2011be
|
6212 |
if ( !a.ownerDocument || !b.ownerDocument ) {
|
A |
6213 |
if ( a == b ) {
|
|
6214 |
hasDuplicate = true;
|
|
6215 |
}
|
|
6216 |
return a.ownerDocument ? -1 : 1;
|
|
6217 |
}
|
|
6218 |
|
29da64
|
6219 |
var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
|
A |
6220 |
aRange.setStart(a, 0);
|
|
6221 |
aRange.setEnd(a, 0);
|
|
6222 |
bRange.setStart(b, 0);
|
|
6223 |
bRange.setEnd(b, 0);
|
|
6224 |
var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
|
|
6225 |
if ( ret === 0 ) {
|
|
6226 |
hasDuplicate = true;
|
|
6227 |
}
|
|
6228 |
return ret;
|
|
6229 |
};
|
|
6230 |
}
|
|
6231 |
|
2011be
|
6232 |
// Utility function for retreiving the text value of an array of DOM nodes
|
A |
6233 |
Sizzle.getText = function( elems ) {
|
|
6234 |
var ret = "", elem;
|
|
6235 |
|
|
6236 |
for ( var i = 0; elems[i]; i++ ) {
|
|
6237 |
elem = elems[i];
|
|
6238 |
|
|
6239 |
// Get the text from text nodes and CDATA nodes
|
|
6240 |
if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
|
|
6241 |
ret += elem.nodeValue;
|
|
6242 |
|
|
6243 |
// Traverse everything else, except comment nodes
|
|
6244 |
} else if ( elem.nodeType !== 8 ) {
|
|
6245 |
ret += Sizzle.getText( elem.childNodes );
|
|
6246 |
}
|
|
6247 |
}
|
|
6248 |
|
|
6249 |
return ret;
|
|
6250 |
};
|
|
6251 |
|
29da64
|
6252 |
// Check to see if the browser returns elements by name when
|
A |
6253 |
// querying by getElementById (and provide a workaround)
|
|
6254 |
(function(){
|
|
6255 |
// We're going to inject a fake input element with a specified name
|
|
6256 |
var form = document.createElement("div"),
|
2011be
|
6257 |
id = "script" + (new Date()).getTime();
|
29da64
|
6258 |
form.innerHTML = "<a name='" + id + "'/>";
|
A |
6259 |
|
|
6260 |
// Inject it into the root element, check its status, and remove it quickly
|
|
6261 |
var root = document.documentElement;
|
|
6262 |
root.insertBefore( form, root.firstChild );
|
|
6263 |
|
|
6264 |
// The workaround has to do additional checks after a getElementById
|
|
6265 |
// Which slows things down for other browsers (hence the branching)
|
2011be
|
6266 |
if ( document.getElementById( id ) ) {
|
29da64
|
6267 |
Expr.find.ID = function(match, context, isXML){
|
A |
6268 |
if ( typeof context.getElementById !== "undefined" && !isXML ) {
|
|
6269 |
var m = context.getElementById(match[1]);
|
|
6270 |
return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
|
|
6271 |
}
|
|
6272 |
};
|
|
6273 |
|
|
6274 |
Expr.filter.ID = function(elem, match){
|
|
6275 |
var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
|
|
6276 |
return elem.nodeType === 1 && node && node.nodeValue === match;
|
|
6277 |
};
|
|
6278 |
}
|
|
6279 |
|
|
6280 |
root.removeChild( form );
|
2011be
|
6281 |
root = form = null; // release memory in IE
|
29da64
|
6282 |
})();
|
A |
6283 |
|
|
6284 |
(function(){
|
|
6285 |
// Check to see if the browser returns only elements
|
|
6286 |
// when doing getElementsByTagName("*")
|
|
6287 |
|
|
6288 |
// Create a fake element
|
|
6289 |
var div = document.createElement("div");
|
|
6290 |
div.appendChild( document.createComment("") );
|
|
6291 |
|
|
6292 |
// Make sure no comments are found
|
|
6293 |
if ( div.getElementsByTagName("*").length > 0 ) {
|
|
6294 |
Expr.find.TAG = function(match, context){
|
|
6295 |
var results = context.getElementsByTagName(match[1]);
|
|
6296 |
|
|
6297 |
// Filter out possible comments
|
|
6298 |
if ( match[1] === "*" ) {
|
|
6299 |
var tmp = [];
|
|
6300 |
|
|
6301 |
for ( var i = 0; results[i]; i++ ) {
|
|
6302 |
if ( results[i].nodeType === 1 ) {
|
|
6303 |
tmp.push( results[i] );
|
|
6304 |
}
|
|
6305 |
}
|
|
6306 |
|
|
6307 |
results = tmp;
|
|
6308 |
}
|
|
6309 |
|
|
6310 |
return results;
|
|
6311 |
};
|
|
6312 |
}
|
|
6313 |
|
|
6314 |
// Check to see if an attribute returns normalized href attributes
|
|
6315 |
div.innerHTML = "<a href='#'></a>";
|
|
6316 |
if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
|
|
6317 |
div.firstChild.getAttribute("href") !== "#" ) {
|
|
6318 |
Expr.attrHandle.href = function(elem){
|
|
6319 |
return elem.getAttribute("href", 2);
|
|
6320 |
};
|
|
6321 |
}
|
2011be
|
6322 |
|
A |
6323 |
div = null; // release memory in IE
|
29da64
|
6324 |
})();
|
A |
6325 |
|
2011be
|
6326 |
if ( document.querySelectorAll ) {
|
A |
6327 |
(function(){
|
|
6328 |
var oldSizzle = Sizzle, div = document.createElement("div");
|
|
6329 |
div.innerHTML = "<p class='TEST'></p>";
|
29da64
|
6330 |
|
2011be
|
6331 |
// Safari can't handle uppercase or unicode characters when
|
A |
6332 |
// in quirks mode.
|
|
6333 |
if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
|
|
6334 |
return;
|
29da64
|
6335 |
}
|
2011be
|
6336 |
|
A |
6337 |
Sizzle = function(query, context, extra, seed){
|
|
6338 |
context = context || document;
|
|
6339 |
|
|
6340 |
// Only use querySelectorAll on non-XML documents
|
|
6341 |
// (ID selectors don't work in non-HTML documents)
|
|
6342 |
if ( !seed && context.nodeType === 9 && !Sizzle.isXML(context) ) {
|
|
6343 |
try {
|
|
6344 |
return makeArray( context.querySelectorAll(query), extra );
|
|
6345 |
} catch(e){}
|
|
6346 |
}
|
29da64
|
6347 |
|
2011be
|
6348 |
return oldSizzle(query, context, extra, seed);
|
A |
6349 |
};
|
29da64
|
6350 |
|
2011be
|
6351 |
for ( var prop in oldSizzle ) {
|
A |
6352 |
Sizzle[ prop ] = oldSizzle[ prop ];
|
|
6353 |
}
|
29da64
|
6354 |
|
2011be
|
6355 |
div = null; // release memory in IE
|
A |
6356 |
})();
|
|
6357 |
}
|
|
6358 |
|
|
6359 |
(function(){
|
29da64
|
6360 |
var div = document.createElement("div");
|
2011be
|
6361 |
|
29da64
|
6362 |
div.innerHTML = "<div class='test e'></div><div class='test'></div>";
|
A |
6363 |
|
|
6364 |
// Opera can't find a second classname (in 9.6)
|
2011be
|
6365 |
// Also, make sure that getElementsByClassName actually exists
|
A |
6366 |
if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
|
29da64
|
6367 |
return;
|
2011be
|
6368 |
}
|
29da64
|
6369 |
|
A |
6370 |
// Safari caches class attributes, doesn't catch changes (in 3.2)
|
|
6371 |
div.lastChild.className = "e";
|
|
6372 |
|
2011be
|
6373 |
if ( div.getElementsByClassName("e").length === 1 ) {
|
29da64
|
6374 |
return;
|
2011be
|
6375 |
}
|
A |
6376 |
|
29da64
|
6377 |
Expr.order.splice(1, 0, "CLASS");
|
A |
6378 |
Expr.find.CLASS = function(match, context, isXML) {
|
|
6379 |
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
|
|
6380 |
return context.getElementsByClassName(match[1]);
|
|
6381 |
}
|
|
6382 |
};
|
2011be
|
6383 |
|
A |
6384 |
div = null; // release memory in IE
|
29da64
|
6385 |
})();
|
A |
6386 |
|
|
6387 |
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
|
|
6388 |
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
|
6389 |
var elem = checkSet[i];
|
|
6390 |
if ( elem ) {
|
|
6391 |
elem = elem[dir];
|
|
6392 |
var match = false;
|
|
6393 |
|
|
6394 |
while ( elem ) {
|
|
6395 |
if ( elem.sizcache === doneName ) {
|
|
6396 |
match = checkSet[elem.sizset];
|
|
6397 |
break;
|
|
6398 |
}
|
|
6399 |
|
|
6400 |
if ( elem.nodeType === 1 && !isXML ){
|
|
6401 |
elem.sizcache = doneName;
|
|
6402 |
elem.sizset = i;
|
|
6403 |
}
|
|
6404 |
|
2011be
|
6405 |
if ( elem.nodeName.toLowerCase() === cur ) {
|
29da64
|
6406 |
match = elem;
|
A |
6407 |
break;
|
|
6408 |
}
|
|
6409 |
|
|
6410 |
elem = elem[dir];
|
|
6411 |
}
|
|
6412 |
|
|
6413 |
checkSet[i] = match;
|
|
6414 |
}
|
|
6415 |
}
|
|
6416 |
}
|
|
6417 |
|
|
6418 |
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
|
|
6419 |
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
|
6420 |
var elem = checkSet[i];
|
|
6421 |
if ( elem ) {
|
|
6422 |
elem = elem[dir];
|
|
6423 |
var match = false;
|
|
6424 |
|
|
6425 |
while ( elem ) {
|
|
6426 |
if ( elem.sizcache === doneName ) {
|
|
6427 |
match = checkSet[elem.sizset];
|
|
6428 |
break;
|
|
6429 |
}
|
|
6430 |
|
|
6431 |
if ( elem.nodeType === 1 ) {
|
|
6432 |
if ( !isXML ) {
|
|
6433 |
elem.sizcache = doneName;
|
|
6434 |
elem.sizset = i;
|
|
6435 |
}
|
|
6436 |
if ( typeof cur !== "string" ) {
|
|
6437 |
if ( elem === cur ) {
|
|
6438 |
match = true;
|
|
6439 |
break;
|
|
6440 |
}
|
|
6441 |
|
|
6442 |
} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
|
|
6443 |
match = elem;
|
|
6444 |
break;
|
|
6445 |
}
|
|
6446 |
}
|
|
6447 |
|
|
6448 |
elem = elem[dir];
|
|
6449 |
}
|
|
6450 |
|
|
6451 |
checkSet[i] = match;
|
|
6452 |
}
|
|
6453 |
}
|
|
6454 |
}
|
|
6455 |
|
2011be
|
6456 |
Sizzle.contains = document.compareDocumentPosition ? function(a, b){
|
A |
6457 |
return !!(a.compareDocumentPosition(b) & 16);
|
29da64
|
6458 |
} : function(a, b){
|
A |
6459 |
return a !== b && (a.contains ? a.contains(b) : true);
|
|
6460 |
};
|
|
6461 |
|
2011be
|
6462 |
Sizzle.isXML = function(elem){
|
A |
6463 |
// documentElement is verified for cases where it doesn't yet exist
|
|
6464 |
// (such as loading iframes in IE - #4833)
|
|
6465 |
var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
|
|
6466 |
return documentElement ? documentElement.nodeName !== "HTML" : false;
|
29da64
|
6467 |
};
|
A |
6468 |
|
|
6469 |
var posProcess = function(selector, context){
|
|
6470 |
var tmpSet = [], later = "", match,
|
|
6471 |
root = context.nodeType ? [context] : context;
|
|
6472 |
|
|
6473 |
// Position selectors must be done after the filter
|
|
6474 |
// And so must :not(positional) so we move all PSEUDOs to the end
|
|
6475 |
while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
|
|
6476 |
later += match[0];
|
|
6477 |
selector = selector.replace( Expr.match.PSEUDO, "" );
|
|
6478 |
}
|
|
6479 |
|
|
6480 |
selector = Expr.relative[selector] ? selector + "*" : selector;
|
|
6481 |
|
|
6482 |
for ( var i = 0, l = root.length; i < l; i++ ) {
|
|
6483 |
Sizzle( selector, root[i], tmpSet );
|
|
6484 |
}
|
|
6485 |
|
|
6486 |
return Sizzle.filter( later, tmpSet );
|
|
6487 |
};
|
|
6488 |
|
|
6489 |
// EXPOSE
|
|
6490 |
|
|
6491 |
window.tinymce.dom.Sizzle = Sizzle;
|
|
6492 |
|
|
6493 |
})();
|
|
6494 |
|
69d05c
|
6495 |
|
29da64
|
6496 |
(function(tinymce) {
|
d9344f
|
6497 |
// Shorten names
|
S |
6498 |
var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event;
|
|
6499 |
|
58fb65
|
6500 |
tinymce.create('tinymce.dom.EventUtils', {
|
A |
6501 |
EventUtils : function() {
|
|
6502 |
this.inits = [];
|
|
6503 |
this.events = [];
|
|
6504 |
},
|
d9344f
|
6505 |
|
S |
6506 |
add : function(o, n, f, s) {
|
|
6507 |
var cb, t = this, el = t.events, r;
|
58fb65
|
6508 |
|
A |
6509 |
if (n instanceof Array) {
|
|
6510 |
r = [];
|
|
6511 |
|
|
6512 |
each(n, function(n) {
|
|
6513 |
r.push(t.add(o, n, f, s));
|
|
6514 |
});
|
|
6515 |
|
|
6516 |
return r;
|
|
6517 |
}
|
d9344f
|
6518 |
|
S |
6519 |
// Handle array
|
29da64
|
6520 |
if (o && o.hasOwnProperty && o instanceof Array) {
|
d9344f
|
6521 |
r = [];
|
S |
6522 |
|
|
6523 |
each(o, function(o) {
|
|
6524 |
o = DOM.get(o);
|
|
6525 |
r.push(t.add(o, n, f, s));
|
|
6526 |
});
|
|
6527 |
|
|
6528 |
return r;
|
|
6529 |
}
|
|
6530 |
|
|
6531 |
o = DOM.get(o);
|
|
6532 |
|
|
6533 |
if (!o)
|
|
6534 |
return;
|
|
6535 |
|
|
6536 |
// Setup event callback
|
|
6537 |
cb = function(e) {
|
58fb65
|
6538 |
// Is all events disabled
|
A |
6539 |
if (t.disabled)
|
|
6540 |
return;
|
|
6541 |
|
d9344f
|
6542 |
e = e || window.event;
|
S |
6543 |
|
58fb65
|
6544 |
// Patch in target, preventDefault and stopPropagation in IE it's W3C valid
|
A |
6545 |
if (e && isIE) {
|
|
6546 |
if (!e.target)
|
|
6547 |
e.target = e.srcElement;
|
|
6548 |
|
|
6549 |
// Patch in preventDefault, stopPropagation methods for W3C compatibility
|
|
6550 |
tinymce.extend(e, t._stoppers);
|
|
6551 |
}
|
d9344f
|
6552 |
|
S |
6553 |
if (!s)
|
|
6554 |
return f(e);
|
|
6555 |
|
|
6556 |
return f.call(s, e);
|
|
6557 |
};
|
|
6558 |
|
|
6559 |
if (n == 'unload') {
|
|
6560 |
tinymce.unloads.unshift({func : cb});
|
|
6561 |
return cb;
|
|
6562 |
}
|
|
6563 |
|
|
6564 |
if (n == 'init') {
|
|
6565 |
if (t.domLoaded)
|
|
6566 |
cb();
|
|
6567 |
else
|
|
6568 |
t.inits.push(cb);
|
|
6569 |
|
|
6570 |
return cb;
|
|
6571 |
}
|
|
6572 |
|
|
6573 |
// Store away listener reference
|
|
6574 |
el.push({
|
|
6575 |
obj : o,
|
|
6576 |
name : n,
|
|
6577 |
func : f,
|
|
6578 |
cfunc : cb,
|
|
6579 |
scope : s
|
|
6580 |
});
|
|
6581 |
|
|
6582 |
t._add(o, n, cb);
|
|
6583 |
|
|
6584 |
return f;
|
|
6585 |
},
|
|
6586 |
|
|
6587 |
remove : function(o, n, f) {
|
|
6588 |
var t = this, a = t.events, s = false, r;
|
|
6589 |
|
|
6590 |
// Handle array
|
29da64
|
6591 |
if (o && o.hasOwnProperty && o instanceof Array) {
|
d9344f
|
6592 |
r = [];
|
S |
6593 |
|
|
6594 |
each(o, function(o) {
|
|
6595 |
o = DOM.get(o);
|
|
6596 |
r.push(t.remove(o, n, f));
|
|
6597 |
});
|
|
6598 |
|
|
6599 |
return r;
|
|
6600 |
}
|
|
6601 |
|
|
6602 |
o = DOM.get(o);
|
|
6603 |
|
|
6604 |
each(a, function(e, i) {
|
|
6605 |
if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) {
|
|
6606 |
a.splice(i, 1);
|
|
6607 |
t._remove(o, n, e.cfunc);
|
|
6608 |
s = true;
|
|
6609 |
return false;
|
|
6610 |
}
|
|
6611 |
});
|
|
6612 |
|
|
6613 |
return s;
|
|
6614 |
},
|
|
6615 |
|
|
6616 |
clear : function(o) {
|
|
6617 |
var t = this, a = t.events, i, e;
|
|
6618 |
|
|
6619 |
if (o) {
|
|
6620 |
o = DOM.get(o);
|
|
6621 |
|
|
6622 |
for (i = a.length - 1; i >= 0; i--) {
|
|
6623 |
e = a[i];
|
|
6624 |
|
|
6625 |
if (e.obj === o) {
|
|
6626 |
t._remove(e.obj, e.name, e.cfunc);
|
|
6627 |
e.obj = e.cfunc = null;
|
|
6628 |
a.splice(i, 1);
|
|
6629 |
}
|
|
6630 |
}
|
|
6631 |
}
|
|
6632 |
},
|
|
6633 |
|
|
6634 |
cancel : function(e) {
|
|
6635 |
if (!e)
|
|
6636 |
return false;
|
|
6637 |
|
|
6638 |
this.stop(e);
|
58fb65
|
6639 |
|
d9344f
|
6640 |
return this.prevent(e);
|
S |
6641 |
},
|
|
6642 |
|
|
6643 |
stop : function(e) {
|
|
6644 |
if (e.stopPropagation)
|
|
6645 |
e.stopPropagation();
|
|
6646 |
else
|
|
6647 |
e.cancelBubble = true;
|
|
6648 |
|
|
6649 |
return false;
|
|
6650 |
},
|
|
6651 |
|
|
6652 |
prevent : function(e) {
|
|
6653 |
if (e.preventDefault)
|
|
6654 |
e.preventDefault();
|
|
6655 |
else
|
|
6656 |
e.returnValue = false;
|
|
6657 |
|
|
6658 |
return false;
|
|
6659 |
},
|
|
6660 |
|
58fb65
|
6661 |
destroy : function() {
|
A |
6662 |
var t = this;
|
d9344f
|
6663 |
|
S |
6664 |
each(t.events, function(e, i) {
|
|
6665 |
t._remove(e.obj, e.name, e.cfunc);
|
|
6666 |
e.obj = e.cfunc = null;
|
|
6667 |
});
|
|
6668 |
|
|
6669 |
t.events = [];
|
|
6670 |
t = null;
|
|
6671 |
},
|
|
6672 |
|
|
6673 |
_add : function(o, n, f) {
|
|
6674 |
if (o.attachEvent)
|
|
6675 |
o.attachEvent('on' + n, f);
|
|
6676 |
else if (o.addEventListener)
|
|
6677 |
o.addEventListener(n, f, false);
|
|
6678 |
else
|
|
6679 |
o['on' + n] = f;
|
|
6680 |
},
|
|
6681 |
|
|
6682 |
_remove : function(o, n, f) {
|
|
6683 |
if (o) {
|
|
6684 |
try {
|
|
6685 |
if (o.detachEvent)
|
|
6686 |
o.detachEvent('on' + n, f);
|
|
6687 |
else if (o.removeEventListener)
|
|
6688 |
o.removeEventListener(n, f, false);
|
|
6689 |
else
|
|
6690 |
o['on' + n] = null;
|
|
6691 |
} catch (ex) {
|
|
6692 |
// Might fail with permission denined on IE so we just ignore that
|
|
6693 |
}
|
|
6694 |
}
|
|
6695 |
},
|
|
6696 |
|
58fb65
|
6697 |
_pageInit : function(win) {
|
A |
6698 |
var t = this;
|
d9344f
|
6699 |
|
29da64
|
6700 |
// Keep it from running more than once
|
58fb65
|
6701 |
if (t.domLoaded)
|
29da64
|
6702 |
return;
|
A |
6703 |
|
58fb65
|
6704 |
t.domLoaded = true;
|
d9344f
|
6705 |
|
58fb65
|
6706 |
each(t.inits, function(c) {
|
d9344f
|
6707 |
c();
|
S |
6708 |
});
|
|
6709 |
|
58fb65
|
6710 |
t.inits = [];
|
d9344f
|
6711 |
},
|
S |
6712 |
|
58fb65
|
6713 |
_wait : function(win) {
|
A |
6714 |
var t = this, doc = win.document;
|
|
6715 |
|
d9344f
|
6716 |
// No need since the document is already loaded
|
58fb65
|
6717 |
if (win.tinyMCE_GZ && tinyMCE_GZ.loaded) {
|
A |
6718 |
t.domLoaded = 1;
|
d9344f
|
6719 |
return;
|
18240a
|
6720 |
}
|
d9344f
|
6721 |
|
29da64
|
6722 |
// Use IE method
|
58fb65
|
6723 |
if (doc.attachEvent) {
|
A |
6724 |
doc.attachEvent("onreadystatechange", function() {
|
|
6725 |
if (doc.readyState === "complete") {
|
|
6726 |
doc.detachEvent("onreadystatechange", arguments.callee);
|
|
6727 |
t._pageInit(win);
|
d9344f
|
6728 |
}
|
29da64
|
6729 |
});
|
A |
6730 |
|
58fb65
|
6731 |
if (doc.documentElement.doScroll && win == win.top) {
|
29da64
|
6732 |
(function() {
|
58fb65
|
6733 |
if (t.domLoaded)
|
29da64
|
6734 |
return;
|
A |
6735 |
|
|
6736 |
try {
|
|
6737 |
// If IE is used, use the trick by Diego Perini
|
|
6738 |
// http://javascript.nwbox.com/IEContentLoaded/
|
58fb65
|
6739 |
doc.documentElement.doScroll("left");
|
29da64
|
6740 |
} catch (ex) {
|
A |
6741 |
setTimeout(arguments.callee, 0);
|
|
6742 |
return;
|
|
6743 |
}
|
|
6744 |
|
58fb65
|
6745 |
t._pageInit(win);
|
29da64
|
6746 |
})();
|
A |
6747 |
}
|
58fb65
|
6748 |
} else if (doc.addEventListener) {
|
A |
6749 |
t._add(win, 'DOMContentLoaded', function() {
|
|
6750 |
t._pageInit(win);
|
|
6751 |
});
|
|
6752 |
}
|
d9344f
|
6753 |
|
58fb65
|
6754 |
t._add(win, 'load', function() {
|
A |
6755 |
t._pageInit(win);
|
|
6756 |
});
|
|
6757 |
},
|
|
6758 |
|
|
6759 |
_stoppers : {
|
a9251b
|
6760 |
preventDefault : function() {
|
58fb65
|
6761 |
this.returnValue = false;
|
A |
6762 |
},
|
|
6763 |
|
|
6764 |
stopPropagation : function() {
|
|
6765 |
this.cancelBubble = true;
|
|
6766 |
}
|
d9344f
|
6767 |
}
|
58fb65
|
6768 |
});
|
d9344f
|
6769 |
|
58fb65
|
6770 |
Event = tinymce.dom.Event = new tinymce.dom.EventUtils();
|
d9344f
|
6771 |
|
S |
6772 |
// Dispatch DOM content loaded event for IE and Safari
|
58fb65
|
6773 |
Event._wait(window);
|
A |
6774 |
|
|
6775 |
tinymce.addUnload(function() {
|
|
6776 |
Event.destroy();
|
|
6777 |
});
|
29da64
|
6778 |
})(tinymce);
|
69d05c
|
6779 |
|
29da64
|
6780 |
(function(tinymce) {
|
69d05c
|
6781 |
tinymce.dom.Element = function(id, settings) {
|
A |
6782 |
var t = this, dom, el;
|
d9344f
|
6783 |
|
69d05c
|
6784 |
t.settings = settings = settings || {};
|
A |
6785 |
t.id = id;
|
|
6786 |
t.dom = dom = settings.dom || tinymce.DOM;
|
d9344f
|
6787 |
|
69d05c
|
6788 |
// Only IE leaks DOM references, this is a lot faster
|
A |
6789 |
if (!tinymce.isIE)
|
|
6790 |
el = dom.get(t.id);
|
d9344f
|
6791 |
|
69d05c
|
6792 |
tinymce.each(
|
A |
6793 |
('getPos,getRect,getParent,add,setStyle,getStyle,setStyles,' +
|
|
6794 |
'setAttrib,setAttribs,getAttrib,addClass,removeClass,' +
|
|
6795 |
'hasClass,getOuterHTML,setOuterHTML,remove,show,hide,' +
|
|
6796 |
'isHidden,setHTML,get').split(/,/)
|
|
6797 |
, function(k) {
|
d9344f
|
6798 |
t[k] = function() {
|
29da64
|
6799 |
var a = [id], i;
|
d9344f
|
6800 |
|
29da64
|
6801 |
for (i = 0; i < arguments.length; i++)
|
A |
6802 |
a.push(arguments[i]);
|
d9344f
|
6803 |
|
29da64
|
6804 |
a = dom[k].apply(dom, a);
|
d9344f
|
6805 |
t.update(k);
|
S |
6806 |
|
29da64
|
6807 |
return a;
|
d9344f
|
6808 |
};
|
69d05c
|
6809 |
});
|
d9344f
|
6810 |
|
69d05c
|
6811 |
tinymce.extend(t, {
|
A |
6812 |
on : function(n, f, s) {
|
|
6813 |
return tinymce.dom.Event.add(t.id, n, f, s);
|
|
6814 |
},
|
d9344f
|
6815 |
|
69d05c
|
6816 |
getXY : function() {
|
A |
6817 |
return {
|
|
6818 |
x : parseInt(t.getStyle('left')),
|
|
6819 |
y : parseInt(t.getStyle('top'))
|
|
6820 |
};
|
|
6821 |
},
|
d9344f
|
6822 |
|
69d05c
|
6823 |
getSize : function() {
|
A |
6824 |
var n = dom.get(t.id);
|
d9344f
|
6825 |
|
69d05c
|
6826 |
return {
|
A |
6827 |
w : parseInt(t.getStyle('width') || n.clientWidth),
|
|
6828 |
h : parseInt(t.getStyle('height') || n.clientHeight)
|
|
6829 |
};
|
|
6830 |
},
|
d9344f
|
6831 |
|
69d05c
|
6832 |
moveTo : function(x, y) {
|
A |
6833 |
t.setStyles({left : x, top : y});
|
|
6834 |
},
|
d9344f
|
6835 |
|
69d05c
|
6836 |
moveBy : function(x, y) {
|
A |
6837 |
var p = t.getXY();
|
d9344f
|
6838 |
|
69d05c
|
6839 |
t.moveTo(p.x + x, p.y + y);
|
A |
6840 |
},
|
d9344f
|
6841 |
|
69d05c
|
6842 |
resizeTo : function(w, h) {
|
A |
6843 |
t.setStyles({width : w, height : h});
|
|
6844 |
},
|
d9344f
|
6845 |
|
69d05c
|
6846 |
resizeBy : function(w, h) {
|
A |
6847 |
var s = t.getSize();
|
d9344f
|
6848 |
|
69d05c
|
6849 |
t.resizeTo(s.w + w, s.h + h);
|
A |
6850 |
},
|
d9344f
|
6851 |
|
69d05c
|
6852 |
update : function(k) {
|
A |
6853 |
var b;
|
d9344f
|
6854 |
|
69d05c
|
6855 |
if (tinymce.isIE6 && settings.blocker) {
|
A |
6856 |
k = k || '';
|
d9344f
|
6857 |
|
69d05c
|
6858 |
// Ignore getters
|
A |
6859 |
if (k.indexOf('get') === 0 || k.indexOf('has') === 0 || k.indexOf('is') === 0)
|
|
6860 |
return;
|
d9344f
|
6861 |
|
69d05c
|
6862 |
// Remove blocker on remove
|
A |
6863 |
if (k == 'remove') {
|
|
6864 |
dom.remove(t.blocker);
|
|
6865 |
return;
|
|
6866 |
}
|
|
6867 |
|
|
6868 |
if (!t.blocker) {
|
|
6869 |
t.blocker = dom.uniqueId();
|
|
6870 |
b = dom.add(settings.container || dom.getRoot(), 'iframe', {id : t.blocker, style : 'position:absolute;', frameBorder : 0, src : 'javascript:""'});
|
|
6871 |
dom.setStyle(b, 'opacity', 0);
|
|
6872 |
} else
|
|
6873 |
b = dom.get(t.blocker);
|
|
6874 |
|
|
6875 |
dom.setStyles(b, {
|
|
6876 |
left : t.getStyle('left', 1),
|
|
6877 |
top : t.getStyle('top', 1),
|
|
6878 |
width : t.getStyle('width', 1),
|
|
6879 |
height : t.getStyle('height', 1),
|
|
6880 |
display : t.getStyle('display', 1),
|
|
6881 |
zIndex : parseInt(t.getStyle('zIndex', 1) || 0) - 1
|
|
6882 |
});
|
d9344f
|
6883 |
}
|
S |
6884 |
}
|
69d05c
|
6885 |
});
|
A |
6886 |
};
|
29da64
|
6887 |
})(tinymce);
|
69d05c
|
6888 |
|
29da64
|
6889 |
(function(tinymce) {
|
18240a
|
6890 |
function trimNl(s) {
|
A |
6891 |
return s.replace(/[\n\r]+/g, '');
|
|
6892 |
};
|
|
6893 |
|
d9344f
|
6894 |
// Shorten names
|
S |
6895 |
var is = tinymce.is, isIE = tinymce.isIE, each = tinymce.each;
|
|
6896 |
|
|
6897 |
tinymce.create('tinymce.dom.Selection', {
|
|
6898 |
Selection : function(dom, win, serializer) {
|
|
6899 |
var t = this;
|
|
6900 |
|
|
6901 |
t.dom = dom;
|
|
6902 |
t.win = win;
|
|
6903 |
t.serializer = serializer;
|
|
6904 |
|
29da64
|
6905 |
// Add events
|
A |
6906 |
each([
|
|
6907 |
'onBeforeSetContent',
|
a9251b
|
6908 |
|
29da64
|
6909 |
'onBeforeGetContent',
|
a9251b
|
6910 |
|
29da64
|
6911 |
'onSetContent',
|
a9251b
|
6912 |
|
29da64
|
6913 |
'onGetContent'
|
A |
6914 |
], function(e) {
|
|
6915 |
t[e] = new tinymce.util.Dispatcher(t);
|
|
6916 |
});
|
|
6917 |
|
|
6918 |
// No W3C Range support
|
|
6919 |
if (!t.win.getSelection)
|
|
6920 |
t.tridentSel = new tinymce.dom.TridentSelection(t);
|
a9251b
|
6921 |
|
T |
6922 |
if (tinymce.isIE && dom.boxModel)
|
|
6923 |
this._fixIESelection();
|
29da64
|
6924 |
|
d9344f
|
6925 |
// Prevent leaks
|
S |
6926 |
tinymce.addUnload(t.destroy, t);
|
|
6927 |
},
|
|
6928 |
|
|
6929 |
getContent : function(s) {
|
|
6930 |
var t = this, r = t.getRng(), e = t.dom.create("body"), se = t.getSel(), wb, wa, n;
|
|
6931 |
|
|
6932 |
s = s || {};
|
|
6933 |
wb = wa = '';
|
|
6934 |
s.get = true;
|
|
6935 |
s.format = s.format || 'html';
|
29da64
|
6936 |
t.onBeforeGetContent.dispatch(t, s);
|
d9344f
|
6937 |
|
S |
6938 |
if (s.format == 'text')
|
|
6939 |
return t.isCollapsed() ? '' : (r.text || (se.toString ? se.toString() : ''));
|
|
6940 |
|
|
6941 |
if (r.cloneContents) {
|
|
6942 |
n = r.cloneContents();
|
|
6943 |
|
|
6944 |
if (n)
|
|
6945 |
e.appendChild(n);
|
|
6946 |
} else if (is(r.item) || is(r.htmlText))
|
|
6947 |
e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText;
|
|
6948 |
else
|
|
6949 |
e.innerHTML = r.toString();
|
|
6950 |
|
|
6951 |
// Keep whitespace before and after
|
|
6952 |
if (/^\s/.test(e.innerHTML))
|
|
6953 |
wb = ' ';
|
|
6954 |
|
|
6955 |
if (/\s+$/.test(e.innerHTML))
|
|
6956 |
wa = ' ';
|
|
6957 |
|
|
6958 |
s.getInner = true;
|
|
6959 |
|
29da64
|
6960 |
s.content = t.isCollapsed() ? '' : wb + t.serializer.serialize(e, s) + wa;
|
A |
6961 |
t.onGetContent.dispatch(t, s);
|
|
6962 |
|
|
6963 |
return s.content;
|
d9344f
|
6964 |
},
|
S |
6965 |
|
a9251b
|
6966 |
setContent : function(content, args) {
|
T |
6967 |
var self = this, rng = self.getRng(), caretNode, doc = self.win.document, frag, temp;
|
d9344f
|
6968 |
|
a9251b
|
6969 |
args = args || {format : 'html'};
|
T |
6970 |
args.set = true;
|
|
6971 |
content = args.content = content;
|
29da64
|
6972 |
|
A |
6973 |
// Dispatch before set content event
|
a9251b
|
6974 |
if (!args.no_events)
|
T |
6975 |
self.onBeforeSetContent.dispatch(self, args);
|
d9344f
|
6976 |
|
a9251b
|
6977 |
content = args.content;
|
T |
6978 |
|
|
6979 |
if (rng.insertNode) {
|
29da64
|
6980 |
// Make caret marker since insertNode places the caret in the beginning of text after insert
|
a9251b
|
6981 |
content += '<span id="__caret">_</span>';
|
d9344f
|
6982 |
|
29da64
|
6983 |
// Delete and insert new node
|
a9251b
|
6984 |
if (rng.startContainer == doc && rng.endContainer == doc) {
|
69d05c
|
6985 |
// WebKit will fail if the body is empty since the range is then invalid and it can't insert contents
|
a9251b
|
6986 |
doc.body.innerHTML = content;
|
69d05c
|
6987 |
} else {
|
a9251b
|
6988 |
rng.deleteContents();
|
T |
6989 |
|
|
6990 |
if (doc.body.childNodes.length == 0) {
|
|
6991 |
doc.body.innerHTML = content;
|
2011be
|
6992 |
} else {
|
a9251b
|
6993 |
// createContextualFragment doesn't exists in IE 9 DOMRanges
|
T |
6994 |
if (rng.createContextualFragment) {
|
|
6995 |
rng.insertNode(rng.createContextualFragment(content));
|
|
6996 |
} else {
|
|
6997 |
// Fake createContextualFragment call in IE 9
|
|
6998 |
frag = doc.createDocumentFragment();
|
|
6999 |
temp = doc.createElement('div');
|
|
7000 |
|
|
7001 |
frag.appendChild(temp);
|
|
7002 |
temp.outerHTML = content;
|
|
7003 |
|
|
7004 |
rng.insertNode(frag);
|
|
7005 |
}
|
2011be
|
7006 |
}
|
69d05c
|
7007 |
}
|
29da64
|
7008 |
|
A |
7009 |
// Move to caret marker
|
a9251b
|
7010 |
caretNode = self.dom.get('__caret');
|
T |
7011 |
|
29da64
|
7012 |
// Make sure we wrap it compleatly, Opera fails with a simple select call
|
a9251b
|
7013 |
rng = doc.createRange();
|
T |
7014 |
rng.setStartBefore(caretNode);
|
|
7015 |
rng.setEndBefore(caretNode);
|
|
7016 |
self.setRng(rng);
|
29da64
|
7017 |
|
A |
7018 |
// Remove the caret position
|
a9251b
|
7019 |
self.dom.remove('__caret');
|
T |
7020 |
self.setRng(rng);
|
d9344f
|
7021 |
} else {
|
a9251b
|
7022 |
if (rng.item) {
|
18240a
|
7023 |
// Delete content and get caret text selection
|
a9251b
|
7024 |
doc.execCommand('Delete', false, null);
|
T |
7025 |
rng = self.getRng();
|
18240a
|
7026 |
}
|
A |
7027 |
|
a9251b
|
7028 |
rng.pasteHTML(content);
|
d9344f
|
7029 |
}
|
29da64
|
7030 |
|
A |
7031 |
// Dispatch set content event
|
a9251b
|
7032 |
if (!args.no_events)
|
T |
7033 |
self.onSetContent.dispatch(self, args);
|
d9344f
|
7034 |
},
|
S |
7035 |
|
|
7036 |
getStart : function() {
|
2011be
|
7037 |
var rng = this.getRng(), startElement, parentElement, checkRng, node;
|
d9344f
|
7038 |
|
2011be
|
7039 |
if (rng.duplicate || rng.item) {
|
A |
7040 |
// Control selection, return first item
|
|
7041 |
if (rng.item)
|
|
7042 |
return rng.item(0);
|
d9344f
|
7043 |
|
2011be
|
7044 |
// Get start element
|
A |
7045 |
checkRng = rng.duplicate();
|
|
7046 |
checkRng.collapse(1);
|
|
7047 |
startElement = checkRng.parentElement();
|
d9344f
|
7048 |
|
2011be
|
7049 |
// Check if range parent is inside the start element, then return the inner parent element
|
A |
7050 |
// This will fix issues when a single element is selected, IE would otherwise return the wrong start element
|
|
7051 |
parentElement = node = rng.parentElement();
|
|
7052 |
while (node = node.parentNode) {
|
|
7053 |
if (node == startElement) {
|
|
7054 |
startElement = parentElement;
|
|
7055 |
break;
|
|
7056 |
}
|
|
7057 |
}
|
|
7058 |
|
|
7059 |
return startElement;
|
d9344f
|
7060 |
} else {
|
2011be
|
7061 |
startElement = rng.startContainer;
|
d9344f
|
7062 |
|
2011be
|
7063 |
if (startElement.nodeType == 1 && startElement.hasChildNodes())
|
A |
7064 |
startElement = startElement.childNodes[Math.min(startElement.childNodes.length - 1, rng.startOffset)];
|
d9344f
|
7065 |
|
2011be
|
7066 |
if (startElement && startElement.nodeType == 3)
|
A |
7067 |
return startElement.parentNode;
|
69d05c
|
7068 |
|
2011be
|
7069 |
return startElement;
|
d9344f
|
7070 |
}
|
S |
7071 |
},
|
|
7072 |
|
|
7073 |
getEnd : function() {
|
69d05c
|
7074 |
var t = this, r = t.getRng(), e, eo;
|
d9344f
|
7075 |
|
799907
|
7076 |
if (r.duplicate || r.item) {
|
d9344f
|
7077 |
if (r.item)
|
S |
7078 |
return r.item(0);
|
|
7079 |
|
|
7080 |
r = r.duplicate();
|
|
7081 |
r.collapse(0);
|
|
7082 |
e = r.parentElement();
|
|
7083 |
|
18240a
|
7084 |
if (e && e.nodeName == 'BODY')
|
69d05c
|
7085 |
return e.lastChild || e;
|
d9344f
|
7086 |
|
S |
7087 |
return e;
|
|
7088 |
} else {
|
|
7089 |
e = r.endContainer;
|
69d05c
|
7090 |
eo = r.endOffset;
|
d9344f
|
7091 |
|
69d05c
|
7092 |
if (e.nodeType == 1 && e.hasChildNodes())
|
A |
7093 |
e = e.childNodes[eo > 0 ? eo - 1 : eo];
|
d9344f
|
7094 |
|
69d05c
|
7095 |
if (e && e.nodeType == 3)
|
A |
7096 |
return e.parentNode;
|
|
7097 |
|
|
7098 |
return e;
|
d9344f
|
7099 |
}
|
S |
7100 |
},
|
|
7101 |
|
69d05c
|
7102 |
getBookmark : function(type, normalized) {
|
A |
7103 |
var t = this, dom = t.dom, rng, rng2, id, collapsed, name, element, index, chr = '\uFEFF', styles;
|
d9344f
|
7104 |
|
69d05c
|
7105 |
function findIndex(name, element) {
|
A |
7106 |
var index = 0;
|
d9344f
|
7107 |
|
69d05c
|
7108 |
each(dom.select(name), function(node, i) {
|
A |
7109 |
if (node == element)
|
|
7110 |
index = i;
|
|
7111 |
});
|
d9344f
|
7112 |
|
69d05c
|
7113 |
return index;
|
A |
7114 |
};
|
|
7115 |
|
|
7116 |
if (type == 2) {
|
|
7117 |
function getLocation() {
|
|
7118 |
var rng = t.getRng(true), root = dom.getRoot(), bookmark = {};
|
|
7119 |
|
|
7120 |
function getPoint(rng, start) {
|
|
7121 |
var container = rng[start ? 'startContainer' : 'endContainer'],
|
799907
|
7122 |
offset = rng[start ? 'startOffset' : 'endOffset'], point = [], node, childNodes, after = 0;
|
69d05c
|
7123 |
|
A |
7124 |
if (container.nodeType == 3) {
|
|
7125 |
if (normalized) {
|
|
7126 |
for (node = container.previousSibling; node && node.nodeType == 3; node = node.previousSibling)
|
|
7127 |
offset += node.nodeValue.length;
|
|
7128 |
}
|
|
7129 |
|
|
7130 |
point.push(offset);
|
|
7131 |
} else {
|
|
7132 |
childNodes = container.childNodes;
|
2011be
|
7133 |
|
A |
7134 |
if (offset >= childNodes.length && childNodes.length) {
|
69d05c
|
7135 |
after = 1;
|
2011be
|
7136 |
offset = Math.max(0, childNodes.length - 1);
|
69d05c
|
7137 |
}
|
A |
7138 |
|
|
7139 |
point.push(t.dom.nodeIndex(childNodes[offset], normalized) + after);
|
d9344f
|
7140 |
}
|
S |
7141 |
|
69d05c
|
7142 |
for (; container && container != root; container = container.parentNode)
|
A |
7143 |
point.push(t.dom.nodeIndex(container, normalized));
|
|
7144 |
|
|
7145 |
return point;
|
d9344f
|
7146 |
};
|
S |
7147 |
|
69d05c
|
7148 |
bookmark.start = getPoint(rng, true);
|
A |
7149 |
|
|
7150 |
if (!t.isCollapsed())
|
|
7151 |
bookmark.end = getPoint(rng);
|
|
7152 |
|
|
7153 |
return bookmark;
|
|
7154 |
};
|
|
7155 |
|
|
7156 |
return getLocation();
|
|
7157 |
}
|
|
7158 |
|
|
7159 |
// Handle simple range
|
|
7160 |
if (type)
|
|
7161 |
return {rng : t.getRng()};
|
|
7162 |
|
|
7163 |
rng = t.getRng();
|
|
7164 |
id = dom.uniqueId();
|
|
7165 |
collapsed = tinyMCE.activeEditor.selection.isCollapsed();
|
|
7166 |
styles = 'overflow:hidden;line-height:0px';
|
|
7167 |
|
|
7168 |
// Explorer method
|
|
7169 |
if (rng.duplicate || rng.item) {
|
d9344f
|
7170 |
// Text selection
|
69d05c
|
7171 |
if (!rng.item) {
|
A |
7172 |
rng2 = rng.duplicate();
|
d9344f
|
7173 |
|
a9251b
|
7174 |
try {
|
T |
7175 |
// Insert start marker
|
|
7176 |
rng.collapse();
|
|
7177 |
rng.pasteHTML('<span data-mce-type="bookmark" id="' + id + '_start" style="' + styles + '">' + chr + '</span>');
|
d9344f
|
7178 |
|
a9251b
|
7179 |
// Insert end marker
|
T |
7180 |
if (!collapsed) {
|
|
7181 |
rng2.collapse(false);
|
|
7182 |
|
|
7183 |
// Detect the empty space after block elements in IE and move the end back one character <p></p>] becomes <p>]</p>
|
|
7184 |
rng.moveToElementText(rng2.parentElement());
|
|
7185 |
if (rng.compareEndPoints('StartToEnd', rng2) == 0)
|
|
7186 |
rng2.move('character', -1);
|
|
7187 |
|
|
7188 |
rng2.pasteHTML('<span data-mce-type="bookmark" id="' + id + '_end" style="' + styles + '">' + chr + '</span>');
|
|
7189 |
}
|
|
7190 |
} catch (ex) {
|
|
7191 |
// IE might throw unspecified error so lets ignore it
|
|
7192 |
return null;
|
d9344f
|
7193 |
}
|
69d05c
|
7194 |
} else {
|
A |
7195 |
// Control selection
|
|
7196 |
element = rng.item(0);
|
|
7197 |
name = element.nodeName;
|
d9344f
|
7198 |
|
69d05c
|
7199 |
return {name : name, index : findIndex(name, element)};
|
A |
7200 |
}
|
|
7201 |
} else {
|
|
7202 |
element = t.getNode();
|
|
7203 |
name = element.nodeName;
|
|
7204 |
if (name == 'IMG')
|
|
7205 |
return {name : name, index : findIndex(name, element)};
|
|
7206 |
|
|
7207 |
// W3C method
|
|
7208 |
rng2 = rng.cloneRange();
|
|
7209 |
|
|
7210 |
// Insert end marker
|
|
7211 |
if (!collapsed) {
|
|
7212 |
rng2.collapse(false);
|
a9251b
|
7213 |
rng2.insertNode(dom.create('span', {'data-mce-type' : "bookmark", id : id + '_end', style : styles}, chr));
|
d9344f
|
7214 |
}
|
S |
7215 |
|
69d05c
|
7216 |
rng.collapse(true);
|
a9251b
|
7217 |
rng.insertNode(dom.create('span', {'data-mce-type' : "bookmark", id : id + '_start', style : styles}, chr));
|
d9344f
|
7218 |
}
|
69d05c
|
7219 |
|
A |
7220 |
t.moveToBookmark({id : id, keep : 1});
|
|
7221 |
|
|
7222 |
return {id : id};
|
d9344f
|
7223 |
},
|
S |
7224 |
|
69d05c
|
7225 |
moveToBookmark : function(bookmark) {
|
2011be
|
7226 |
var t = this, dom = t.dom, marker1, marker2, rng, root, startContainer, endContainer, startOffset, endOffset;
|
d9344f
|
7227 |
|
69d05c
|
7228 |
// Clear selection cache
|
A |
7229 |
if (t.tridentSel)
|
58fb65
|
7230 |
t.tridentSel.destroy();
|
A |
7231 |
|
69d05c
|
7232 |
if (bookmark) {
|
A |
7233 |
if (bookmark.start) {
|
|
7234 |
rng = dom.createRng();
|
|
7235 |
root = dom.getRoot();
|
d9344f
|
7236 |
|
69d05c
|
7237 |
function setEndPoint(start) {
|
2011be
|
7238 |
var point = bookmark[start ? 'start' : 'end'], i, node, offset, children;
|
d9344f
|
7239 |
|
69d05c
|
7240 |
if (point) {
|
a9251b
|
7241 |
offset = point[0];
|
T |
7242 |
|
69d05c
|
7243 |
// Find container node
|
2011be
|
7244 |
for (node = root, i = point.length - 1; i >= 1; i--) {
|
A |
7245 |
children = node.childNodes;
|
|
7246 |
|
a9251b
|
7247 |
if (point[i] > children.length - 1)
|
T |
7248 |
return;
|
|
7249 |
|
|
7250 |
node = children[point[i]];
|
2011be
|
7251 |
}
|
a9251b
|
7252 |
|
T |
7253 |
// Move text offset to best suitable location
|
|
7254 |
if (node.nodeType === 3)
|
|
7255 |
offset = Math.min(point[0], node.nodeValue.length);
|
|
7256 |
|
|
7257 |
// Move element offset to best suitable location
|
|
7258 |
if (node.nodeType === 1)
|
|
7259 |
offset = Math.min(point[0], node.childNodes.length);
|
d9344f
|
7260 |
|
69d05c
|
7261 |
// Set offset within container node
|
A |
7262 |
if (start)
|
a9251b
|
7263 |
rng.setStart(node, offset);
|
69d05c
|
7264 |
else
|
a9251b
|
7265 |
rng.setEnd(node, offset);
|
d9344f
|
7266 |
}
|
a9251b
|
7267 |
|
T |
7268 |
return true;
|
69d05c
|
7269 |
};
|
d9344f
|
7270 |
|
a9251b
|
7271 |
if (setEndPoint(true) && setEndPoint()) {
|
T |
7272 |
t.setRng(rng);
|
|
7273 |
}
|
69d05c
|
7274 |
} else if (bookmark.id) {
|
A |
7275 |
function restoreEndPoint(suffix) {
|
|
7276 |
var marker = dom.get(bookmark.id + '_' + suffix), node, idx, next, prev, keep = bookmark.keep;
|
|
7277 |
|
|
7278 |
if (marker) {
|
|
7279 |
node = marker.parentNode;
|
|
7280 |
|
|
7281 |
if (suffix == 'start') {
|
|
7282 |
if (!keep) {
|
|
7283 |
idx = dom.nodeIndex(marker);
|
|
7284 |
} else {
|
2011be
|
7285 |
node = marker.firstChild;
|
69d05c
|
7286 |
idx = 1;
|
A |
7287 |
}
|
|
7288 |
|
2011be
|
7289 |
startContainer = endContainer = node;
|
A |
7290 |
startOffset = endOffset = idx;
|
69d05c
|
7291 |
} else {
|
A |
7292 |
if (!keep) {
|
|
7293 |
idx = dom.nodeIndex(marker);
|
|
7294 |
} else {
|
2011be
|
7295 |
node = marker.firstChild;
|
69d05c
|
7296 |
idx = 1;
|
A |
7297 |
}
|
|
7298 |
|
2011be
|
7299 |
endContainer = node;
|
A |
7300 |
endOffset = idx;
|
69d05c
|
7301 |
}
|
A |
7302 |
|
|
7303 |
if (!keep) {
|
|
7304 |
prev = marker.previousSibling;
|
|
7305 |
next = marker.nextSibling;
|
|
7306 |
|
|
7307 |
// Remove all marker text nodes
|
|
7308 |
each(tinymce.grep(marker.childNodes), function(node) {
|
|
7309 |
if (node.nodeType == 3)
|
|
7310 |
node.nodeValue = node.nodeValue.replace(/\uFEFF/g, '');
|
|
7311 |
});
|
|
7312 |
|
|
7313 |
// Remove marker but keep children if for example contents where inserted into the marker
|
|
7314 |
// Also remove duplicated instances of the marker for example by a split operation or by WebKit auto split on paste feature
|
|
7315 |
while (marker = dom.get(bookmark.id + '_' + suffix))
|
|
7316 |
dom.remove(marker, 1);
|
|
7317 |
|
a9251b
|
7318 |
// If siblings are text nodes then merge them unless it's Opera since it some how removes the node
|
T |
7319 |
// and we are sniffing since adding a lot of detection code for a browser with 3% of the market isn't worth the effort. Sorry, Opera but it's just a fact
|
|
7320 |
if (prev && next && prev.nodeType == next.nodeType && prev.nodeType == 3 && !tinymce.isOpera) {
|
69d05c
|
7321 |
idx = prev.nodeValue.length;
|
A |
7322 |
prev.appendData(next.nodeValue);
|
|
7323 |
dom.remove(next);
|
|
7324 |
|
|
7325 |
if (suffix == 'start') {
|
2011be
|
7326 |
startContainer = endContainer = prev;
|
A |
7327 |
startOffset = endOffset = idx;
|
|
7328 |
} else {
|
|
7329 |
endContainer = prev;
|
|
7330 |
endOffset = idx;
|
|
7331 |
}
|
69d05c
|
7332 |
}
|
A |
7333 |
}
|
|
7334 |
}
|
2011be
|
7335 |
};
|
A |
7336 |
|
|
7337 |
function addBogus(node) {
|
a9251b
|
7338 |
// Adds a bogus BR element for empty block elements or just a space on IE since it renders BR elements incorrectly
|
T |
7339 |
if (dom.isBlock(node) && !node.innerHTML)
|
|
7340 |
node.innerHTML = !isIE ? '<br data-mce-bogus="1" />' : ' ';
|
2011be
|
7341 |
|
A |
7342 |
return node;
|
69d05c
|
7343 |
};
|
A |
7344 |
|
|
7345 |
// Restore start/end points
|
|
7346 |
restoreEndPoint('start');
|
|
7347 |
restoreEndPoint('end');
|
|
7348 |
|
a9251b
|
7349 |
if (startContainer) {
|
T |
7350 |
rng = dom.createRng();
|
|
7351 |
rng.setStart(addBogus(startContainer), startOffset);
|
|
7352 |
rng.setEnd(addBogus(endContainer), endOffset);
|
|
7353 |
t.setRng(rng);
|
|
7354 |
}
|
69d05c
|
7355 |
} else if (bookmark.name) {
|
A |
7356 |
t.select(dom.select(bookmark.name)[bookmark.index]);
|
|
7357 |
} else if (bookmark.rng)
|
|
7358 |
t.setRng(bookmark.rng);
|
d9344f
|
7359 |
}
|
S |
7360 |
},
|
|
7361 |
|
69d05c
|
7362 |
select : function(node, content) {
|
A |
7363 |
var t = this, dom = t.dom, rng = dom.createRng(), idx;
|
d9344f
|
7364 |
|
a9251b
|
7365 |
if (node) {
|
T |
7366 |
idx = dom.nodeIndex(node);
|
|
7367 |
rng.setStart(node.parentNode, idx);
|
|
7368 |
rng.setEnd(node.parentNode, idx + 1);
|
d9344f
|
7369 |
|
a9251b
|
7370 |
// Find first/last text node or BR element
|
T |
7371 |
if (content) {
|
|
7372 |
function setPoint(node, start) {
|
|
7373 |
var walker = new tinymce.dom.TreeWalker(node, node);
|
d9344f
|
7374 |
|
a9251b
|
7375 |
do {
|
T |
7376 |
// Text node
|
|
7377 |
if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) {
|
|
7378 |
if (start)
|
|
7379 |
rng.setStart(node, 0);
|
|
7380 |
else
|
|
7381 |
rng.setEnd(node, node.nodeValue.length);
|
69d05c
|
7382 |
|
a9251b
|
7383 |
return;
|
T |
7384 |
}
|
d9344f
|
7385 |
|
a9251b
|
7386 |
// BR element
|
T |
7387 |
if (node.nodeName == 'BR') {
|
|
7388 |
if (start)
|
|
7389 |
rng.setStartBefore(node);
|
|
7390 |
else
|
|
7391 |
rng.setEndBefore(node);
|
d9344f
|
7392 |
|
a9251b
|
7393 |
return;
|
T |
7394 |
}
|
|
7395 |
} while (node = (start ? walker.next() : walker.prev()));
|
|
7396 |
};
|
d9344f
|
7397 |
|
a9251b
|
7398 |
setPoint(node, 1);
|
T |
7399 |
setPoint(node);
|
|
7400 |
}
|
|
7401 |
|
|
7402 |
t.setRng(rng);
|
d9344f
|
7403 |
}
|
69d05c
|
7404 |
|
A |
7405 |
return node;
|
d9344f
|
7406 |
},
|
S |
7407 |
|
|
7408 |
isCollapsed : function() {
|
|
7409 |
var t = this, r = t.getRng(), s = t.getSel();
|
|
7410 |
|
|
7411 |
if (!r || r.item)
|
|
7412 |
return false;
|
|
7413 |
|
69d05c
|
7414 |
if (r.compareEndPoints)
|
A |
7415 |
return r.compareEndPoints('StartToEnd', r) === 0;
|
|
7416 |
|
|
7417 |
return !s || r.collapsed;
|
d9344f
|
7418 |
},
|
S |
7419 |
|
a9251b
|
7420 |
collapse : function(to_start) {
|
T |
7421 |
var self = this, rng = self.getRng(), node;
|
d9344f
|
7422 |
|
S |
7423 |
// Control range on IE
|
a9251b
|
7424 |
if (rng.item) {
|
T |
7425 |
node = rng.item(0);
|
|
7426 |
rng = self.win.document.body.createTextRange();
|
|
7427 |
rng.moveToElementText(node);
|
d9344f
|
7428 |
}
|
S |
7429 |
|
a9251b
|
7430 |
rng.collapse(!!to_start);
|
T |
7431 |
self.setRng(rng);
|
d9344f
|
7432 |
},
|
S |
7433 |
|
|
7434 |
getSel : function() {
|
|
7435 |
var t = this, w = this.win;
|
|
7436 |
|
|
7437 |
return w.getSelection ? w.getSelection() : w.document.selection;
|
|
7438 |
},
|
|
7439 |
|
29da64
|
7440 |
getRng : function(w3c) {
|
a9251b
|
7441 |
var t = this, s, r, elm, doc = t.win.document;
|
29da64
|
7442 |
|
A |
7443 |
// Found tridentSel object then we need to use that one
|
|
7444 |
if (w3c && t.tridentSel)
|
|
7445 |
return t.tridentSel.getRangeAt(0);
|
d9344f
|
7446 |
|
S |
7447 |
try {
|
29da64
|
7448 |
if (s = t.getSel())
|
a9251b
|
7449 |
r = s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ? s.createRange() : doc.createRange());
|
d9344f
|
7450 |
} catch (ex) {
|
S |
7451 |
// IE throws unspecified error here if TinyMCE is placed in a frame/iframe
|
a9251b
|
7452 |
}
|
T |
7453 |
|
|
7454 |
// We have W3C ranges and it's IE then fake control selection since IE9 doesn't handle that correctly yet
|
|
7455 |
if (tinymce.isIE && r && r.setStart && doc.selection.createRange().item) {
|
|
7456 |
elm = doc.selection.createRange().item(0);
|
|
7457 |
r = doc.createRange();
|
|
7458 |
r.setStartBefore(elm);
|
|
7459 |
r.setEndAfter(elm);
|
d9344f
|
7460 |
}
|
S |
7461 |
|
|
7462 |
// No range found then create an empty one
|
|
7463 |
// This can occur when the editor is placed in a hidden container element on Gecko
|
|
7464 |
// Or on IE when there was an exception
|
|
7465 |
if (!r)
|
a9251b
|
7466 |
r = doc.createRange ? doc.createRange() : doc.body.createTextRange();
|
d9344f
|
7467 |
|
2011be
|
7468 |
if (t.selectedRange && t.explicitRange) {
|
A |
7469 |
if (r.compareBoundaryPoints(r.START_TO_START, t.selectedRange) === 0 && r.compareBoundaryPoints(r.END_TO_END, t.selectedRange) === 0) {
|
|
7470 |
// Safari, Opera and Chrome only ever select text which causes the range to change.
|
|
7471 |
// This lets us use the originally set range if the selection hasn't been changed by the user.
|
|
7472 |
r = t.explicitRange;
|
|
7473 |
} else {
|
|
7474 |
t.selectedRange = null;
|
|
7475 |
t.explicitRange = null;
|
|
7476 |
}
|
|
7477 |
}
|
a9251b
|
7478 |
|
d9344f
|
7479 |
return r;
|
S |
7480 |
},
|
|
7481 |
|
|
7482 |
setRng : function(r) {
|
29da64
|
7483 |
var s, t = this;
|
2011be
|
7484 |
|
29da64
|
7485 |
if (!t.tridentSel) {
|
A |
7486 |
s = t.getSel();
|
d9344f
|
7487 |
|
S |
7488 |
if (s) {
|
2011be
|
7489 |
t.explicitRange = r;
|
a9251b
|
7490 |
|
T |
7491 |
try {
|
|
7492 |
s.removeAllRanges();
|
|
7493 |
} catch (ex) {
|
|
7494 |
// IE9 might throw errors here don't know why
|
|
7495 |
}
|
|
7496 |
|
d9344f
|
7497 |
s.addRange(r);
|
2011be
|
7498 |
t.selectedRange = s.getRangeAt(0);
|
d9344f
|
7499 |
}
|
S |
7500 |
} else {
|
29da64
|
7501 |
// Is W3C Range
|
A |
7502 |
if (r.cloneRange) {
|
|
7503 |
t.tridentSel.addRange(r);
|
|
7504 |
return;
|
|
7505 |
}
|
|
7506 |
|
|
7507 |
// Is IE specific range
|
d9344f
|
7508 |
try {
|
S |
7509 |
r.select();
|
|
7510 |
} catch (ex) {
|
|
7511 |
// Needed for some odd IE bug #1843306
|
|
7512 |
}
|
|
7513 |
}
|
|
7514 |
},
|
|
7515 |
|
|
7516 |
setNode : function(n) {
|
|
7517 |
var t = this;
|
|
7518 |
|
|
7519 |
t.setContent(t.dom.getOuterHTML(n));
|
|
7520 |
|
|
7521 |
return n;
|
|
7522 |
},
|
|
7523 |
|
|
7524 |
getNode : function() {
|
a9251b
|
7525 |
var t = this, rng = t.getRng(), sel = t.getSel(), elm, start = rng.startContainer, end = rng.endContainer;
|
T |
7526 |
|
|
7527 |
// Range maybe lost after the editor is made visible again
|
|
7528 |
if (!rng)
|
|
7529 |
return t.dom.getRoot();
|
d9344f
|
7530 |
|
799907
|
7531 |
if (rng.setStart) {
|
69d05c
|
7532 |
elm = rng.commonAncestorContainer;
|
d9344f
|
7533 |
|
S |
7534 |
// Handle selection a image or other control like element such as anchors
|
69d05c
|
7535 |
if (!rng.collapsed) {
|
A |
7536 |
if (rng.startContainer == rng.endContainer) {
|
a9251b
|
7537 |
if (rng.endOffset - rng.startOffset < 2) {
|
69d05c
|
7538 |
if (rng.startContainer.hasChildNodes())
|
A |
7539 |
elm = rng.startContainer.childNodes[rng.startOffset];
|
d9344f
|
7540 |
}
|
S |
7541 |
}
|
69d05c
|
7542 |
|
A |
7543 |
// If the anchor node is a element instead of a text node then return this element
|
a9251b
|
7544 |
//if (tinymce.isWebKit && sel.anchorNode && sel.anchorNode.nodeType == 1)
|
T |
7545 |
// return sel.anchorNode.childNodes[sel.anchorOffset];
|
|
7546 |
|
|
7547 |
// Handle cases where the selection is immediately wrapped around a node and return that node instead of it's parent.
|
|
7548 |
// This happens when you double click an underlined word in FireFox.
|
|
7549 |
if (start.nodeType === 3 && end.nodeType === 3) {
|
|
7550 |
function skipEmptyTextNodes(n, forwards) {
|
|
7551 |
var orig = n;
|
|
7552 |
while (n && n.nodeType === 3 && n.length === 0) {
|
|
7553 |
n = forwards ? n.nextSibling : n.previousSibling;
|
|
7554 |
}
|
|
7555 |
return n || orig;
|
|
7556 |
}
|
|
7557 |
if (start.length === rng.startOffset) {
|
|
7558 |
start = skipEmptyTextNodes(start.nextSibling, true);
|
|
7559 |
} else {
|
|
7560 |
start = start.parentNode;
|
|
7561 |
}
|
|
7562 |
if (rng.endOffset === 0) {
|
|
7563 |
end = skipEmptyTextNodes(end.previousSibling, false);
|
|
7564 |
} else {
|
|
7565 |
end = end.parentNode;
|
|
7566 |
}
|
|
7567 |
|
|
7568 |
if (start && start === end)
|
|
7569 |
return start;
|
|
7570 |
}
|
d9344f
|
7571 |
}
|
S |
7572 |
|
69d05c
|
7573 |
if (elm && elm.nodeType == 3)
|
A |
7574 |
return elm.parentNode;
|
|
7575 |
|
|
7576 |
return elm;
|
d9344f
|
7577 |
}
|
S |
7578 |
|
69d05c
|
7579 |
return rng.item ? rng.item(0) : rng.parentElement();
|
29da64
|
7580 |
},
|
A |
7581 |
|
|
7582 |
getSelectedBlocks : function(st, en) {
|
|
7583 |
var t = this, dom = t.dom, sb, eb, n, bl = [];
|
|
7584 |
|
|
7585 |
sb = dom.getParent(st || t.getStart(), dom.isBlock);
|
|
7586 |
eb = dom.getParent(en || t.getEnd(), dom.isBlock);
|
|
7587 |
|
|
7588 |
if (sb)
|
|
7589 |
bl.push(sb);
|
|
7590 |
|
|
7591 |
if (sb && eb && sb != eb) {
|
|
7592 |
n = sb;
|
|
7593 |
|
|
7594 |
while ((n = n.nextSibling) && n != eb) {
|
|
7595 |
if (dom.isBlock(n))
|
|
7596 |
bl.push(n);
|
|
7597 |
}
|
|
7598 |
}
|
|
7599 |
|
|
7600 |
if (eb && sb != eb)
|
|
7601 |
bl.push(eb);
|
|
7602 |
|
|
7603 |
return bl;
|
d9344f
|
7604 |
},
|
S |
7605 |
|
|
7606 |
destroy : function(s) {
|
|
7607 |
var t = this;
|
|
7608 |
|
|
7609 |
t.win = null;
|
|
7610 |
|
29da64
|
7611 |
if (t.tridentSel)
|
A |
7612 |
t.tridentSel.destroy();
|
|
7613 |
|
d9344f
|
7614 |
// Manual destroy then remove unload handler
|
S |
7615 |
if (!s)
|
|
7616 |
tinymce.removeUnload(t.destroy);
|
a9251b
|
7617 |
},
|
69d05c
|
7618 |
|
a9251b
|
7619 |
// IE has an issue where you can't select/move the caret by clicking outside the body if the document is in standards mode
|
T |
7620 |
_fixIESelection : function() {
|
|
7621 |
var dom = this.dom, doc = dom.doc, body = doc.body, started, startRng, htmlElm;
|
d9344f
|
7622 |
|
a9251b
|
7623 |
// Make HTML element unselectable since we are going to handle selection by hand
|
T |
7624 |
doc.documentElement.unselectable = true;
|
d9344f
|
7625 |
|
a9251b
|
7626 |
// Return range from point or null if it failed
|
T |
7627 |
function rngFromPoint(x, y) {
|
|
7628 |
var rng = body.createTextRange();
|
|
7629 |
|
|
7630 |
try {
|
|
7631 |
rng.moveToPoint(x, y);
|
|
7632 |
} catch (ex) {
|
|
7633 |
// IE sometimes throws and exception, so lets just ignore it
|
|
7634 |
rng = null;
|
|
7635 |
}
|
|
7636 |
|
|
7637 |
return rng;
|
|
7638 |
};
|
|
7639 |
|
|
7640 |
// Fires while the selection is changing
|
|
7641 |
function selectionChange(e) {
|
|
7642 |
var pointRng;
|
|
7643 |
|
|
7644 |
// Check if the button is down or not
|
|
7645 |
if (e.button) {
|
|
7646 |
// Create range from mouse position
|
|
7647 |
pointRng = rngFromPoint(e.x, e.y);
|
|
7648 |
|
|
7649 |
if (pointRng) {
|
|
7650 |
// Check if pointRange is before/after selection then change the endPoint
|
|
7651 |
if (pointRng.compareEndPoints('StartToStart', startRng) > 0)
|
|
7652 |
pointRng.setEndPoint('StartToStart', startRng);
|
|
7653 |
else
|
|
7654 |
pointRng.setEndPoint('EndToEnd', startRng);
|
|
7655 |
|
|
7656 |
pointRng.select();
|
|
7657 |
}
|
d9344f
|
7658 |
} else
|
a9251b
|
7659 |
endSelection();
|
T |
7660 |
}
|
|
7661 |
|
|
7662 |
// Removes listeners
|
|
7663 |
function endSelection() {
|
|
7664 |
var rng = doc.selection.createRange();
|
|
7665 |
|
|
7666 |
// If the range is collapsed then use the last start range
|
|
7667 |
if (startRng && !rng.item && rng.compareEndPoints('StartToEnd', rng) === 0)
|
|
7668 |
startRng.select();
|
|
7669 |
|
|
7670 |
dom.unbind(doc, 'mouseup', endSelection);
|
|
7671 |
dom.unbind(doc, 'mousemove', selectionChange);
|
|
7672 |
startRng = started = 0;
|
d9344f
|
7673 |
};
|
S |
7674 |
|
a9251b
|
7675 |
// Detect when user selects outside BODY
|
T |
7676 |
dom.bind(doc, ['mousedown', 'contextmenu'], function(e) {
|
|
7677 |
if (e.target.nodeName === 'HTML') {
|
|
7678 |
if (started)
|
|
7679 |
endSelection();
|
d9344f
|
7680 |
|
a9251b
|
7681 |
// Detect vertical scrollbar, since IE will fire a mousedown on the scrollbar and have target set as HTML
|
T |
7682 |
htmlElm = doc.documentElement;
|
|
7683 |
if (htmlElm.scrollHeight > htmlElm.clientHeight)
|
|
7684 |
return;
|
d9344f
|
7685 |
|
a9251b
|
7686 |
started = 1;
|
T |
7687 |
// Setup start position
|
|
7688 |
startRng = rngFromPoint(e.x, e.y);
|
|
7689 |
if (startRng) {
|
|
7690 |
// Listen for selection change events
|
|
7691 |
dom.bind(doc, 'mouseup', endSelection);
|
|
7692 |
dom.bind(doc, 'mousemove', selectionChange);
|
d9344f
|
7693 |
|
a9251b
|
7694 |
dom.win.focus();
|
T |
7695 |
startRng.select();
|
|
7696 |
}
|
|
7697 |
}
|
|
7698 |
});
|
d9344f
|
7699 |
}
|
58fb65
|
7700 |
});
|
29da64
|
7701 |
})(tinymce);
|
69d05c
|
7702 |
|
29da64
|
7703 |
(function(tinymce) {
|
a9251b
|
7704 |
tinymce.dom.Serializer = function(settings, dom, schema) {
|
T |
7705 |
var onPreProcess, onPostProcess, isIE = tinymce.isIE, each = tinymce.each, htmlParser;
|
d9344f
|
7706 |
|
a9251b
|
7707 |
// Support the old apply_source_formatting option
|
T |
7708 |
if (!settings.apply_source_formatting)
|
|
7709 |
settings.indent = false;
|
d9344f
|
7710 |
|
a9251b
|
7711 |
settings.remove_trailing_brs = true;
|
d9344f
|
7712 |
|
a9251b
|
7713 |
// Default DOM and Schema if they are undefined
|
T |
7714 |
dom = dom || tinymce.DOM;
|
|
7715 |
schema = schema || new tinymce.html.Schema(settings);
|
|
7716 |
settings.entity_encoding = settings.entity_encoding || 'named';
|
d9344f
|
7717 |
|
a9251b
|
7718 |
onPreProcess = new tinymce.util.Dispatcher(self);
|
d9344f
|
7719 |
|
a9251b
|
7720 |
onPostProcess = new tinymce.util.Dispatcher(self);
|
d9344f
|
7721 |
|
a9251b
|
7722 |
htmlParser = new tinymce.html.DomParser(settings, schema);
|
d9344f
|
7723 |
|
a9251b
|
7724 |
// Convert move data-mce-src, data-mce-href and data-mce-style into nodes or process them if needed
|
T |
7725 |
htmlParser.addAttributeFilter('src,href,style', function(nodes, name) {
|
|
7726 |
var i = nodes.length, node, value, internalName = 'data-mce-' + name, urlConverter = settings.url_converter, urlConverterScope = settings.url_converter_scope, undef;
|
d9344f
|
7727 |
|
a9251b
|
7728 |
while (i--) {
|
T |
7729 |
node = nodes[i];
|
d9344f
|
7730 |
|
a9251b
|
7731 |
value = node.attributes.map[internalName];
|
T |
7732 |
if (value !== undef) {
|
|
7733 |
// Set external name to internal value and remove internal
|
|
7734 |
node.attr(name, value.length > 0 ? value : null);
|
|
7735 |
node.attr(internalName, null);
|
|
7736 |
} else {
|
|
7737 |
// No internal attribute found then convert the value we have in the DOM
|
|
7738 |
value = node.attributes.map[name];
|
d9344f
|
7739 |
|
a9251b
|
7740 |
if (name === "style")
|
T |
7741 |
value = dom.serializeStyle(dom.parseStyle(value), node.name);
|
|
7742 |
else if (urlConverter)
|
|
7743 |
value = urlConverter.call(urlConverterScope, value, name, node.name);
|
|
7744 |
|
|
7745 |
node.attr(name, value.length > 0 ? value : null);
|
|
7746 |
}
|
d9344f
|
7747 |
}
|
a9251b
|
7748 |
});
|
d9344f
|
7749 |
|
a9251b
|
7750 |
// Remove internal classes mceItem<..>
|
T |
7751 |
htmlParser.addAttributeFilter('class', function(nodes, name) {
|
|
7752 |
var i = nodes.length, node, value;
|
d9344f
|
7753 |
|
a9251b
|
7754 |
while (i--) {
|
T |
7755 |
node = nodes[i];
|
|
7756 |
value = node.attr('class').replace(/\s*mce(Item\w+|Selected)\s*/g, '');
|
|
7757 |
node.attr('class', value.length > 0 ? value : null);
|
d9344f
|
7758 |
}
|
a9251b
|
7759 |
});
|
d9344f
|
7760 |
|
a9251b
|
7761 |
// Remove bookmark elements
|
T |
7762 |
htmlParser.addAttributeFilter('data-mce-type', function(nodes, name, args) {
|
|
7763 |
var i = nodes.length, node;
|
d9344f
|
7764 |
|
a9251b
|
7765 |
while (i--) {
|
T |
7766 |
node = nodes[i];
|
d9344f
|
7767 |
|
a9251b
|
7768 |
if (node.attributes.map['data-mce-type'] === 'bookmark' && !args.cleanup)
|
T |
7769 |
node.remove();
|
|
7770 |
}
|
|
7771 |
});
|
d9344f
|
7772 |
|
a9251b
|
7773 |
// Force script into CDATA sections and remove the mce- prefix also add comments around styles
|
T |
7774 |
htmlParser.addNodeFilter('script,style', function(nodes, name) {
|
|
7775 |
var i = nodes.length, node, value;
|
d9344f
|
7776 |
|
a9251b
|
7777 |
function trim(value) {
|
T |
7778 |
return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n')
|
|
7779 |
.replace(/^[\r\n]*|[\r\n]*$/g, '')
|
|
7780 |
.replace(/^\s*(\/\/\s*<!--|\/\/\s*<!\[CDATA\[|<!--|<!\[CDATA\[)[\r\n]*/g, '')
|
|
7781 |
.replace(/\s*(\/\/\s*\]\]>|\/\/\s*-->|\]\]>|-->|\]\]-->)\s*$/g, '');
|
|
7782 |
};
|
d9344f
|
7783 |
|
a9251b
|
7784 |
while (i--) {
|
T |
7785 |
node = nodes[i];
|
|
7786 |
value = node.firstChild ? node.firstChild.value : '';
|
d9344f
|
7787 |
|
a9251b
|
7788 |
if (name === "script") {
|
T |
7789 |
// Remove mce- prefix from script elements
|
|
7790 |
node.attr('type', (node.attr('type') || 'text/javascript').replace(/^mce\-/, ''));
|
d9344f
|
7791 |
|
a9251b
|
7792 |
if (value.length > 0)
|
T |
7793 |
node.firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
|
|
7794 |
} else {
|
|
7795 |
if (value.length > 0)
|
|
7796 |
node.firstChild.value = '<!--\n' + trim(value) + '\n-->';
|
|
7797 |
}
|
|
7798 |
}
|
|
7799 |
});
|
|
7800 |
|
|
7801 |
// Convert comments to cdata and handle protected comments
|
|
7802 |
htmlParser.addNodeFilter('#comment', function(nodes, name) {
|
|
7803 |
var i = nodes.length, node;
|
|
7804 |
|
|
7805 |
while (i--) {
|
|
7806 |
node = nodes[i];
|
|
7807 |
|
|
7808 |
if (node.value.indexOf('[CDATA[') === 0) {
|
|
7809 |
node.name = '#cdata';
|
|
7810 |
node.type = 4;
|
|
7811 |
node.value = node.value.replace(/^\[CDATA\[|\]\]$/g, '');
|
|
7812 |
} else if (node.value.indexOf('mce:protected ') === 0) {
|
|
7813 |
node.name = "#text";
|
|
7814 |
node.type = 3;
|
|
7815 |
node.raw = true;
|
|
7816 |
node.value = unescape(node.value).substr(14);
|
|
7817 |
}
|
|
7818 |
}
|
|
7819 |
});
|
|
7820 |
|
|
7821 |
htmlParser.addNodeFilter('xml:namespace,input', function(nodes, name) {
|
|
7822 |
var i = nodes.length, node;
|
|
7823 |
|
|
7824 |
while (i--) {
|
|
7825 |
node = nodes[i];
|
|
7826 |
if (node.type === 7)
|
|
7827 |
node.remove();
|
|
7828 |
else if (node.type === 1) {
|
|
7829 |
if (name === "input" && !("type" in node.attributes.map))
|
|
7830 |
node.attr('type', 'text');
|
|
7831 |
}
|
|
7832 |
}
|
|
7833 |
});
|
|
7834 |
|
|
7835 |
// Fix list elements, TODO: Replace this later
|
|
7836 |
if (settings.fix_list_elements) {
|
|
7837 |
htmlParser.addNodeFilter('ul,ol', function(nodes, name) {
|
|
7838 |
var i = nodes.length, node, parentNode;
|
|
7839 |
|
|
7840 |
while (i--) {
|
|
7841 |
node = nodes[i];
|
|
7842 |
parentNode = node.parent;
|
|
7843 |
|
|
7844 |
if (parentNode.name === 'ul' || parentNode.name === 'ol') {
|
|
7845 |
if (node.prev && node.prev.name === 'li') {
|
|
7846 |
node.prev.append(node);
|
|
7847 |
}
|
|
7848 |
}
|
|
7849 |
}
|
|
7850 |
});
|
|
7851 |
}
|
|
7852 |
|
|
7853 |
// Remove internal data attributes
|
|
7854 |
htmlParser.addAttributeFilter('data-mce-src,data-mce-href,data-mce-style', function(nodes, name) {
|
|
7855 |
var i = nodes.length;
|
|
7856 |
|
|
7857 |
while (i--) {
|
|
7858 |
nodes[i].attr(name, null);
|
|
7859 |
}
|
|
7860 |
});
|
|
7861 |
|
|
7862 |
// Return public methods
|
|
7863 |
return {
|
|
7864 |
schema : schema,
|
|
7865 |
|
|
7866 |
addNodeFilter : htmlParser.addNodeFilter,
|
|
7867 |
|
|
7868 |
addAttributeFilter : htmlParser.addAttributeFilter,
|
|
7869 |
|
|
7870 |
onPreProcess : onPreProcess,
|
|
7871 |
|
|
7872 |
onPostProcess : onPostProcess,
|
|
7873 |
|
|
7874 |
serialize : function(node, args) {
|
|
7875 |
var impl, doc, oldDoc, htmlSerializer, content;
|
|
7876 |
|
|
7877 |
// Explorer won't clone contents of script and style and the
|
|
7878 |
// selected index of select elements are cleared on a clone operation.
|
|
7879 |
if (isIE && dom.select('script,style,select').length > 0) {
|
|
7880 |
content = node.innerHTML;
|
|
7881 |
node = node.cloneNode(false);
|
|
7882 |
dom.setHTML(node, content);
|
|
7883 |
} else
|
|
7884 |
node = node.cloneNode(true);
|
|
7885 |
|
|
7886 |
// Nodes needs to be attached to something in WebKit/Opera
|
|
7887 |
// Older builds of Opera crashes if you attach the node to an document created dynamically
|
|
7888 |
// and since we can't feature detect a crash we need to sniff the acutal build number
|
|
7889 |
// This fix will make DOM ranges and make Sizzle happy!
|
|
7890 |
impl = node.ownerDocument.implementation;
|
|
7891 |
if (impl.createHTMLDocument) {
|
|
7892 |
// Create an empty HTML document
|
|
7893 |
doc = impl.createHTMLDocument("");
|
|
7894 |
|
|
7895 |
// Add the element or it's children if it's a body element to the new document
|
|
7896 |
each(node.nodeName == 'BODY' ? node.childNodes : [node], function(node) {
|
|
7897 |
doc.body.appendChild(doc.importNode(node, true));
|
|
7898 |
});
|
|
7899 |
|
|
7900 |
// Grab first child or body element for serialization
|
|
7901 |
if (node.nodeName != 'BODY')
|
|
7902 |
node = doc.body.firstChild;
|
|
7903 |
else
|
|
7904 |
node = doc.body;
|
|
7905 |
|
|
7906 |
// set the new document in DOMUtils so createElement etc works
|
|
7907 |
oldDoc = dom.doc;
|
|
7908 |
dom.doc = doc;
|
d9344f
|
7909 |
}
|
S |
7910 |
|
a9251b
|
7911 |
args = args || {};
|
T |
7912 |
args.format = args.format || 'html';
|
d9344f
|
7913 |
|
a9251b
|
7914 |
// Pre process
|
T |
7915 |
if (!args.no_events) {
|
|
7916 |
args.node = node;
|
|
7917 |
onPreProcess.dispatch(self, args);
|
|
7918 |
}
|
d9344f
|
7919 |
|
a9251b
|
7920 |
// Setup serializer
|
T |
7921 |
htmlSerializer = new tinymce.html.Serializer(settings, schema);
|
d9344f
|
7922 |
|
a9251b
|
7923 |
// Parse and serialize HTML
|
T |
7924 |
args.content = htmlSerializer.serialize(
|
|
7925 |
htmlParser.parse(args.getInner ? node.innerHTML : tinymce.trim(dom.getOuterHTML(node), args), args)
|
|
7926 |
);
|
d9344f
|
7927 |
|
a9251b
|
7928 |
// Replace all BOM characters for now until we can find a better solution
|
T |
7929 |
if (!args.cleanup)
|
|
7930 |
args.content = args.content.replace(/\uFEFF/g, '');
|
|
7931 |
|
|
7932 |
// Post process
|
|
7933 |
if (!args.no_events)
|
|
7934 |
onPostProcess.dispatch(self, args);
|
|
7935 |
|
|
7936 |
// Restore the old document if it was changed
|
|
7937 |
if (oldDoc)
|
|
7938 |
dom.doc = oldDoc;
|
|
7939 |
|
|
7940 |
args.node = null;
|
|
7941 |
|
|
7942 |
return args.content;
|
|
7943 |
},
|
|
7944 |
|
|
7945 |
addRules : function(rules) {
|
|
7946 |
schema.addValidElements(rules);
|
|
7947 |
},
|
|
7948 |
|
|
7949 |
setRules : function(rules) {
|
|
7950 |
schema.setValidElements(rules);
|
d9344f
|
7951 |
}
|
a9251b
|
7952 |
};
|
d9344f
|
7953 |
};
|
29da64
|
7954 |
})(tinymce);
|
A |
7955 |
(function(tinymce) {
|
69d05c
|
7956 |
tinymce.dom.ScriptLoader = function(settings) {
|
A |
7957 |
var QUEUED = 0,
|
|
7958 |
LOADING = 1,
|
|
7959 |
LOADED = 2,
|
|
7960 |
states = {},
|
|
7961 |
queue = [],
|
|
7962 |
scriptLoadedCallbacks = {},
|
|
7963 |
queueLoadedCallbacks = [],
|
|
7964 |
loading = 0,
|
|
7965 |
undefined;
|
d9344f
|
7966 |
|
69d05c
|
7967 |
function loadScript(url, callback) {
|
A |
7968 |
var t = this, dom = tinymce.DOM, elm, uri, loc, id;
|
d9344f
|
7969 |
|
69d05c
|
7970 |
// Execute callback when script is loaded
|
A |
7971 |
function done() {
|
|
7972 |
dom.remove(id);
|
d9344f
|
7973 |
|
69d05c
|
7974 |
if (elm)
|
A |
7975 |
elm.onreadystatechange = elm.onload = elm = null;
|
d9344f
|
7976 |
|
69d05c
|
7977 |
callback();
|
A |
7978 |
};
|
a9251b
|
7979 |
|
T |
7980 |
function error() {
|
|
7981 |
// Report the error so it's easier for people to spot loading errors
|
|
7982 |
if (typeof(console) !== "undefined" && console.log)
|
|
7983 |
console.log("Failed to load: " + url);
|
|
7984 |
|
|
7985 |
// We can't mark it as done if there is a load error since
|
|
7986 |
// A) We don't want to produce 404 errors on the server and
|
|
7987 |
// B) the onerror event won't fire on all browsers.
|
|
7988 |
// done();
|
|
7989 |
};
|
d9344f
|
7990 |
|
69d05c
|
7991 |
id = dom.uniqueId();
|
d9344f
|
7992 |
|
69d05c
|
7993 |
if (tinymce.isIE6) {
|
A |
7994 |
uri = new tinymce.util.URI(url);
|
|
7995 |
loc = location;
|
d9344f
|
7996 |
|
69d05c
|
7997 |
// If script is from same domain and we
|
A |
7998 |
// use IE 6 then use XHR since it's more reliable
|
a9251b
|
7999 |
if (uri.host == loc.hostname && uri.port == loc.port && (uri.protocol + ':') == loc.protocol && uri.protocol.toLowerCase() != 'file') {
|
d9344f
|
8000 |
tinymce.util.XHR.send({
|
69d05c
|
8001 |
url : tinymce._addVer(uri.getURI()),
|
A |
8002 |
success : function(content) {
|
|
8003 |
// Create new temp script element
|
|
8004 |
var script = dom.create('script', {
|
|
8005 |
type : 'text/javascript'
|
|
8006 |
});
|
|
8007 |
|
|
8008 |
// Evaluate script in global scope
|
|
8009 |
script.text = content;
|
|
8010 |
document.getElementsByTagName('head')[0].appendChild(script);
|
|
8011 |
dom.remove(script);
|
|
8012 |
|
|
8013 |
done();
|
a9251b
|
8014 |
},
|
T |
8015 |
|
|
8016 |
error : error
|
d9344f
|
8017 |
});
|
S |
8018 |
|
69d05c
|
8019 |
return;
|
A |
8020 |
}
|
d9344f
|
8021 |
}
|
S |
8022 |
|
69d05c
|
8023 |
// Create new script element
|
A |
8024 |
elm = dom.create('script', {
|
|
8025 |
id : id,
|
|
8026 |
type : 'text/javascript',
|
|
8027 |
src : tinymce._addVer(url)
|
d9344f
|
8028 |
});
|
S |
8029 |
|
a9251b
|
8030 |
// Add onload listener for non IE browsers since IE9
|
T |
8031 |
// fires onload event before the script is parsed and executed
|
|
8032 |
if (!tinymce.isIE)
|
|
8033 |
elm.onload = done;
|
d9344f
|
8034 |
|
a9251b
|
8035 |
// Add onerror event will get fired on some browsers but not all of them
|
T |
8036 |
elm.onerror = error;
|
|
8037 |
|
|
8038 |
// Opera 9.60 doesn't seem to fire the onreadystate event at correctly
|
|
8039 |
if (!tinymce.isOpera) {
|
|
8040 |
elm.onreadystatechange = function() {
|
|
8041 |
var state = elm.readyState;
|
|
8042 |
|
|
8043 |
// Loaded state is passed on IE 6 however there
|
|
8044 |
// are known issues with this method but we can't use
|
|
8045 |
// XHR in a cross domain loading
|
|
8046 |
if (state == 'complete' || state == 'loaded')
|
|
8047 |
done();
|
|
8048 |
};
|
|
8049 |
}
|
d9344f
|
8050 |
|
69d05c
|
8051 |
// Most browsers support this feature so we report errors
|
A |
8052 |
// for those at least to help users track their missing plugins etc
|
|
8053 |
// todo: Removed since it produced error if the document is unloaded by navigating away, re-add it as an option
|
|
8054 |
/*elm.onerror = function() {
|
|
8055 |
alert('Failed to load: ' + url);
|
|
8056 |
};*/
|
d9344f
|
8057 |
|
69d05c
|
8058 |
// Add script to document
|
A |
8059 |
(document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
|
|
8060 |
};
|
d9344f
|
8061 |
|
69d05c
|
8062 |
this.isDone = function(url) {
|
A |
8063 |
return states[url] == LOADED;
|
|
8064 |
};
|
29da64
|
8065 |
|
69d05c
|
8066 |
this.markDone = function(url) {
|
A |
8067 |
states[url] = LOADED;
|
|
8068 |
};
|
29da64
|
8069 |
|
69d05c
|
8070 |
this.add = this.load = function(url, callback, scope) {
|
A |
8071 |
var item, state = states[url];
|
29da64
|
8072 |
|
69d05c
|
8073 |
// Add url to load queue
|
A |
8074 |
if (state == undefined) {
|
|
8075 |
queue.push(url);
|
|
8076 |
states[url] = QUEUED;
|
d9344f
|
8077 |
}
|
69d05c
|
8078 |
|
A |
8079 |
if (callback) {
|
|
8080 |
// Store away callback for later execution
|
|
8081 |
if (!scriptLoadedCallbacks[url])
|
|
8082 |
scriptLoadedCallbacks[url] = [];
|
|
8083 |
|
|
8084 |
scriptLoadedCallbacks[url].push({
|
|
8085 |
func : callback,
|
|
8086 |
scope : scope || this
|
|
8087 |
});
|
|
8088 |
}
|
|
8089 |
};
|
|
8090 |
|
|
8091 |
this.loadQueue = function(callback, scope) {
|
|
8092 |
this.loadScripts(queue, callback, scope);
|
|
8093 |
};
|
|
8094 |
|
|
8095 |
this.loadScripts = function(scripts, callback, scope) {
|
|
8096 |
var loadScripts;
|
|
8097 |
|
|
8098 |
function execScriptLoadedCallbacks(url) {
|
|
8099 |
// Execute URL callback functions
|
|
8100 |
tinymce.each(scriptLoadedCallbacks[url], function(callback) {
|
|
8101 |
callback.func.call(callback.scope);
|
|
8102 |
});
|
|
8103 |
|
|
8104 |
scriptLoadedCallbacks[url] = undefined;
|
|
8105 |
};
|
|
8106 |
|
|
8107 |
queueLoadedCallbacks.push({
|
|
8108 |
func : callback,
|
|
8109 |
scope : scope || this
|
|
8110 |
});
|
|
8111 |
|
|
8112 |
loadScripts = function() {
|
|
8113 |
var loadingScripts = tinymce.grep(scripts);
|
|
8114 |
|
|
8115 |
// Current scripts has been handled
|
|
8116 |
scripts.length = 0;
|
|
8117 |
|
|
8118 |
// Load scripts that needs to be loaded
|
|
8119 |
tinymce.each(loadingScripts, function(url) {
|
|
8120 |
// Script is already loaded then execute script callbacks directly
|
|
8121 |
if (states[url] == LOADED) {
|
|
8122 |
execScriptLoadedCallbacks(url);
|
|
8123 |
return;
|
|
8124 |
}
|
|
8125 |
|
|
8126 |
// Is script not loading then start loading it
|
|
8127 |
if (states[url] != LOADING) {
|
|
8128 |
states[url] = LOADING;
|
|
8129 |
loading++;
|
|
8130 |
|
|
8131 |
loadScript(url, function() {
|
|
8132 |
states[url] = LOADED;
|
|
8133 |
loading--;
|
|
8134 |
|
|
8135 |
execScriptLoadedCallbacks(url);
|
|
8136 |
|
|
8137 |
// Load more scripts if they where added by the recently loaded script
|
|
8138 |
loadScripts();
|
|
8139 |
});
|
|
8140 |
}
|
|
8141 |
});
|
|
8142 |
|
|
8143 |
// No scripts are currently loading then execute all pending queue loaded callbacks
|
|
8144 |
if (!loading) {
|
|
8145 |
tinymce.each(queueLoadedCallbacks, function(callback) {
|
|
8146 |
callback.func.call(callback.scope);
|
|
8147 |
});
|
|
8148 |
|
|
8149 |
queueLoadedCallbacks.length = 0;
|
|
8150 |
}
|
|
8151 |
};
|
|
8152 |
|
|
8153 |
loadScripts();
|
|
8154 |
};
|
|
8155 |
};
|
d9344f
|
8156 |
|
S |
8157 |
// Global script loader
|
|
8158 |
tinymce.ScriptLoader = new tinymce.dom.ScriptLoader();
|
29da64
|
8159 |
})(tinymce);
|
69d05c
|
8160 |
|
A |
8161 |
tinymce.dom.TreeWalker = function(start_node, root_node) {
|
|
8162 |
var node = start_node;
|
|
8163 |
|
|
8164 |
function findSibling(node, start_name, sibling_name, shallow) {
|
|
8165 |
var sibling, parent;
|
|
8166 |
|
|
8167 |
if (node) {
|
|
8168 |
// Walk into nodes if it has a start
|
|
8169 |
if (!shallow && node[start_name])
|
|
8170 |
return node[start_name];
|
|
8171 |
|
|
8172 |
// Return the sibling if it has one
|
|
8173 |
if (node != root_node) {
|
|
8174 |
sibling = node[sibling_name];
|
|
8175 |
if (sibling)
|
|
8176 |
return sibling;
|
|
8177 |
|
|
8178 |
// Walk up the parents to look for siblings
|
|
8179 |
for (parent = node.parentNode; parent && parent != root_node; parent = parent.parentNode) {
|
|
8180 |
sibling = parent[sibling_name];
|
|
8181 |
if (sibling)
|
|
8182 |
return sibling;
|
|
8183 |
}
|
|
8184 |
}
|
|
8185 |
}
|
|
8186 |
};
|
|
8187 |
|
|
8188 |
this.current = function() {
|
|
8189 |
return node;
|
|
8190 |
};
|
|
8191 |
|
|
8192 |
this.next = function(shallow) {
|
|
8193 |
return (node = findSibling(node, 'firstChild', 'nextSibling', shallow));
|
|
8194 |
};
|
|
8195 |
|
|
8196 |
this.prev = function(shallow) {
|
a9251b
|
8197 |
return (node = findSibling(node, 'lastChild', 'previousSibling', shallow));
|
69d05c
|
8198 |
};
|
A |
8199 |
};
|
|
8200 |
|
|
8201 |
(function(tinymce) {
|
|
8202 |
tinymce.dom.RangeUtils = function(dom) {
|
|
8203 |
var INVISIBLE_CHAR = '\uFEFF';
|
|
8204 |
|
|
8205 |
this.walk = function(rng, callback) {
|
|
8206 |
var startContainer = rng.startContainer,
|
|
8207 |
startOffset = rng.startOffset,
|
|
8208 |
endContainer = rng.endContainer,
|
|
8209 |
endOffset = rng.endOffset,
|
|
8210 |
ancestor, startPoint,
|
|
8211 |
endPoint, node, parent, siblings, nodes;
|
|
8212 |
|
|
8213 |
// Handle table cell selection the table plugin enables
|
|
8214 |
// you to fake select table cells and perform formatting actions on them
|
|
8215 |
nodes = dom.select('td.mceSelected,th.mceSelected');
|
|
8216 |
if (nodes.length > 0) {
|
|
8217 |
tinymce.each(nodes, function(node) {
|
|
8218 |
callback([node]);
|
|
8219 |
});
|
|
8220 |
|
|
8221 |
return;
|
|
8222 |
}
|
|
8223 |
|
|
8224 |
function collectSiblings(node, name, end_node) {
|
|
8225 |
var siblings = [];
|
|
8226 |
|
|
8227 |
for (; node && node != end_node; node = node[name])
|
|
8228 |
siblings.push(node);
|
|
8229 |
|
|
8230 |
return siblings;
|
|
8231 |
};
|
|
8232 |
|
|
8233 |
function findEndPoint(node, root) {
|
|
8234 |
do {
|
|
8235 |
if (node.parentNode == root)
|
|
8236 |
return node;
|
|
8237 |
|
|
8238 |
node = node.parentNode;
|
|
8239 |
} while(node);
|
|
8240 |
};
|
|
8241 |
|
|
8242 |
function walkBoundary(start_node, end_node, next) {
|
|
8243 |
var siblingName = next ? 'nextSibling' : 'previousSibling';
|
|
8244 |
|
|
8245 |
for (node = start_node, parent = node.parentNode; node && node != end_node; node = parent) {
|
|
8246 |
parent = node.parentNode;
|
|
8247 |
siblings = collectSiblings(node == start_node ? node : node[siblingName], siblingName);
|
|
8248 |
|
|
8249 |
if (siblings.length) {
|
|
8250 |
if (!next)
|
|
8251 |
siblings.reverse();
|
|
8252 |
|
|
8253 |
callback(siblings);
|
|
8254 |
}
|
|
8255 |
}
|
|
8256 |
};
|
|
8257 |
|
|
8258 |
// If index based start position then resolve it
|
|
8259 |
if (startContainer.nodeType == 1 && startContainer.hasChildNodes())
|
|
8260 |
startContainer = startContainer.childNodes[startOffset];
|
|
8261 |
|
|
8262 |
// If index based end position then resolve it
|
|
8263 |
if (endContainer.nodeType == 1 && endContainer.hasChildNodes())
|
a9251b
|
8264 |
endContainer = endContainer.childNodes[Math.min(endOffset - 1, endContainer.childNodes.length - 1)];
|
69d05c
|
8265 |
|
A |
8266 |
// Find common ancestor and end points
|
|
8267 |
ancestor = dom.findCommonAncestor(startContainer, endContainer);
|
|
8268 |
|
|
8269 |
// Same container
|
|
8270 |
if (startContainer == endContainer)
|
|
8271 |
return callback([startContainer]);
|
|
8272 |
|
|
8273 |
// Process left side
|
|
8274 |
for (node = startContainer; node; node = node.parentNode) {
|
|
8275 |
if (node == endContainer)
|
|
8276 |
return walkBoundary(startContainer, ancestor, true);
|
|
8277 |
|
|
8278 |
if (node == ancestor)
|
|
8279 |
break;
|
|
8280 |
}
|
|
8281 |
|
|
8282 |
// Process right side
|
|
8283 |
for (node = endContainer; node; node = node.parentNode) {
|
|
8284 |
if (node == startContainer)
|
|
8285 |
return walkBoundary(endContainer, ancestor);
|
|
8286 |
|
|
8287 |
if (node == ancestor)
|
|
8288 |
break;
|
|
8289 |
}
|
|
8290 |
|
|
8291 |
// Find start/end point
|
|
8292 |
startPoint = findEndPoint(startContainer, ancestor) || startContainer;
|
|
8293 |
endPoint = findEndPoint(endContainer, ancestor) || endContainer;
|
|
8294 |
|
|
8295 |
// Walk left leaf
|
|
8296 |
walkBoundary(startContainer, startPoint, true);
|
|
8297 |
|
|
8298 |
// Walk the middle from start to end point
|
|
8299 |
siblings = collectSiblings(
|
|
8300 |
startPoint == startContainer ? startPoint : startPoint.nextSibling,
|
|
8301 |
'nextSibling',
|
|
8302 |
endPoint == endContainer ? endPoint.nextSibling : endPoint
|
|
8303 |
);
|
|
8304 |
|
|
8305 |
if (siblings.length)
|
|
8306 |
callback(siblings);
|
|
8307 |
|
|
8308 |
// Walk right leaf
|
|
8309 |
walkBoundary(endContainer, endPoint);
|
|
8310 |
};
|
|
8311 |
|
|
8312 |
/* this.split = function(rng) {
|
|
8313 |
var startContainer = rng.startContainer,
|
|
8314 |
startOffset = rng.startOffset,
|
|
8315 |
endContainer = rng.endContainer,
|
|
8316 |
endOffset = rng.endOffset;
|
|
8317 |
|
|
8318 |
function splitText(node, offset) {
|
|
8319 |
if (offset == node.nodeValue.length)
|
|
8320 |
node.appendData(INVISIBLE_CHAR);
|
|
8321 |
|
|
8322 |
node = node.splitText(offset);
|
|
8323 |
|
|
8324 |
if (node.nodeValue === INVISIBLE_CHAR)
|
|
8325 |
node.nodeValue = '';
|
|
8326 |
|
|
8327 |
return node;
|
|
8328 |
};
|
|
8329 |
|
|
8330 |
// Handle single text node
|
|
8331 |
if (startContainer == endContainer) {
|
|
8332 |
if (startContainer.nodeType == 3) {
|
|
8333 |
if (startOffset != 0)
|
|
8334 |
startContainer = endContainer = splitText(startContainer, startOffset);
|
|
8335 |
|
|
8336 |
if (endOffset - startOffset != startContainer.nodeValue.length)
|
|
8337 |
splitText(startContainer, endOffset - startOffset);
|
|
8338 |
}
|
|
8339 |
} else {
|
|
8340 |
// Split startContainer text node if needed
|
|
8341 |
if (startContainer.nodeType == 3 && startOffset != 0) {
|
|
8342 |
startContainer = splitText(startContainer, startOffset);
|
|
8343 |
startOffset = 0;
|
|
8344 |
}
|
|
8345 |
|
|
8346 |
// Split endContainer text node if needed
|
|
8347 |
if (endContainer.nodeType == 3 && endOffset != endContainer.nodeValue.length) {
|
|
8348 |
endContainer = splitText(endContainer, endOffset).previousSibling;
|
|
8349 |
endOffset = endContainer.nodeValue.length;
|
|
8350 |
}
|
|
8351 |
}
|
|
8352 |
|
|
8353 |
return {
|
|
8354 |
startContainer : startContainer,
|
|
8355 |
startOffset : startOffset,
|
|
8356 |
endContainer : endContainer,
|
|
8357 |
endOffset : endOffset
|
|
8358 |
};
|
|
8359 |
};
|
|
8360 |
*/
|
|
8361 |
};
|
2011be
|
8362 |
|
A |
8363 |
tinymce.dom.RangeUtils.compareRanges = function(rng1, rng2) {
|
|
8364 |
if (rng1 && rng2) {
|
|
8365 |
// Compare native IE ranges
|
|
8366 |
if (rng1.item || rng1.duplicate) {
|
|
8367 |
// Both are control ranges and the selected element matches
|
|
8368 |
if (rng1.item && rng2.item && rng1.item(0) === rng2.item(0))
|
|
8369 |
return true;
|
|
8370 |
|
|
8371 |
// Both are text ranges and the range matches
|
|
8372 |
if (rng1.isEqual && rng2.isEqual && rng2.isEqual(rng1))
|
|
8373 |
return true;
|
|
8374 |
} else {
|
|
8375 |
// Compare w3c ranges
|
|
8376 |
return rng1.startContainer == rng2.startContainer && rng1.startOffset == rng2.startOffset;
|
|
8377 |
}
|
|
8378 |
}
|
|
8379 |
|
|
8380 |
return false;
|
|
8381 |
};
|
69d05c
|
8382 |
})(tinymce);
|
A |
8383 |
|
29da64
|
8384 |
(function(tinymce) {
|
a9251b
|
8385 |
var Event = tinymce.dom.Event, each = tinymce.each;
|
T |
8386 |
|
|
8387 |
tinymce.create('tinymce.ui.KeyboardNavigation', {
|
|
8388 |
KeyboardNavigation: function(settings, dom) {
|
|
8389 |
var t = this, root = settings.root, items = settings.items,
|
|
8390 |
enableUpDown = settings.enableUpDown, enableLeftRight = settings.enableLeftRight || !settings.enableUpDown,
|
|
8391 |
excludeFromTabOrder = settings.excludeFromTabOrder,
|
|
8392 |
itemFocussed, itemBlurred, rootKeydown, rootFocussed, focussedId;
|
|
8393 |
|
|
8394 |
dom = dom || tinymce.DOM;
|
|
8395 |
|
|
8396 |
itemFocussed = function(evt) {
|
|
8397 |
focussedId = evt.target.id;
|
|
8398 |
};
|
|
8399 |
|
|
8400 |
itemBlurred = function(evt) {
|
|
8401 |
dom.setAttrib(evt.target.id, 'tabindex', '-1');
|
|
8402 |
};
|
|
8403 |
|
|
8404 |
rootFocussed = function(evt) {
|
|
8405 |
var item = dom.get(focussedId);
|
|
8406 |
dom.setAttrib(item, 'tabindex', '0');
|
|
8407 |
item.focus();
|
|
8408 |
};
|
|
8409 |
|
|
8410 |
t.focus = function() {
|
|
8411 |
dom.get(focussedId).focus();
|
|
8412 |
};
|
|
8413 |
|
|
8414 |
t.destroy = function() {
|
|
8415 |
each(items, function(item) {
|
|
8416 |
dom.unbind(dom.get(item.id), 'focus', itemFocussed);
|
|
8417 |
dom.unbind(dom.get(item.id), 'blur', itemBlurred);
|
|
8418 |
});
|
|
8419 |
|
|
8420 |
dom.unbind(dom.get(root), 'focus', rootFocussed);
|
|
8421 |
dom.unbind(dom.get(root), 'keydown', rootKeydown);
|
|
8422 |
|
|
8423 |
items = dom = root = t.focus = itemFocussed = itemBlurred = rootKeydown = rootFocussed = null;
|
|
8424 |
t.destroy = function() {};
|
|
8425 |
};
|
|
8426 |
|
|
8427 |
t.moveFocus = function(dir, evt) {
|
|
8428 |
var idx = -1, controls = t.controls, newFocus;
|
|
8429 |
|
|
8430 |
if (!focussedId)
|
|
8431 |
return;
|
|
8432 |
|
|
8433 |
each(items, function(item, index) {
|
|
8434 |
if (item.id === focussedId) {
|
|
8435 |
idx = index;
|
|
8436 |
return false;
|
|
8437 |
}
|
|
8438 |
});
|
|
8439 |
|
|
8440 |
idx += dir;
|
|
8441 |
if (idx < 0) {
|
|
8442 |
idx = items.length - 1;
|
|
8443 |
} else if (idx >= items.length) {
|
|
8444 |
idx = 0;
|
|
8445 |
}
|
|
8446 |
|
|
8447 |
newFocus = items[idx];
|
|
8448 |
dom.setAttrib(focussedId, 'tabindex', '-1');
|
|
8449 |
dom.setAttrib(newFocus.id, 'tabindex', '0');
|
|
8450 |
dom.get(newFocus.id).focus();
|
|
8451 |
|
|
8452 |
if (settings.actOnFocus) {
|
|
8453 |
settings.onAction(newFocus.id);
|
|
8454 |
}
|
|
8455 |
|
|
8456 |
if (evt)
|
|
8457 |
Event.cancel(evt);
|
|
8458 |
};
|
|
8459 |
|
|
8460 |
rootKeydown = function(evt) {
|
|
8461 |
var DOM_VK_LEFT = 37, DOM_VK_RIGHT = 39, DOM_VK_UP = 38, DOM_VK_DOWN = 40, DOM_VK_ESCAPE = 27, DOM_VK_ENTER = 14, DOM_VK_RETURN = 13, DOM_VK_SPACE = 32;
|
|
8462 |
|
|
8463 |
switch (evt.keyCode) {
|
|
8464 |
case DOM_VK_LEFT:
|
|
8465 |
if (enableLeftRight) t.moveFocus(-1);
|
|
8466 |
break;
|
|
8467 |
|
|
8468 |
case DOM_VK_RIGHT:
|
|
8469 |
if (enableLeftRight) t.moveFocus(1);
|
|
8470 |
break;
|
|
8471 |
|
|
8472 |
case DOM_VK_UP:
|
|
8473 |
if (enableUpDown) t.moveFocus(-1);
|
|
8474 |
break;
|
|
8475 |
|
|
8476 |
case DOM_VK_DOWN:
|
|
8477 |
if (enableUpDown) t.moveFocus(1);
|
|
8478 |
break;
|
|
8479 |
|
|
8480 |
case DOM_VK_ESCAPE:
|
|
8481 |
if (settings.onCancel) {
|
|
8482 |
settings.onCancel();
|
|
8483 |
Event.cancel(evt);
|
|
8484 |
}
|
|
8485 |
break;
|
|
8486 |
|
|
8487 |
case DOM_VK_ENTER:
|
|
8488 |
case DOM_VK_RETURN:
|
|
8489 |
case DOM_VK_SPACE:
|
|
8490 |
if (settings.onAction) {
|
|
8491 |
settings.onAction(focussedId);
|
|
8492 |
Event.cancel(evt);
|
|
8493 |
}
|
|
8494 |
break;
|
|
8495 |
}
|
|
8496 |
};
|
|
8497 |
|
|
8498 |
// Set up state and listeners for each item.
|
|
8499 |
each(items, function(item, idx) {
|
|
8500 |
var tabindex;
|
|
8501 |
|
|
8502 |
if (!item.id) {
|
|
8503 |
item.id = dom.uniqueId('_mce_item_');
|
|
8504 |
}
|
|
8505 |
|
|
8506 |
if (excludeFromTabOrder) {
|
|
8507 |
dom.bind(item.id, 'blur', itemBlurred);
|
|
8508 |
tabindex = '-1';
|
|
8509 |
} else {
|
|
8510 |
tabindex = (idx === 0 ? '0' : '-1');
|
|
8511 |
}
|
|
8512 |
|
|
8513 |
dom.setAttrib(item.id, 'tabindex', tabindex);
|
|
8514 |
dom.bind(dom.get(item.id), 'focus', itemFocussed);
|
|
8515 |
});
|
|
8516 |
|
|
8517 |
// Setup initial state for root element.
|
|
8518 |
if (items[0]){
|
|
8519 |
focussedId = items[0].id;
|
|
8520 |
}
|
|
8521 |
|
|
8522 |
dom.setAttrib(root, 'tabindex', '-1');
|
|
8523 |
|
|
8524 |
// Setup listeners for root element.
|
|
8525 |
dom.bind(dom.get(root), 'focus', rootFocussed);
|
|
8526 |
dom.bind(dom.get(root), 'keydown', rootKeydown);
|
|
8527 |
}
|
|
8528 |
});
|
|
8529 |
})(tinymce);
|
|
8530 |
(function(tinymce) {
|
d9344f
|
8531 |
// Shorten class names
|
S |
8532 |
var DOM = tinymce.DOM, is = tinymce.is;
|
|
8533 |
|
|
8534 |
tinymce.create('tinymce.ui.Control', {
|
a9251b
|
8535 |
Control : function(id, s, editor) {
|
d9344f
|
8536 |
this.id = id;
|
S |
8537 |
this.settings = s = s || {};
|
|
8538 |
this.rendered = false;
|
|
8539 |
this.onRender = new tinymce.util.Dispatcher(this);
|
|
8540 |
this.classPrefix = '';
|
|
8541 |
this.scope = s.scope || this;
|
|
8542 |
this.disabled = 0;
|
|
8543 |
this.active = 0;
|
a9251b
|
8544 |
this.editor = editor;
|
T |
8545 |
},
|
|
8546 |
|
|
8547 |
setAriaProperty : function(property, value) {
|
|
8548 |
var element = DOM.get(this.id + '_aria') || DOM.get(this.id);
|
|
8549 |
if (element) {
|
|
8550 |
DOM.setAttrib(element, 'aria-' + property, !!value);
|
|
8551 |
}
|
|
8552 |
},
|
|
8553 |
|
|
8554 |
focus : function() {
|
|
8555 |
DOM.get(this.id).focus();
|
d9344f
|
8556 |
},
|
S |
8557 |
|
|
8558 |
setDisabled : function(s) {
|
|
8559 |
if (s != this.disabled) {
|
a9251b
|
8560 |
this.setAriaProperty('disabled', s);
|
d9344f
|
8561 |
|
S |
8562 |
this.setState('Disabled', s);
|
|
8563 |
this.setState('Enabled', !s);
|
|
8564 |
this.disabled = s;
|
|
8565 |
}
|
|
8566 |
},
|
|
8567 |
|
|
8568 |
isDisabled : function() {
|
|
8569 |
return this.disabled;
|
|
8570 |
},
|
|
8571 |
|
|
8572 |
setActive : function(s) {
|
|
8573 |
if (s != this.active) {
|
|
8574 |
this.setState('Active', s);
|
|
8575 |
this.active = s;
|
a9251b
|
8576 |
this.setAriaProperty('pressed', s);
|
d9344f
|
8577 |
}
|
S |
8578 |
},
|
|
8579 |
|
|
8580 |
isActive : function() {
|
|
8581 |
return this.active;
|
|
8582 |
},
|
|
8583 |
|
|
8584 |
setState : function(c, s) {
|
|
8585 |
var n = DOM.get(this.id);
|
|
8586 |
|
|
8587 |
c = this.classPrefix + c;
|
|
8588 |
|
|
8589 |
if (s)
|
|
8590 |
DOM.addClass(n, c);
|
|
8591 |
else
|
|
8592 |
DOM.removeClass(n, c);
|
|
8593 |
},
|
|
8594 |
|
|
8595 |
isRendered : function() {
|
|
8596 |
return this.rendered;
|
|
8597 |
},
|
|
8598 |
|
|
8599 |
renderHTML : function() {
|
|
8600 |
},
|
|
8601 |
|
|
8602 |
renderTo : function(n) {
|
|
8603 |
DOM.setHTML(n, this.renderHTML());
|
|
8604 |
},
|
|
8605 |
|
|
8606 |
postRender : function() {
|
|
8607 |
var t = this, b;
|
|
8608 |
|
|
8609 |
// Set pending states
|
|
8610 |
if (is(t.disabled)) {
|
|
8611 |
b = t.disabled;
|
|
8612 |
t.disabled = -1;
|
|
8613 |
t.setDisabled(b);
|
|
8614 |
}
|
|
8615 |
|
|
8616 |
if (is(t.active)) {
|
|
8617 |
b = t.active;
|
|
8618 |
t.active = -1;
|
|
8619 |
t.setActive(b);
|
|
8620 |
}
|
|
8621 |
},
|
|
8622 |
|
|
8623 |
remove : function() {
|
|
8624 |
DOM.remove(this.id);
|
|
8625 |
this.destroy();
|
|
8626 |
},
|
|
8627 |
|
|
8628 |
destroy : function() {
|
|
8629 |
tinymce.dom.Event.clear(this.id);
|
|
8630 |
}
|
58fb65
|
8631 |
});
|
69d05c
|
8632 |
})(tinymce);
|
A |
8633 |
tinymce.create('tinymce.ui.Container:tinymce.ui.Control', {
|
a9251b
|
8634 |
Container : function(id, s, editor) {
|
T |
8635 |
this.parent(id, s, editor);
|
58fb65
|
8636 |
|
d9344f
|
8637 |
this.controls = [];
|
58fb65
|
8638 |
|
d9344f
|
8639 |
this.lookup = {};
|
S |
8640 |
},
|
|
8641 |
|
|
8642 |
add : function(c) {
|
|
8643 |
this.lookup[c.id] = c;
|
|
8644 |
this.controls.push(c);
|
|
8645 |
|
|
8646 |
return c;
|
|
8647 |
},
|
|
8648 |
|
|
8649 |
get : function(n) {
|
|
8650 |
return this.lookup[n];
|
|
8651 |
}
|
58fb65
|
8652 |
});
|
d9344f
|
8653 |
|
69d05c
|
8654 |
|
d9344f
|
8655 |
tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
|
S |
8656 |
Separator : function(id, s) {
|
|
8657 |
this.parent(id, s);
|
|
8658 |
this.classPrefix = 'mceSeparator';
|
a9251b
|
8659 |
this.setDisabled(true);
|
d9344f
|
8660 |
},
|
S |
8661 |
|
|
8662 |
renderHTML : function() {
|
a9251b
|
8663 |
return tinymce.DOM.createHTML('span', {'class' : this.classPrefix, role : 'separator', 'aria-orientation' : 'vertical', tabindex : '-1'});
|
d9344f
|
8664 |
}
|
58fb65
|
8665 |
});
|
69d05c
|
8666 |
|
29da64
|
8667 |
(function(tinymce) {
|
d9344f
|
8668 |
var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
|
S |
8669 |
|
|
8670 |
tinymce.create('tinymce.ui.MenuItem:tinymce.ui.Control', {
|
|
8671 |
MenuItem : function(id, s) {
|
|
8672 |
this.parent(id, s);
|
|
8673 |
this.classPrefix = 'mceMenuItem';
|
|
8674 |
},
|
|
8675 |
|
|
8676 |
setSelected : function(s) {
|
|
8677 |
this.setState('Selected', s);
|
a9251b
|
8678 |
this.setAriaProperty('checked', !!s);
|
d9344f
|
8679 |
this.selected = s;
|
S |
8680 |
},
|
|
8681 |
|
|
8682 |
isSelected : function() {
|
|
8683 |
return this.selected;
|
|
8684 |
},
|
|
8685 |
|
|
8686 |
postRender : function() {
|
|
8687 |
var t = this;
|
|
8688 |
|
|
8689 |
t.parent();
|
|
8690 |
|
|
8691 |
// Set pending state
|
|
8692 |
if (is(t.selected))
|
|
8693 |
t.setSelected(t.selected);
|
|
8694 |
}
|
58fb65
|
8695 |
});
|
29da64
|
8696 |
})(tinymce);
|
69d05c
|
8697 |
|
29da64
|
8698 |
(function(tinymce) {
|
d9344f
|
8699 |
var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
|
S |
8700 |
|
|
8701 |
tinymce.create('tinymce.ui.Menu:tinymce.ui.MenuItem', {
|
|
8702 |
Menu : function(id, s) {
|
|
8703 |
var t = this;
|
|
8704 |
|
|
8705 |
t.parent(id, s);
|
|
8706 |
t.items = {};
|
|
8707 |
t.collapsed = false;
|
|
8708 |
t.menuCount = 0;
|
|
8709 |
t.onAddItem = new tinymce.util.Dispatcher(this);
|
|
8710 |
},
|
|
8711 |
|
|
8712 |
expand : function(d) {
|
|
8713 |
var t = this;
|
|
8714 |
|
|
8715 |
if (d) {
|
|
8716 |
walk(t, function(o) {
|
|
8717 |
if (o.expand)
|
|
8718 |
o.expand();
|
|
8719 |
}, 'items', t);
|
|
8720 |
}
|
|
8721 |
|
|
8722 |
t.collapsed = false;
|
|
8723 |
},
|
|
8724 |
|
|
8725 |
collapse : function(d) {
|
|
8726 |
var t = this;
|
|
8727 |
|
|
8728 |
if (d) {
|
|
8729 |
walk(t, function(o) {
|
|
8730 |
if (o.collapse)
|
|
8731 |
o.collapse();
|
|
8732 |
}, 'items', t);
|
|
8733 |
}
|
|
8734 |
|
|
8735 |
t.collapsed = true;
|
|
8736 |
},
|
|
8737 |
|
|
8738 |
isCollapsed : function() {
|
|
8739 |
return this.collapsed;
|
|
8740 |
},
|
|
8741 |
|
|
8742 |
add : function(o) {
|
|
8743 |
if (!o.settings)
|
|
8744 |
o = new tinymce.ui.MenuItem(o.id || DOM.uniqueId(), o);
|
|
8745 |
|
|
8746 |
this.onAddItem.dispatch(this, o);
|
|
8747 |
|
|
8748 |
return this.items[o.id] = o;
|
|
8749 |
},
|
|
8750 |
|
|
8751 |
addSeparator : function() {
|
|
8752 |
return this.add({separator : true});
|
|
8753 |
},
|
|
8754 |
|
|
8755 |
addMenu : function(o) {
|
|
8756 |
if (!o.collapse)
|
|
8757 |
o = this.createMenu(o);
|
|
8758 |
|
|
8759 |
this.menuCount++;
|
|
8760 |
|
|
8761 |
return this.add(o);
|
|
8762 |
},
|
|
8763 |
|
|
8764 |
hasMenus : function() {
|
|
8765 |
return this.menuCount !== 0;
|
|
8766 |
},
|
|
8767 |
|
|
8768 |
remove : function(o) {
|
|
8769 |
delete this.items[o.id];
|
|
8770 |
},
|
|
8771 |
|
|
8772 |
removeAll : function() {
|
|
8773 |
var t = this;
|
|
8774 |
|
|
8775 |
walk(t, function(o) {
|
|
8776 |
if (o.removeAll)
|
|
8777 |
o.removeAll();
|
|
8778 |
else
|
|
8779 |
o.remove();
|
|
8780 |
|
|
8781 |
o.destroy();
|
|
8782 |
}, 'items', t);
|
|
8783 |
|
|
8784 |
t.items = {};
|
|
8785 |
},
|
|
8786 |
|
|
8787 |
createMenu : function(o) {
|
|
8788 |
var m = new tinymce.ui.Menu(o.id || DOM.uniqueId(), o);
|
|
8789 |
|
|
8790 |
m.onAddItem.add(this.onAddItem.dispatch, this.onAddItem);
|
|
8791 |
|
|
8792 |
return m;
|
|
8793 |
}
|
58fb65
|
8794 |
});
|
69d05c
|
8795 |
})(tinymce);
|
A |
8796 |
(function(tinymce) {
|
d9344f
|
8797 |
var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, Event = tinymce.dom.Event, Element = tinymce.dom.Element;
|
S |
8798 |
|
|
8799 |
tinymce.create('tinymce.ui.DropMenu:tinymce.ui.Menu', {
|
|
8800 |
DropMenu : function(id, s) {
|
|
8801 |
s = s || {};
|
|
8802 |
s.container = s.container || DOM.doc.body;
|
|
8803 |
s.offset_x = s.offset_x || 0;
|
|
8804 |
s.offset_y = s.offset_y || 0;
|
|
8805 |
s.vp_offset_x = s.vp_offset_x || 0;
|
|
8806 |
s.vp_offset_y = s.vp_offset_y || 0;
|
|
8807 |
|
|
8808 |
if (is(s.icons) && !s.icons)
|
|
8809 |
s['class'] += ' mceNoIcons';
|
|
8810 |
|
|
8811 |
this.parent(id, s);
|
|
8812 |
this.onShowMenu = new tinymce.util.Dispatcher(this);
|
|
8813 |
this.onHideMenu = new tinymce.util.Dispatcher(this);
|
|
8814 |
this.classPrefix = 'mceMenu';
|
|
8815 |
},
|
|
8816 |
|
|
8817 |
createMenu : function(s) {
|
|
8818 |
var t = this, cs = t.settings, m;
|
|
8819 |
|
|
8820 |
s.container = s.container || cs.container;
|
|
8821 |
s.parent = t;
|
|
8822 |
s.constrain = s.constrain || cs.constrain;
|
|
8823 |
s['class'] = s['class'] || cs['class'];
|
|
8824 |
s.vp_offset_x = s.vp_offset_x || cs.vp_offset_x;
|
|
8825 |
s.vp_offset_y = s.vp_offset_y || cs.vp_offset_y;
|
a9251b
|
8826 |
s.keyboard_focus = cs.keyboard_focus;
|
d9344f
|
8827 |
m = new tinymce.ui.DropMenu(s.id || DOM.uniqueId(), s);
|
S |
8828 |
|
|
8829 |
m.onAddItem.add(t.onAddItem.dispatch, t.onAddItem);
|
|
8830 |
|
|
8831 |
return m;
|
a9251b
|
8832 |
},
|
T |
8833 |
|
|
8834 |
focus : function() {
|
|
8835 |
var t = this;
|
|
8836 |
if (t.keyboardNav) {
|
|
8837 |
t.keyboardNav.focus();
|
|
8838 |
}
|
d9344f
|
8839 |
},
|
S |
8840 |
|
|
8841 |
update : function() {
|
|
8842 |
var t = this, s = t.settings, tb = DOM.get('menu_' + t.id + '_tbl'), co = DOM.get('menu_' + t.id + '_co'), tw, th;
|
|
8843 |
|
|
8844 |
tw = s.max_width ? Math.min(tb.clientWidth, s.max_width) : tb.clientWidth;
|
|
8845 |
th = s.max_height ? Math.min(tb.clientHeight, s.max_height) : tb.clientHeight;
|
|
8846 |
|
|
8847 |
if (!DOM.boxModel)
|
|
8848 |
t.element.setStyles({width : tw + 2, height : th + 2});
|
|
8849 |
else
|
|
8850 |
t.element.setStyles({width : tw, height : th});
|
|
8851 |
|
|
8852 |
if (s.max_width)
|
|
8853 |
DOM.setStyle(co, 'width', tw);
|
|
8854 |
|
|
8855 |
if (s.max_height) {
|
|
8856 |
DOM.setStyle(co, 'height', th);
|
|
8857 |
|
|
8858 |
if (tb.clientHeight < s.max_height)
|
|
8859 |
DOM.setStyle(co, 'overflow', 'hidden');
|
|
8860 |
}
|
|
8861 |
},
|
|
8862 |
|
|
8863 |
showMenu : function(x, y, px) {
|
|
8864 |
var t = this, s = t.settings, co, vp = DOM.getViewPort(), w, h, mx, my, ot = 2, dm, tb, cp = t.classPrefix;
|
|
8865 |
|
|
8866 |
t.collapse(1);
|
|
8867 |
|
|
8868 |
if (t.isMenuVisible)
|
|
8869 |
return;
|
|
8870 |
|
|
8871 |
if (!t.rendered) {
|
|
8872 |
co = DOM.add(t.settings.container, t.renderNode());
|
|
8873 |
|
|
8874 |
each(t.items, function(o) {
|
|
8875 |
o.postRender();
|
|
8876 |
});
|
|
8877 |
|
|
8878 |
t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
|
|
8879 |
} else
|
|
8880 |
co = DOM.get('menu_' + t.id);
|
|
8881 |
|
|
8882 |
// Move layer out of sight unless it's Opera since it scrolls to top of page due to an bug
|
|
8883 |
if (!tinymce.isOpera)
|
|
8884 |
DOM.setStyles(co, {left : -0xFFFF , top : -0xFFFF});
|
|
8885 |
|
|
8886 |
DOM.show(co);
|
|
8887 |
t.update();
|
|
8888 |
|
|
8889 |
x += s.offset_x || 0;
|
|
8890 |
y += s.offset_y || 0;
|
|
8891 |
vp.w -= 4;
|
|
8892 |
vp.h -= 4;
|
|
8893 |
|
|
8894 |
// Move inside viewport if not submenu
|
|
8895 |
if (s.constrain) {
|
|
8896 |
w = co.clientWidth - ot;
|
|
8897 |
h = co.clientHeight - ot;
|
|
8898 |
mx = vp.x + vp.w;
|
|
8899 |
my = vp.y + vp.h;
|
|
8900 |
|
|
8901 |
if ((x + s.vp_offset_x + w) > mx)
|
|
8902 |
x = px ? px - w : Math.max(0, (mx - s.vp_offset_x) - w);
|
|
8903 |
|
|
8904 |
if ((y + s.vp_offset_y + h) > my)
|
|
8905 |
y = Math.max(0, (my - s.vp_offset_y) - h);
|
|
8906 |
}
|
|
8907 |
|
|
8908 |
DOM.setStyles(co, {left : x , top : y});
|
|
8909 |
t.element.update();
|
|
8910 |
|
|
8911 |
t.isMenuVisible = 1;
|
18240a
|
8912 |
t.mouseClickFunc = Event.add(co, 'click', function(e) {
|
d9344f
|
8913 |
var m;
|
S |
8914 |
|
|
8915 |
e = e.target;
|
|
8916 |
|
29da64
|
8917 |
if (e && (e = DOM.getParent(e, 'tr')) && !DOM.hasClass(e, cp + 'ItemSub')) {
|
d9344f
|
8918 |
m = t.items[e.id];
|
S |
8919 |
|
|
8920 |
if (m.isDisabled())
|
|
8921 |
return;
|
|
8922 |
|
|
8923 |
dm = t;
|
|
8924 |
|
|
8925 |
while (dm) {
|
|
8926 |
if (dm.hideMenu)
|
|
8927 |
dm.hideMenu();
|
|
8928 |
|
|
8929 |
dm = dm.settings.parent;
|
|
8930 |
}
|
|
8931 |
|
|
8932 |
if (m.settings.onclick)
|
|
8933 |
m.settings.onclick(e);
|
|
8934 |
|
|
8935 |
return Event.cancel(e); // Cancel to fix onbeforeunload problem
|
|
8936 |
}
|
|
8937 |
});
|
|
8938 |
|
|
8939 |
if (t.hasMenus()) {
|
|
8940 |
t.mouseOverFunc = Event.add(co, 'mouseover', function(e) {
|
|
8941 |
var m, r, mi;
|
|
8942 |
|
|
8943 |
e = e.target;
|
29da64
|
8944 |
if (e && (e = DOM.getParent(e, 'tr'))) {
|
d9344f
|
8945 |
m = t.items[e.id];
|
S |
8946 |
|
|
8947 |
if (t.lastMenu)
|
|
8948 |
t.lastMenu.collapse(1);
|
|
8949 |
|
|
8950 |
if (m.isDisabled())
|
|
8951 |
return;
|
|
8952 |
|
|
8953 |
if (e && DOM.hasClass(e, cp + 'ItemSub')) {
|
|
8954 |
//p = DOM.getPos(s.container);
|
|
8955 |
r = DOM.getRect(e);
|
|
8956 |
m.showMenu((r.x + r.w - ot), r.y - ot, r.x);
|
|
8957 |
t.lastMenu = m;
|
|
8958 |
DOM.addClass(DOM.get(m.id).firstChild, cp + 'ItemActive');
|
|
8959 |
}
|
|
8960 |
}
|
|
8961 |
});
|
|
8962 |
}
|
a9251b
|
8963 |
|
T |
8964 |
Event.add(co, 'keydown', t._keyHandler, t);
|
d9344f
|
8965 |
|
S |
8966 |
t.onShowMenu.dispatch(t);
|
|
8967 |
|
a9251b
|
8968 |
if (s.keyboard_focus) {
|
T |
8969 |
t._setupKeyboardNav();
|
d9344f
|
8970 |
}
|
S |
8971 |
},
|
|
8972 |
|
|
8973 |
hideMenu : function(c) {
|
|
8974 |
var t = this, co = DOM.get('menu_' + t.id), e;
|
|
8975 |
|
|
8976 |
if (!t.isMenuVisible)
|
|
8977 |
return;
|
|
8978 |
|
a9251b
|
8979 |
if (t.keyboardNav) t.keyboardNav.destroy();
|
d9344f
|
8980 |
Event.remove(co, 'mouseover', t.mouseOverFunc);
|
18240a
|
8981 |
Event.remove(co, 'click', t.mouseClickFunc);
|
d9344f
|
8982 |
Event.remove(co, 'keydown', t._keyHandler);
|
S |
8983 |
DOM.hide(co);
|
|
8984 |
t.isMenuVisible = 0;
|
|
8985 |
|
|
8986 |
if (!c)
|
|
8987 |
t.collapse(1);
|
|
8988 |
|
|
8989 |
if (t.element)
|
|
8990 |
t.element.hide();
|
|
8991 |
|
|
8992 |
if (e = DOM.get(t.id))
|
|
8993 |
DOM.removeClass(e.firstChild, t.classPrefix + 'ItemActive');
|
|
8994 |
|
|
8995 |
t.onHideMenu.dispatch(t);
|
|
8996 |
},
|
|
8997 |
|
|
8998 |
add : function(o) {
|
|
8999 |
var t = this, co;
|
|
9000 |
|
|
9001 |
o = t.parent(o);
|
|
9002 |
|
|
9003 |
if (t.isRendered && (co = DOM.get('menu_' + t.id)))
|
|
9004 |
t._add(DOM.select('tbody', co)[0], o);
|
|
9005 |
|
|
9006 |
return o;
|
|
9007 |
},
|
|
9008 |
|
|
9009 |
collapse : function(d) {
|
|
9010 |
this.parent(d);
|
|
9011 |
this.hideMenu(1);
|
|
9012 |
},
|
|
9013 |
|
|
9014 |
remove : function(o) {
|
|
9015 |
DOM.remove(o.id);
|
|
9016 |
this.destroy();
|
|
9017 |
|
|
9018 |
return this.parent(o);
|
|
9019 |
},
|
|
9020 |
|
|
9021 |
destroy : function() {
|
|
9022 |
var t = this, co = DOM.get('menu_' + t.id);
|
|
9023 |
|
a9251b
|
9024 |
if (t.keyboardNav) t.keyboardNav.destroy();
|
d9344f
|
9025 |
Event.remove(co, 'mouseover', t.mouseOverFunc);
|
a9251b
|
9026 |
Event.remove(DOM.select('a', co), 'focus', t.mouseOverFunc);
|
d9344f
|
9027 |
Event.remove(co, 'click', t.mouseClickFunc);
|
a9251b
|
9028 |
Event.remove(co, 'keydown', t._keyHandler);
|
d9344f
|
9029 |
|
S |
9030 |
if (t.element)
|
|
9031 |
t.element.remove();
|
|
9032 |
|
|
9033 |
DOM.remove(co);
|
|
9034 |
},
|
|
9035 |
|
|
9036 |
renderNode : function() {
|
|
9037 |
var t = this, s = t.settings, n, tb, co, w;
|
|
9038 |
|
a9251b
|
9039 |
w = DOM.create('div', {role: 'listbox', id : 'menu_' + t.id, 'class' : s['class'], 'style' : 'position:absolute;left:0;top:0;z-index:200000;outline:0'});
|
T |
9040 |
if (t.settings.parent) {
|
|
9041 |
DOM.setAttrib(w, 'aria-parent', 'menu_' + t.settings.parent.id);
|
|
9042 |
}
|
|
9043 |
co = DOM.add(w, 'div', {role: 'presentation', id : 'menu_' + t.id + '_co', 'class' : t.classPrefix + (s['class'] ? ' ' + s['class'] : '')});
|
d9344f
|
9044 |
t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
|
S |
9045 |
|
|
9046 |
if (s.menu_line)
|
|
9047 |
DOM.add(co, 'span', {'class' : t.classPrefix + 'Line'});
|
|
9048 |
|
|
9049 |
// n = DOM.add(co, 'div', {id : 'menu_' + t.id + '_co', 'class' : 'mceMenuContainer'});
|
a9251b
|
9050 |
n = DOM.add(co, 'table', {role: 'presentation', id : 'menu_' + t.id + '_tbl', border : 0, cellPadding : 0, cellSpacing : 0});
|
d9344f
|
9051 |
tb = DOM.add(n, 'tbody');
|
S |
9052 |
|
|
9053 |
each(t.items, function(o) {
|
|
9054 |
t._add(tb, o);
|
|
9055 |
});
|
|
9056 |
|
|
9057 |
t.rendered = true;
|
|
9058 |
|
|
9059 |
return w;
|
|
9060 |
},
|
|
9061 |
|
|
9062 |
// Internal functions
|
a9251b
|
9063 |
_setupKeyboardNav : function(){
|
T |
9064 |
var contextMenu, menuItems, t=this;
|
|
9065 |
contextMenu = DOM.select('#menu_' + t.id)[0];
|
|
9066 |
menuItems = DOM.select('a[role=option]', 'menu_' + t.id);
|
|
9067 |
menuItems.splice(0,0,contextMenu);
|
|
9068 |
t.keyboardNav = new tinymce.ui.KeyboardNavigation({
|
|
9069 |
root: 'menu_' + t.id,
|
|
9070 |
items: menuItems,
|
|
9071 |
onCancel: function() {
|
|
9072 |
t.hideMenu();
|
|
9073 |
},
|
|
9074 |
enableUpDown: true
|
|
9075 |
});
|
|
9076 |
contextMenu.focus();
|
|
9077 |
},
|
d9344f
|
9078 |
|
a9251b
|
9079 |
_keyHandler : function(evt) {
|
T |
9080 |
var t = this, e;
|
|
9081 |
switch (evt.keyCode) {
|
|
9082 |
case 37: // Left
|
|
9083 |
if (t.settings.parent) {
|
|
9084 |
t.hideMenu();
|
|
9085 |
t.settings.parent.focus();
|
|
9086 |
Event.cancel(evt);
|
|
9087 |
}
|
|
9088 |
break;
|
|
9089 |
case 39: // Right
|
|
9090 |
if (t.mouseOverFunc)
|
|
9091 |
t.mouseOverFunc(evt);
|
|
9092 |
break;
|
18240a
|
9093 |
}
|
d9344f
|
9094 |
},
|
S |
9095 |
|
|
9096 |
_add : function(tb, o) {
|
29da64
|
9097 |
var n, s = o.settings, a, ro, it, cp = this.classPrefix, ic;
|
d9344f
|
9098 |
|
S |
9099 |
if (s.separator) {
|
|
9100 |
ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'ItemSeparator'});
|
|
9101 |
DOM.add(ro, 'td', {'class' : cp + 'ItemSeparator'});
|
|
9102 |
|
|
9103 |
if (n = ro.previousSibling)
|
|
9104 |
DOM.addClass(n, 'mceLast');
|
|
9105 |
|
|
9106 |
return;
|
|
9107 |
}
|
|
9108 |
|
|
9109 |
n = ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'Item ' + cp + 'ItemEnabled'});
|
a9251b
|
9110 |
n = it = DOM.add(n, s.titleItem ? 'th' : 'td');
|
T |
9111 |
n = a = DOM.add(n, 'a', {id: o.id + '_aria', role: s.titleItem ? 'presentation' : 'option', href : 'javascript:;', onclick : "return false;", onmousedown : 'return false;'});
|
|
9112 |
|
|
9113 |
if (s.parent) {
|
|
9114 |
DOM.setAttrib(a, 'aria-haspopup', 'true');
|
|
9115 |
DOM.setAttrib(a, 'aria-owns', 'menu_' + o.id);
|
|
9116 |
}
|
d9344f
|
9117 |
|
S |
9118 |
DOM.addClass(it, s['class']);
|
|
9119 |
// n = DOM.add(n, 'span', {'class' : 'item'});
|
29da64
|
9120 |
|
A |
9121 |
ic = DOM.add(n, 'span', {'class' : 'mceIcon' + (s.icon ? ' mce_' + s.icon : '')});
|
|
9122 |
|
|
9123 |
if (s.icon_src)
|
|
9124 |
DOM.add(ic, 'img', {src : s.icon_src});
|
|
9125 |
|
d9344f
|
9126 |
n = DOM.add(n, s.element || 'span', {'class' : 'mceText', title : o.settings.title}, o.settings.title);
|
S |
9127 |
|
|
9128 |
if (o.settings.style)
|
|
9129 |
DOM.setAttrib(n, 'style', o.settings.style);
|
|
9130 |
|
|
9131 |
if (tb.childNodes.length == 1)
|
|
9132 |
DOM.addClass(ro, 'mceFirst');
|
|
9133 |
|
|
9134 |
if ((n = ro.previousSibling) && DOM.hasClass(n, cp + 'ItemSeparator'))
|
|
9135 |
DOM.addClass(ro, 'mceFirst');
|
|
9136 |
|
|
9137 |
if (o.collapse)
|
|
9138 |
DOM.addClass(ro, cp + 'ItemSub');
|
|
9139 |
|
|
9140 |
if (n = ro.previousSibling)
|
|
9141 |
DOM.removeClass(n, 'mceLast');
|
|
9142 |
|
|
9143 |
DOM.addClass(ro, 'mceLast');
|
|
9144 |
}
|
58fb65
|
9145 |
});
|
69d05c
|
9146 |
})(tinymce);
|
A |
9147 |
(function(tinymce) {
|
d9344f
|
9148 |
var DOM = tinymce.DOM;
|
S |
9149 |
|
|
9150 |
tinymce.create('tinymce.ui.Button:tinymce.ui.Control', {
|
a9251b
|
9151 |
Button : function(id, s, ed) {
|
T |
9152 |
this.parent(id, s, ed);
|
d9344f
|
9153 |
this.classPrefix = 'mceButton';
|
S |
9154 |
},
|
|
9155 |
|
|
9156 |
renderHTML : function() {
|
18240a
|
9157 |
var cp = this.classPrefix, s = this.settings, h, l;
|
A |
9158 |
|
|
9159 |
l = DOM.encode(s.label || '');
|
a9251b
|
9160 |
h = '<a role="button" id="' + this.id + '" href="javascript:;" class="' + cp + ' ' + cp + 'Enabled ' + s['class'] + (l ? ' ' + cp + 'Labeled' : '') +'" onmousedown="return false;" onclick="return false;" aria-labelledby="' + this.id + '_voice" title="' + DOM.encode(s.title) + '">';
|
d9344f
|
9161 |
|
S |
9162 |
if (s.image)
|
a9251b
|
9163 |
h += '<img class="mceIcon" src="' + s.image + '" alt="' + DOM.encode(s.title) + '" />' + l;
|
d9344f
|
9164 |
else
|
a9251b
|
9165 |
h += '<span class="mceIcon ' + s['class'] + '"></span>' + (l ? '<span class="' + cp + 'Label">' + l + '</span>' : '');
|
d9344f
|
9166 |
|
a9251b
|
9167 |
h += '<span class="mceVoiceLabel mceIconOnly" style="display: none;" id="' + this.id + '_voice">' + s.title + '</span>';
|
T |
9168 |
h += '</a>';
|
d9344f
|
9169 |
return h;
|
S |
9170 |
},
|
|
9171 |
|
|
9172 |
postRender : function() {
|
|
9173 |
var t = this, s = t.settings;
|
|
9174 |
|
|
9175 |
tinymce.dom.Event.add(t.id, 'click', function(e) {
|
|
9176 |
if (!t.isDisabled())
|
|
9177 |
return s.onclick.call(s.scope, e);
|
|
9178 |
});
|
|
9179 |
}
|
58fb65
|
9180 |
});
|
29da64
|
9181 |
})(tinymce);
|
69d05c
|
9182 |
|
29da64
|
9183 |
(function(tinymce) {
|
d9344f
|
9184 |
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;
|
S |
9185 |
|
|
9186 |
tinymce.create('tinymce.ui.ListBox:tinymce.ui.Control', {
|
a9251b
|
9187 |
ListBox : function(id, s, ed) {
|
d9344f
|
9188 |
var t = this;
|
S |
9189 |
|
a9251b
|
9190 |
t.parent(id, s, ed);
|
58fb65
|
9191 |
|
d9344f
|
9192 |
t.items = [];
|
58fb65
|
9193 |
|
d9344f
|
9194 |
t.onChange = new Dispatcher(t);
|
58fb65
|
9195 |
|
d9344f
|
9196 |
t.onPostRender = new Dispatcher(t);
|
58fb65
|
9197 |
|
d9344f
|
9198 |
t.onAdd = new Dispatcher(t);
|
58fb65
|
9199 |
|
d9344f
|
9200 |
t.onRenderMenu = new tinymce.util.Dispatcher(this);
|
58fb65
|
9201 |
|
d9344f
|
9202 |
t.classPrefix = 'mceListBox';
|
S |
9203 |
},
|
|
9204 |
|
29da64
|
9205 |
select : function(va) {
|
A |
9206 |
var t = this, fv, f;
|
|
9207 |
|
|
9208 |
if (va == undefined)
|
|
9209 |
return t.selectByIndex(-1);
|
|
9210 |
|
|
9211 |
// Is string or number make function selector
|
|
9212 |
if (va && va.call)
|
|
9213 |
f = va;
|
|
9214 |
else {
|
|
9215 |
f = function(v) {
|
|
9216 |
return v == va;
|
|
9217 |
};
|
|
9218 |
}
|
d9344f
|
9219 |
|
S |
9220 |
// Do we need to do something?
|
29da64
|
9221 |
if (va != t.selectedValue) {
|
d9344f
|
9222 |
// Find item
|
29da64
|
9223 |
each(t.items, function(o, i) {
|
A |
9224 |
if (f(o.value)) {
|
d9344f
|
9225 |
fv = 1;
|
29da64
|
9226 |
t.selectByIndex(i);
|
d9344f
|
9227 |
return false;
|
S |
9228 |
}
|
|
9229 |
});
|
|
9230 |
|
29da64
|
9231 |
if (!fv)
|
A |
9232 |
t.selectByIndex(-1);
|
|
9233 |
}
|
|
9234 |
},
|
|
9235 |
|
|
9236 |
selectByIndex : function(idx) {
|
|
9237 |
var t = this, e, o;
|
|
9238 |
|
|
9239 |
if (idx != t.selectedIndex) {
|
|
9240 |
e = DOM.get(t.id + '_text');
|
|
9241 |
o = t.items[idx];
|
|
9242 |
|
|
9243 |
if (o) {
|
|
9244 |
t.selectedValue = o.value;
|
|
9245 |
t.selectedIndex = idx;
|
|
9246 |
DOM.setHTML(e, DOM.encode(o.title));
|
|
9247 |
DOM.removeClass(e, 'mceTitle');
|
a9251b
|
9248 |
DOM.setAttrib(t.id, 'aria-valuenow', o.title);
|
29da64
|
9249 |
} else {
|
d9344f
|
9250 |
DOM.setHTML(e, DOM.encode(t.settings.title));
|
S |
9251 |
DOM.addClass(e, 'mceTitle');
|
29da64
|
9252 |
t.selectedValue = t.selectedIndex = null;
|
a9251b
|
9253 |
DOM.setAttrib(t.id, 'aria-valuenow', t.settings.title);
|
29da64
|
9254 |
}
|
A |
9255 |
e = 0;
|
|
9256 |
}
|
d9344f
|
9257 |
},
|
S |
9258 |
|
|
9259 |
add : function(n, v, o) {
|
|
9260 |
var t = this;
|
|
9261 |
|
|
9262 |
o = o || {};
|
|
9263 |
o = tinymce.extend(o, {
|
|
9264 |
title : n,
|
|
9265 |
value : v
|
|
9266 |
});
|
|
9267 |
|
|
9268 |
t.items.push(o);
|
|
9269 |
t.onAdd.dispatch(t, o);
|
|
9270 |
},
|
|
9271 |
|
|
9272 |
getLength : function() {
|
|
9273 |
return this.items.length;
|
|
9274 |
},
|
|
9275 |
|
|
9276 |
renderHTML : function() {
|
|
9277 |
var h = '', t = this, s = t.settings, cp = t.classPrefix;
|
|
9278 |
|
a9251b
|
9279 |
h = '<span role="button" aria-haspopup="true" aria-labelledby="' + t.id +'_text" aria-describedby="' + t.id + '_voiceDesc"><table role="presentation" tabindex="0" id="' + t.id + '" cellpadding="0" cellspacing="0" class="' + cp + ' ' + cp + 'Enabled' + (s['class'] ? (' ' + s['class']) : '') + '"><tbody><tr>';
|
T |
9280 |
h += '<td>' + DOM.createHTML('span', {id: t.id + '_voiceDesc', 'class': 'voiceLabel', style:'display:none;'}, t.settings.title);
|
|
9281 |
h += DOM.createHTML('a', {id : t.id + '_text', tabindex : -1, href : 'javascript:;', 'class' : 'mceText', onclick : "return false;", onmousedown : 'return false;'}, DOM.encode(t.settings.title)) + '</td>';
|
|
9282 |
h += '<td>' + DOM.createHTML('a', {id : t.id + '_open', tabindex : -1, href : 'javascript:;', 'class' : 'mceOpen', onclick : "return false;", onmousedown : 'return false;'}, '<span><span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span></span>') + '</td>';
|
|
9283 |
h += '</tr></tbody></table></span>';
|
d9344f
|
9284 |
|
S |
9285 |
return h;
|
|
9286 |
},
|
|
9287 |
|
|
9288 |
showMenu : function() {
|
|
9289 |
var t = this, p1, p2, e = DOM.get(this.id), m;
|
|
9290 |
|
|
9291 |
if (t.isDisabled() || t.items.length == 0)
|
|
9292 |
return;
|
|
9293 |
|
18240a
|
9294 |
if (t.menu && t.menu.isMenuVisible)
|
A |
9295 |
return t.hideMenu();
|
|
9296 |
|
d9344f
|
9297 |
if (!t.isMenuRendered) {
|
S |
9298 |
t.renderMenu();
|
|
9299 |
t.isMenuRendered = true;
|
|
9300 |
}
|
|
9301 |
|
|
9302 |
p1 = DOM.getPos(this.settings.menu_container);
|
|
9303 |
p2 = DOM.getPos(e);
|
|
9304 |
|
|
9305 |
m = t.menu;
|
|
9306 |
m.settings.offset_x = p2.x;
|
|
9307 |
m.settings.offset_y = p2.y;
|
18240a
|
9308 |
m.settings.keyboard_focus = !tinymce.isOpera; // Opera is buggy when it comes to auto focus
|
d9344f
|
9309 |
|
S |
9310 |
// Select in menu
|
|
9311 |
if (t.oldID)
|
|
9312 |
m.items[t.oldID].setSelected(0);
|
|
9313 |
|
|
9314 |
each(t.items, function(o) {
|
|
9315 |
if (o.value === t.selectedValue) {
|
|
9316 |
m.items[o.id].setSelected(1);
|
|
9317 |
t.oldID = o.id;
|
|
9318 |
}
|
|
9319 |
});
|
|
9320 |
|
|
9321 |
m.showMenu(0, e.clientHeight);
|
|
9322 |
|
|
9323 |
Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
|
|
9324 |
DOM.addClass(t.id, t.classPrefix + 'Selected');
|
18240a
|
9325 |
|
A |
9326 |
//DOM.get(t.id + '_text').focus();
|
d9344f
|
9327 |
},
|
S |
9328 |
|
|
9329 |
hideMenu : function(e) {
|
|
9330 |
var t = this;
|
18240a
|
9331 |
|
69d05c
|
9332 |
if (t.menu && t.menu.isMenuVisible) {
|
a9251b
|
9333 |
DOM.removeClass(t.id, t.classPrefix + 'Selected');
|
T |
9334 |
|
69d05c
|
9335 |
// Prevent double toogles by canceling the mouse click event to the button
|
A |
9336 |
if (e && e.type == "mousedown" && (e.target.id == t.id + '_text' || e.target.id == t.id + '_open'))
|
|
9337 |
return;
|
d9344f
|
9338 |
|
69d05c
|
9339 |
if (!e || !DOM.getParent(e.target, '.mceMenu')) {
|
A |
9340 |
DOM.removeClass(t.id, t.classPrefix + 'Selected');
|
|
9341 |
Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
|
d9344f
|
9342 |
t.menu.hideMenu();
|
69d05c
|
9343 |
}
|
d9344f
|
9344 |
}
|
S |
9345 |
},
|
|
9346 |
|
|
9347 |
renderMenu : function() {
|
|
9348 |
var t = this, m;
|
|
9349 |
|
|
9350 |
m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
|
|
9351 |
menu_line : 1,
|
|
9352 |
'class' : t.classPrefix + 'Menu mceNoIcons',
|
|
9353 |
max_width : 150,
|
|
9354 |
max_height : 150
|
|
9355 |
});
|
|
9356 |
|
a9251b
|
9357 |
m.onHideMenu.add(function() {
|
T |
9358 |
t.hideMenu();
|
|
9359 |
t.focus();
|
|
9360 |
});
|
d9344f
|
9361 |
|
S |
9362 |
m.add({
|
|
9363 |
title : t.settings.title,
|
18240a
|
9364 |
'class' : 'mceMenuItemTitle',
|
A |
9365 |
onclick : function() {
|
|
9366 |
if (t.settings.onselect('') !== false)
|
|
9367 |
t.select(''); // Must be runned after
|
|
9368 |
}
|
|
9369 |
});
|
d9344f
|
9370 |
|
S |
9371 |
each(t.items, function(o) {
|
69d05c
|
9372 |
// No value then treat it as a title
|
A |
9373 |
if (o.value === undefined) {
|
|
9374 |
m.add({
|
|
9375 |
title : o.title,
|
|
9376 |
'class' : 'mceMenuItemTitle',
|
|
9377 |
onclick : function() {
|
|
9378 |
if (t.settings.onselect('') !== false)
|
|
9379 |
t.select(''); // Must be runned after
|
|
9380 |
}
|
|
9381 |
});
|
|
9382 |
} else {
|
|
9383 |
o.id = DOM.uniqueId();
|
|
9384 |
o.onclick = function() {
|
|
9385 |
if (t.settings.onselect(o.value) !== false)
|
|
9386 |
t.select(o.value); // Must be runned after
|
|
9387 |
};
|
d9344f
|
9388 |
|
69d05c
|
9389 |
m.add(o);
|
A |
9390 |
}
|
d9344f
|
9391 |
});
|
S |
9392 |
|
|
9393 |
t.onRenderMenu.dispatch(t, m);
|
|
9394 |
t.menu = m;
|
|
9395 |
},
|
|
9396 |
|
|
9397 |
postRender : function() {
|
|
9398 |
var t = this, cp = t.classPrefix;
|
|
9399 |
|
|
9400 |
Event.add(t.id, 'click', t.showMenu, t);
|
a9251b
|
9401 |
Event.add(t.id, 'keydown', function(evt) {
|
T |
9402 |
if (evt.keyCode == 32) { // Space
|
|
9403 |
t.showMenu(evt);
|
|
9404 |
Event.cancel(evt);
|
|
9405 |
}
|
|
9406 |
});
|
|
9407 |
Event.add(t.id, 'focus', function() {
|
18240a
|
9408 |
if (!t._focused) {
|
a9251b
|
9409 |
t.keyDownHandler = Event.add(t.id, 'keydown', function(e) {
|
T |
9410 |
if (e.keyCode == 40) {
|
|
9411 |
t.showMenu();
|
|
9412 |
Event.cancel(e);
|
|
9413 |
}
|
|
9414 |
});
|
|
9415 |
t.keyPressHandler = Event.add(t.id, 'keypress', function(e) {
|
|
9416 |
var v;
|
|
9417 |
if (e.keyCode == 13) {
|
18240a
|
9418 |
// Fake select on enter
|
A |
9419 |
v = t.selectedValue;
|
|
9420 |
t.selectedValue = null; // Needs to be null to fake change
|
a9251b
|
9421 |
Event.cancel(e);
|
18240a
|
9422 |
t.settings.onselect(v);
|
A |
9423 |
}
|
|
9424 |
});
|
|
9425 |
}
|
|
9426 |
|
|
9427 |
t._focused = 1;
|
|
9428 |
});
|
a9251b
|
9429 |
Event.add(t.id, 'blur', function() {
|
T |
9430 |
Event.remove(t.id, 'keydown', t.keyDownHandler);
|
|
9431 |
Event.remove(t.id, 'keypress', t.keyPressHandler);
|
|
9432 |
t._focused = 0;
|
|
9433 |
});
|
d9344f
|
9434 |
|
S |
9435 |
// Old IE doesn't have hover on all elements
|
|
9436 |
if (tinymce.isIE6 || !DOM.boxModel) {
|
|
9437 |
Event.add(t.id, 'mouseover', function() {
|
|
9438 |
if (!DOM.hasClass(t.id, cp + 'Disabled'))
|
|
9439 |
DOM.addClass(t.id, cp + 'Hover');
|
|
9440 |
});
|
|
9441 |
|
|
9442 |
Event.add(t.id, 'mouseout', function() {
|
|
9443 |
if (!DOM.hasClass(t.id, cp + 'Disabled'))
|
|
9444 |
DOM.removeClass(t.id, cp + 'Hover');
|
|
9445 |
});
|
|
9446 |
}
|
|
9447 |
|
|
9448 |
t.onPostRender.dispatch(t, DOM.get(t.id));
|
|
9449 |
},
|
|
9450 |
|
|
9451 |
destroy : function() {
|
|
9452 |
this.parent();
|
|
9453 |
|
|
9454 |
Event.clear(this.id + '_text');
|
58fb65
|
9455 |
Event.clear(this.id + '_open');
|
d9344f
|
9456 |
}
|
58fb65
|
9457 |
});
|
69d05c
|
9458 |
})(tinymce);
|
A |
9459 |
(function(tinymce) {
|
d9344f
|
9460 |
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;
|
S |
9461 |
|
|
9462 |
tinymce.create('tinymce.ui.NativeListBox:tinymce.ui.ListBox', {
|
|
9463 |
NativeListBox : function(id, s) {
|
|
9464 |
this.parent(id, s);
|
|
9465 |
this.classPrefix = 'mceNativeListBox';
|
|
9466 |
},
|
|
9467 |
|
|
9468 |
setDisabled : function(s) {
|
|
9469 |
DOM.get(this.id).disabled = s;
|
a9251b
|
9470 |
this.setAriaProperty('disabled', s);
|
d9344f
|
9471 |
},
|
S |
9472 |
|
|
9473 |
isDisabled : function() {
|
|
9474 |
return DOM.get(this.id).disabled;
|
|
9475 |
},
|
|
9476 |
|
29da64
|
9477 |
select : function(va) {
|
A |
9478 |
var t = this, fv, f;
|
d9344f
|
9479 |
|
29da64
|
9480 |
if (va == undefined)
|
A |
9481 |
return t.selectByIndex(-1);
|
d9344f
|
9482 |
|
29da64
|
9483 |
// Is string or number make function selector
|
A |
9484 |
if (va && va.call)
|
|
9485 |
f = va;
|
|
9486 |
else {
|
|
9487 |
f = function(v) {
|
|
9488 |
return v == va;
|
|
9489 |
};
|
|
9490 |
}
|
|
9491 |
|
|
9492 |
// Do we need to do something?
|
|
9493 |
if (va != t.selectedValue) {
|
|
9494 |
// Find item
|
|
9495 |
each(t.items, function(o, i) {
|
|
9496 |
if (f(o.value)) {
|
|
9497 |
fv = 1;
|
|
9498 |
t.selectByIndex(i);
|
|
9499 |
return false;
|
|
9500 |
}
|
|
9501 |
});
|
|
9502 |
|
|
9503 |
if (!fv)
|
|
9504 |
t.selectByIndex(-1);
|
|
9505 |
}
|
|
9506 |
},
|
|
9507 |
|
|
9508 |
selectByIndex : function(idx) {
|
|
9509 |
DOM.get(this.id).selectedIndex = idx + 1;
|
|
9510 |
this.selectedValue = this.items[idx] ? this.items[idx].value : null;
|
d9344f
|
9511 |
},
|
S |
9512 |
|
|
9513 |
add : function(n, v, a) {
|
|
9514 |
var o, t = this;
|
|
9515 |
|
|
9516 |
a = a || {};
|
|
9517 |
a.value = v;
|
|
9518 |
|
|
9519 |
if (t.isRendered())
|
|
9520 |
DOM.add(DOM.get(this.id), 'option', a, n);
|
|
9521 |
|
|
9522 |
o = {
|
|
9523 |
title : n,
|
|
9524 |
value : v,
|
|
9525 |
attribs : a
|
|
9526 |
};
|
|
9527 |
|
|
9528 |
t.items.push(o);
|
|
9529 |
t.onAdd.dispatch(t, o);
|
|
9530 |
},
|
|
9531 |
|
|
9532 |
getLength : function() {
|
799907
|
9533 |
return this.items.length;
|
d9344f
|
9534 |
},
|
S |
9535 |
|
|
9536 |
renderHTML : function() {
|
|
9537 |
var h, t = this;
|
|
9538 |
|
|
9539 |
h = DOM.createHTML('option', {value : ''}, '-- ' + t.settings.title + ' --');
|
|
9540 |
|
|
9541 |
each(t.items, function(it) {
|
|
9542 |
h += DOM.createHTML('option', {value : it.value}, it.title);
|
|
9543 |
});
|
|
9544 |
|
a9251b
|
9545 |
h = DOM.createHTML('select', {id : t.id, 'class' : 'mceNativeListBox', 'aria-labelledby': t.id + '_aria'}, h);
|
T |
9546 |
h += DOM.createHTML('span', {id : t.id + '_aria', 'style': 'display: none'}, t.settings.title);
|
d9344f
|
9547 |
return h;
|
S |
9548 |
},
|
|
9549 |
|
|
9550 |
postRender : function() {
|
a9251b
|
9551 |
var t = this, ch, changeListenerAdded = true;
|
d9344f
|
9552 |
|
S |
9553 |
t.rendered = true;
|
|
9554 |
|
|
9555 |
function onChange(e) {
|
29da64
|
9556 |
var v = t.items[e.target.selectedIndex - 1];
|
d9344f
|
9557 |
|
29da64
|
9558 |
if (v && (v = v.value)) {
|
A |
9559 |
t.onChange.dispatch(t, v);
|
d9344f
|
9560 |
|
29da64
|
9561 |
if (t.settings.onselect)
|
A |
9562 |
t.settings.onselect(v);
|
|
9563 |
}
|
d9344f
|
9564 |
};
|
S |
9565 |
|
|
9566 |
Event.add(t.id, 'change', onChange);
|
|
9567 |
|
|
9568 |
// Accessibility keyhandler
|
|
9569 |
Event.add(t.id, 'keydown', function(e) {
|
|
9570 |
var bf;
|
|
9571 |
|
|
9572 |
Event.remove(t.id, 'change', ch);
|
a9251b
|
9573 |
changeListenerAdded = false;
|
d9344f
|
9574 |
|
S |
9575 |
bf = Event.add(t.id, 'blur', function() {
|
a9251b
|
9576 |
if (changeListenerAdded) return;
|
T |
9577 |
changeListenerAdded = true;
|
d9344f
|
9578 |
Event.add(t.id, 'change', onChange);
|
S |
9579 |
Event.remove(t.id, 'blur', bf);
|
|
9580 |
});
|
|
9581 |
|
|
9582 |
if (e.keyCode == 13 || e.keyCode == 32) {
|
|
9583 |
onChange(e);
|
|
9584 |
return Event.cancel(e);
|
|
9585 |
}
|
|
9586 |
});
|
|
9587 |
|
|
9588 |
t.onPostRender.dispatch(t, DOM.get(t.id));
|
|
9589 |
}
|
58fb65
|
9590 |
});
|
69d05c
|
9591 |
})(tinymce);
|
A |
9592 |
(function(tinymce) {
|
d9344f
|
9593 |
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
|
S |
9594 |
|
|
9595 |
tinymce.create('tinymce.ui.MenuButton:tinymce.ui.Button', {
|
a9251b
|
9596 |
MenuButton : function(id, s, ed) {
|
T |
9597 |
this.parent(id, s, ed);
|
58fb65
|
9598 |
|
d9344f
|
9599 |
this.onRenderMenu = new tinymce.util.Dispatcher(this);
|
58fb65
|
9600 |
|
d9344f
|
9601 |
s.menu_container = s.menu_container || DOM.doc.body;
|
S |
9602 |
},
|
|
9603 |
|
|
9604 |
showMenu : function() {
|
|
9605 |
var t = this, p1, p2, e = DOM.get(t.id), m;
|
|
9606 |
|
|
9607 |
if (t.isDisabled())
|
|
9608 |
return;
|
|
9609 |
|
|
9610 |
if (!t.isMenuRendered) {
|
|
9611 |
t.renderMenu();
|
|
9612 |
t.isMenuRendered = true;
|
|
9613 |
}
|
|
9614 |
|
18240a
|
9615 |
if (t.isMenuVisible)
|
A |
9616 |
return t.hideMenu();
|
|
9617 |
|
d9344f
|
9618 |
p1 = DOM.getPos(t.settings.menu_container);
|
S |
9619 |
p2 = DOM.getPos(e);
|
|
9620 |
|
|
9621 |
m = t.menu;
|
|
9622 |
m.settings.offset_x = p2.x;
|
|
9623 |
m.settings.offset_y = p2.y;
|
|
9624 |
m.settings.vp_offset_x = p2.x;
|
|
9625 |
m.settings.vp_offset_y = p2.y;
|
|
9626 |
m.settings.keyboard_focus = t._focused;
|
|
9627 |
m.showMenu(0, e.clientHeight);
|
|
9628 |
|
|
9629 |
Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
|
|
9630 |
t.setState('Selected', 1);
|
18240a
|
9631 |
|
A |
9632 |
t.isMenuVisible = 1;
|
d9344f
|
9633 |
},
|
S |
9634 |
|
|
9635 |
renderMenu : function() {
|
|
9636 |
var t = this, m;
|
|
9637 |
|
|
9638 |
m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
|
|
9639 |
menu_line : 1,
|
|
9640 |
'class' : this.classPrefix + 'Menu',
|
|
9641 |
icons : t.settings.icons
|
|
9642 |
});
|
|
9643 |
|
a9251b
|
9644 |
m.onHideMenu.add(function() {
|
T |
9645 |
t.hideMenu();
|
|
9646 |
t.focus();
|
|
9647 |
});
|
d9344f
|
9648 |
|
S |
9649 |
t.onRenderMenu.dispatch(t, m);
|
|
9650 |
t.menu = m;
|
|
9651 |
},
|
|
9652 |
|
|
9653 |
hideMenu : function(e) {
|
|
9654 |
var t = this;
|
|
9655 |
|
18240a
|
9656 |
// Prevent double toogles by canceling the mouse click event to the button
|
A |
9657 |
if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id || e.id === t.id + '_open';}))
|
|
9658 |
return;
|
|
9659 |
|
29da64
|
9660 |
if (!e || !DOM.getParent(e.target, '.mceMenu')) {
|
d9344f
|
9661 |
t.setState('Selected', 0);
|
S |
9662 |
Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
|
|
9663 |
if (t.menu)
|
|
9664 |
t.menu.hideMenu();
|
|
9665 |
}
|
18240a
|
9666 |
|
A |
9667 |
t.isMenuVisible = 0;
|
d9344f
|
9668 |
},
|
S |
9669 |
|
|
9670 |
postRender : function() {
|
|
9671 |
var t = this, s = t.settings;
|
|
9672 |
|
|
9673 |
Event.add(t.id, 'click', function() {
|
|
9674 |
if (!t.isDisabled()) {
|
|
9675 |
if (s.onclick)
|
|
9676 |
s.onclick(t.value);
|
|
9677 |
|
|
9678 |
t.showMenu();
|
|
9679 |
}
|
|
9680 |
});
|
|
9681 |
}
|
58fb65
|
9682 |
});
|
29da64
|
9683 |
})(tinymce);
|
69d05c
|
9684 |
|
29da64
|
9685 |
(function(tinymce) {
|
d9344f
|
9686 |
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
|
S |
9687 |
|
|
9688 |
tinymce.create('tinymce.ui.SplitButton:tinymce.ui.MenuButton', {
|
a9251b
|
9689 |
SplitButton : function(id, s, ed) {
|
T |
9690 |
this.parent(id, s, ed);
|
d9344f
|
9691 |
this.classPrefix = 'mceSplitButton';
|
S |
9692 |
},
|
|
9693 |
|
|
9694 |
renderHTML : function() {
|
|
9695 |
var h, t = this, s = t.settings, h1;
|
|
9696 |
|
|
9697 |
h = '<tbody><tr>';
|
|
9698 |
|
|
9699 |
if (s.image)
|
a9251b
|
9700 |
h1 = DOM.createHTML('img ', {src : s.image, role: 'presentation', 'class' : 'mceAction ' + s['class']});
|
d9344f
|
9701 |
else
|
S |
9702 |
h1 = DOM.createHTML('span', {'class' : 'mceAction ' + s['class']}, '');
|
|
9703 |
|
a9251b
|
9704 |
h1 += DOM.createHTML('span', {'class': 'mceVoiceLabel mceIconOnly', id: t.id + '_voice', style: 'display:none;'}, s.title);
|
T |
9705 |
h += '<td >' + DOM.createHTML('a', {role: 'button', id : t.id + '_action', tabindex: '-1', href : 'javascript:;', 'class' : 'mceAction ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + '</td>';
|
d9344f
|
9706 |
|
a9251b
|
9707 |
h1 = DOM.createHTML('span', {'class' : 'mceOpen ' + s['class']}, '<span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span>');
|
T |
9708 |
h += '<td >' + DOM.createHTML('a', {role: 'button', id : t.id + '_open', tabindex: '-1', href : 'javascript:;', 'class' : 'mceOpen ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + '</td>';
|
d9344f
|
9709 |
|
S |
9710 |
h += '</tr></tbody>';
|
a9251b
|
9711 |
h = DOM.createHTML('table', {id : t.id, role: 'presentation', tabindex: '0', 'class' : 'mceSplitButton mceSplitButtonEnabled ' + s['class'], cellpadding : '0', cellspacing : '0', title : s.title}, h);
|
T |
9712 |
return DOM.createHTML('span', {role: 'button', 'aria-labelledby': t.id + '_voice', 'aria-haspopup': 'true'}, h);
|
d9344f
|
9713 |
},
|
S |
9714 |
|
|
9715 |
postRender : function() {
|
a9251b
|
9716 |
var t = this, s = t.settings, activate;
|
d9344f
|
9717 |
|
S |
9718 |
if (s.onclick) {
|
a9251b
|
9719 |
activate = function(evt) {
|
T |
9720 |
if (!t.isDisabled()) {
|
d9344f
|
9721 |
s.onclick(t.value);
|
a9251b
|
9722 |
Event.cancel(evt);
|
T |
9723 |
}
|
|
9724 |
};
|
|
9725 |
Event.add(t.id + '_action', 'click', activate);
|
|
9726 |
Event.add(t.id, ['click', 'keydown'], function(evt) {
|
|
9727 |
var DOM_VK_SPACE = 32, DOM_VK_ENTER = 14, DOM_VK_RETURN = 13, DOM_VK_UP = 38, DOM_VK_DOWN = 40;
|
|
9728 |
if ((evt.keyCode === 32 || evt.keyCode === 13 || evt.keyCode === 14) && !evt.altKey && !evt.ctrlKey && !evt.metaKey) {
|
|
9729 |
activate();
|
|
9730 |
Event.cancel(evt);
|
|
9731 |
} else if (evt.type === 'click' || evt.keyCode === DOM_VK_DOWN) {
|
|
9732 |
t.showMenu();
|
|
9733 |
Event.cancel(evt);
|
|
9734 |
}
|
d9344f
|
9735 |
});
|
S |
9736 |
}
|
|
9737 |
|
a9251b
|
9738 |
Event.add(t.id + '_open', 'click', function (evt) {
|
T |
9739 |
t.showMenu();
|
|
9740 |
Event.cancel(evt);
|
|
9741 |
});
|
|
9742 |
Event.add([t.id, t.id + '_open'], 'focus', function() {t._focused = 1;});
|
|
9743 |
Event.add([t.id, t.id + '_open'], 'blur', function() {t._focused = 0;});
|
d9344f
|
9744 |
|
S |
9745 |
// Old IE doesn't have hover on all elements
|
|
9746 |
if (tinymce.isIE6 || !DOM.boxModel) {
|
|
9747 |
Event.add(t.id, 'mouseover', function() {
|
|
9748 |
if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
|
|
9749 |
DOM.addClass(t.id, 'mceSplitButtonHover');
|
|
9750 |
});
|
|
9751 |
|
|
9752 |
Event.add(t.id, 'mouseout', function() {
|
|
9753 |
if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
|
|
9754 |
DOM.removeClass(t.id, 'mceSplitButtonHover');
|
|
9755 |
});
|
|
9756 |
}
|
|
9757 |
},
|
|
9758 |
|
|
9759 |
destroy : function() {
|
|
9760 |
this.parent();
|
|
9761 |
|
|
9762 |
Event.clear(this.id + '_action');
|
|
9763 |
Event.clear(this.id + '_open');
|
a9251b
|
9764 |
Event.clear(this.id);
|
d9344f
|
9765 |
}
|
58fb65
|
9766 |
});
|
29da64
|
9767 |
})(tinymce);
|
69d05c
|
9768 |
|
29da64
|
9769 |
(function(tinymce) {
|
d9344f
|
9770 |
var DOM = tinymce.DOM, Event = tinymce.dom.Event, is = tinymce.is, each = tinymce.each;
|
S |
9771 |
|
|
9772 |
tinymce.create('tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton', {
|
a9251b
|
9773 |
ColorSplitButton : function(id, s, ed) {
|
d9344f
|
9774 |
var t = this;
|
S |
9775 |
|
a9251b
|
9776 |
t.parent(id, s, ed);
|
d9344f
|
9777 |
|
S |
9778 |
t.settings = s = tinymce.extend({
|
|
9779 |
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',
|
|
9780 |
grid_width : 8,
|
|
9781 |
default_color : '#888888'
|
|
9782 |
}, t.settings);
|
|
9783 |
|
18240a
|
9784 |
t.onShowMenu = new tinymce.util.Dispatcher(t);
|
58fb65
|
9785 |
|
18240a
|
9786 |
t.onHideMenu = new tinymce.util.Dispatcher(t);
|
A |
9787 |
|
d9344f
|
9788 |
t.value = s.default_color;
|
S |
9789 |
},
|
|
9790 |
|
|
9791 |
showMenu : function() {
|
|
9792 |
var t = this, r, p, e, p2;
|
|
9793 |
|
|
9794 |
if (t.isDisabled())
|
|
9795 |
return;
|
|
9796 |
|
|
9797 |
if (!t.isMenuRendered) {
|
|
9798 |
t.renderMenu();
|
|
9799 |
t.isMenuRendered = true;
|
|
9800 |
}
|
18240a
|
9801 |
|
A |
9802 |
if (t.isMenuVisible)
|
|
9803 |
return t.hideMenu();
|
d9344f
|
9804 |
|
S |
9805 |
e = DOM.get(t.id);
|
|
9806 |
DOM.show(t.id + '_menu');
|
|
9807 |
DOM.addClass(e, 'mceSplitButtonSelected');
|
|
9808 |
p2 = DOM.getPos(e);
|
|
9809 |
DOM.setStyles(t.id + '_menu', {
|
|
9810 |
left : p2.x,
|
|
9811 |
top : p2.y + e.clientHeight,
|
|
9812 |
zIndex : 200000
|
|
9813 |
});
|
|
9814 |
e = 0;
|
|
9815 |
|
|
9816 |
Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
|
58fb65
|
9817 |
t.onShowMenu.dispatch(t);
|
d9344f
|
9818 |
|
S |
9819 |
if (t._focused) {
|
|
9820 |
t._keyHandler = Event.add(t.id + '_menu', 'keydown', function(e) {
|
|
9821 |
if (e.keyCode == 27)
|
|
9822 |
t.hideMenu();
|
|
9823 |
});
|
|
9824 |
|
|
9825 |
DOM.select('a', t.id + '_menu')[0].focus(); // Select first link
|
|
9826 |
}
|
18240a
|
9827 |
|
A |
9828 |
t.isMenuVisible = 1;
|
d9344f
|
9829 |
},
|
S |
9830 |
|
|
9831 |
hideMenu : function(e) {
|
|
9832 |
var t = this;
|
18240a
|
9833 |
|
a9251b
|
9834 |
if (t.isMenuVisible) {
|
T |
9835 |
// Prevent double toogles by canceling the mouse click event to the button
|
|
9836 |
if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id + '_open';}))
|
|
9837 |
return;
|
d9344f
|
9838 |
|
a9251b
|
9839 |
if (!e || !DOM.getParent(e.target, '.mceSplitButtonMenu')) {
|
T |
9840 |
DOM.removeClass(t.id, 'mceSplitButtonSelected');
|
|
9841 |
Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
|
|
9842 |
Event.remove(t.id + '_menu', 'keydown', t._keyHandler);
|
|
9843 |
DOM.hide(t.id + '_menu');
|
|
9844 |
}
|
|
9845 |
|
|
9846 |
t.isMenuVisible = 0;
|
d9344f
|
9847 |
}
|
S |
9848 |
},
|
|
9849 |
|
|
9850 |
renderMenu : function() {
|
a9251b
|
9851 |
var t = this, m, i = 0, s = t.settings, n, tb, tr, w, context;
|
d9344f
|
9852 |
|
a9251b
|
9853 |
w = DOM.add(s.menu_container, 'div', {role: 'listbox', id : t.id + '_menu', 'class' : s['menu_class'] + ' ' + s['class'], style : 'position:absolute;left:0;top:-1000px;'});
|
d9344f
|
9854 |
m = DOM.add(w, 'div', {'class' : s['class'] + ' mceSplitButtonMenu'});
|
S |
9855 |
DOM.add(m, 'span', {'class' : 'mceMenuLine'});
|
|
9856 |
|
a9251b
|
9857 |
n = DOM.add(m, 'table', {role: 'presentation', 'class' : 'mceColorSplitMenu'});
|
d9344f
|
9858 |
tb = DOM.add(n, 'tbody');
|
S |
9859 |
|
|
9860 |
// Generate color grid
|
|
9861 |
i = 0;
|
|
9862 |
each(is(s.colors, 'array') ? s.colors : s.colors.split(','), function(c) {
|
|
9863 |
c = c.replace(/^#/, '');
|
|
9864 |
|
|
9865 |
if (!i--) {
|
|
9866 |
tr = DOM.add(tb, 'tr');
|
|
9867 |
i = s.grid_width - 1;
|
|
9868 |
}
|
|
9869 |
|
|
9870 |
n = DOM.add(tr, 'td');
|
|
9871 |
n = DOM.add(n, 'a', {
|
a9251b
|
9872 |
role : 'option',
|
d9344f
|
9873 |
href : 'javascript:;',
|
S |
9874 |
style : {
|
|
9875 |
backgroundColor : '#' + c
|
|
9876 |
},
|
a9251b
|
9877 |
'title': t.editor.getLang('colors.' + c, c),
|
T |
9878 |
'data-mce-color' : '#' + c
|
d9344f
|
9879 |
});
|
a9251b
|
9880 |
|
T |
9881 |
if (t.editor.forcedHighContrastMode) {
|
|
9882 |
n = DOM.add(n, 'canvas', { width: 16, height: 16, 'aria-hidden': 'true' });
|
|
9883 |
if (n.getContext && (context = n.getContext("2d"))) {
|
|
9884 |
context.fillStyle = '#' + c;
|
|
9885 |
context.fillRect(0, 0, 16, 16);
|
|
9886 |
} else {
|
|
9887 |
// No point leaving a canvas element around if it's not supported for drawing on anyway.
|
|
9888 |
DOM.remove(n);
|
|
9889 |
}
|
|
9890 |
}
|
d9344f
|
9891 |
});
|
S |
9892 |
|
|
9893 |
if (s.more_colors_func) {
|
|
9894 |
n = DOM.add(tb, 'tr');
|
|
9895 |
n = DOM.add(n, 'td', {colspan : s.grid_width, 'class' : 'mceMoreColors'});
|
a9251b
|
9896 |
n = DOM.add(n, 'a', {role: 'option', id : t.id + '_more', href : 'javascript:;', onclick : 'return false;', 'class' : 'mceMoreColors'}, s.more_colors_title);
|
d9344f
|
9897 |
|
S |
9898 |
Event.add(n, 'click', function(e) {
|
|
9899 |
s.more_colors_func.call(s.more_colors_scope || this);
|
|
9900 |
return Event.cancel(e); // Cancel to fix onbeforeunload problem
|
|
9901 |
});
|
|
9902 |
}
|
|
9903 |
|
|
9904 |
DOM.addClass(m, 'mceColorSplitMenu');
|
a9251b
|
9905 |
|
T |
9906 |
new tinymce.ui.KeyboardNavigation({
|
|
9907 |
root: t.id + '_menu',
|
|
9908 |
items: DOM.select('a', t.id + '_menu'),
|
|
9909 |
onCancel: function() {
|
|
9910 |
t.hideMenu();
|
|
9911 |
t.focus();
|
|
9912 |
}
|
|
9913 |
});
|
|
9914 |
|
|
9915 |
// Prevent IE from scrolling and hindering click to occur #4019
|
|
9916 |
Event.add(t.id + '_menu', 'mousedown', function(e) {return Event.cancel(e);});
|
d9344f
|
9917 |
|
S |
9918 |
Event.add(t.id + '_menu', 'click', function(e) {
|
|
9919 |
var c;
|
|
9920 |
|
a9251b
|
9921 |
e = DOM.getParent(e.target, 'a', tb);
|
d9344f
|
9922 |
|
a9251b
|
9923 |
if (e && e.nodeName.toLowerCase() == 'a' && (c = e.getAttribute('data-mce-color')))
|
d9344f
|
9924 |
t.setColor(c);
|
18240a
|
9925 |
|
A |
9926 |
return Event.cancel(e); // Prevent IE auto save warning
|
d9344f
|
9927 |
});
|
S |
9928 |
|
|
9929 |
return w;
|
|
9930 |
},
|
|
9931 |
|
|
9932 |
setColor : function(c) {
|
a9251b
|
9933 |
this.displayColor(c);
|
T |
9934 |
this.hideMenu();
|
|
9935 |
this.settings.onselect(c);
|
|
9936 |
},
|
|
9937 |
|
|
9938 |
displayColor : function(c) {
|
d9344f
|
9939 |
var t = this;
|
S |
9940 |
|
|
9941 |
DOM.setStyle(t.id + '_preview', 'backgroundColor', c);
|
|
9942 |
|
|
9943 |
t.value = c;
|
|
9944 |
},
|
|
9945 |
|
|
9946 |
postRender : function() {
|
|
9947 |
var t = this, id = t.id;
|
|
9948 |
|
|
9949 |
t.parent();
|
|
9950 |
DOM.add(id + '_action', 'div', {id : id + '_preview', 'class' : 'mceColorPreview'});
|
29da64
|
9951 |
DOM.setStyle(t.id + '_preview', 'backgroundColor', t.value);
|
d9344f
|
9952 |
},
|
S |
9953 |
|
|
9954 |
destroy : function() {
|
|
9955 |
this.parent();
|
|
9956 |
|
|
9957 |
Event.clear(this.id + '_menu');
|
|
9958 |
Event.clear(this.id + '_more');
|
|
9959 |
DOM.remove(this.id + '_menu');
|
|
9960 |
}
|
58fb65
|
9961 |
});
|
29da64
|
9962 |
})(tinymce);
|
69d05c
|
9963 |
|
a9251b
|
9964 |
(function(tinymce) {
|
T |
9965 |
// Shorten class names
|
|
9966 |
var dom = tinymce.DOM, each = tinymce.each, Event = tinymce.dom.Event;
|
|
9967 |
tinymce.create('tinymce.ui.ToolbarGroup:tinymce.ui.Container', {
|
|
9968 |
renderHTML : function() {
|
|
9969 |
var t = this, h = [], controls = t.controls, each = tinymce.each, settings = t.settings;
|
|
9970 |
|
|
9971 |
h.push('<div id="' + t.id + '" role="group" aria-labelledby="' + t.id + '_voice">');
|
|
9972 |
//TODO: ACC test this out - adding a role = application for getting the landmarks working well.
|
|
9973 |
h.push("<span role='application'>");
|
|
9974 |
h.push('<span id="' + t.id + '_voice" class="mceVoiceLabel" style="display:none;">' + dom.encode(settings.name) + '</span>');
|
|
9975 |
each(controls, function(toolbar) {
|
|
9976 |
h.push(toolbar.renderHTML());
|
|
9977 |
});
|
|
9978 |
h.push("</span>");
|
|
9979 |
h.push('</div>');
|
|
9980 |
|
|
9981 |
return h.join('');
|
|
9982 |
},
|
|
9983 |
|
|
9984 |
focus : function() {
|
|
9985 |
this.keyNav.focus();
|
|
9986 |
},
|
|
9987 |
|
|
9988 |
postRender : function() {
|
|
9989 |
var t = this, items = [];
|
|
9990 |
|
|
9991 |
each(t.controls, function(toolbar) {
|
|
9992 |
each (toolbar.controls, function(control) {
|
|
9993 |
if (control.id) {
|
|
9994 |
items.push(control);
|
|
9995 |
}
|
|
9996 |
});
|
|
9997 |
});
|
|
9998 |
|
|
9999 |
t.keyNav = new tinymce.ui.KeyboardNavigation({
|
|
10000 |
root: t.id,
|
|
10001 |
items: items,
|
|
10002 |
onCancel: function() {
|
|
10003 |
t.editor.focus();
|
|
10004 |
},
|
|
10005 |
excludeFromTabOrder: !t.settings.tab_focus_toolbar
|
|
10006 |
});
|
|
10007 |
},
|
|
10008 |
|
|
10009 |
destroy : function() {
|
|
10010 |
var self = this;
|
|
10011 |
|
|
10012 |
self.parent();
|
|
10013 |
self.keyNav.destroy();
|
|
10014 |
Event.clear(self.id);
|
|
10015 |
}
|
|
10016 |
});
|
|
10017 |
})(tinymce);
|
|
10018 |
|
|
10019 |
(function(tinymce) {
|
|
10020 |
// Shorten class names
|
|
10021 |
var dom = tinymce.DOM, each = tinymce.each;
|
d9344f
|
10022 |
tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {
|
S |
10023 |
renderHTML : function() {
|
a9251b
|
10024 |
var t = this, h = '', c, co, s = t.settings, i, pr, nx, cl;
|
d9344f
|
10025 |
|
S |
10026 |
cl = t.controls;
|
|
10027 |
for (i=0; i<cl.length; i++) {
|
|
10028 |
// Get current control, prev control, next control and if the control is a list box or not
|
|
10029 |
co = cl[i];
|
|
10030 |
pr = cl[i - 1];
|
|
10031 |
nx = cl[i + 1];
|
|
10032 |
|
|
10033 |
// Add toolbar start
|
|
10034 |
if (i === 0) {
|
|
10035 |
c = 'mceToolbarStart';
|
|
10036 |
|
|
10037 |
if (co.Button)
|
|
10038 |
c += ' mceToolbarStartButton';
|
|
10039 |
else if (co.SplitButton)
|
|
10040 |
c += ' mceToolbarStartSplitButton';
|
|
10041 |
else if (co.ListBox)
|
|
10042 |
c += ' mceToolbarStartListBox';
|
|
10043 |
|
|
10044 |
h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
|
|
10045 |
}
|
|
10046 |
|
|
10047 |
// Add toolbar end before list box and after the previous button
|
|
10048 |
// This is to fix the o2k7 editor skins
|
|
10049 |
if (pr && co.ListBox) {
|
|
10050 |
if (pr.Button || pr.SplitButton)
|
|
10051 |
h += dom.createHTML('td', {'class' : 'mceToolbarEnd'}, dom.createHTML('span', null, '<!-- IE -->'));
|
|
10052 |
}
|
|
10053 |
|
|
10054 |
// Render control HTML
|
|
10055 |
|
|
10056 |
// IE 8 quick fix, needed to propertly generate a hit area for anchors
|
|
10057 |
if (dom.stdMode)
|
|
10058 |
h += '<td style="position: relative">' + co.renderHTML() + '</td>';
|
|
10059 |
else
|
|
10060 |
h += '<td>' + co.renderHTML() + '</td>';
|
|
10061 |
|
|
10062 |
// Add toolbar start after list box and before the next button
|
|
10063 |
// This is to fix the o2k7 editor skins
|
|
10064 |
if (nx && co.ListBox) {
|
|
10065 |
if (nx.Button || nx.SplitButton)
|
|
10066 |
h += dom.createHTML('td', {'class' : 'mceToolbarStart'}, dom.createHTML('span', null, '<!-- IE -->'));
|
|
10067 |
}
|
|
10068 |
}
|
|
10069 |
|
|
10070 |
c = 'mceToolbarEnd';
|
|
10071 |
|
|
10072 |
if (co.Button)
|
|
10073 |
c += ' mceToolbarEndButton';
|
|
10074 |
else if (co.SplitButton)
|
|
10075 |
c += ' mceToolbarEndSplitButton';
|
|
10076 |
else if (co.ListBox)
|
|
10077 |
c += ' mceToolbarEndListBox';
|
|
10078 |
|
|
10079 |
h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
|
|
10080 |
|
a9251b
|
10081 |
return dom.createHTML('table', {id : t.id, 'class' : 'mceToolbar' + (s['class'] ? ' ' + s['class'] : ''), cellpadding : '0', cellspacing : '0', align : t.settings.align || '', role: 'presentation', tabindex: '-1'}, '<tbody><tr>' + h + '</tr></tbody>');
|
d9344f
|
10082 |
}
|
58fb65
|
10083 |
});
|
a9251b
|
10084 |
})(tinymce);
|
69d05c
|
10085 |
|
29da64
|
10086 |
(function(tinymce) {
|
d9344f
|
10087 |
var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each;
|
S |
10088 |
|
|
10089 |
tinymce.create('tinymce.AddOnManager', {
|
a9251b
|
10090 |
AddOnManager : function() {
|
T |
10091 |
var self = this;
|
58fb65
|
10092 |
|
a9251b
|
10093 |
self.items = [];
|
T |
10094 |
self.urls = {};
|
|
10095 |
self.lookup = {};
|
|
10096 |
self.onAdd = new Dispatcher(self);
|
|
10097 |
},
|
d9344f
|
10098 |
|
S |
10099 |
get : function(n) {
|
|
10100 |
return this.lookup[n];
|
|
10101 |
},
|
|
10102 |
|
|
10103 |
requireLangPack : function(n) {
|
69d05c
|
10104 |
var s = tinymce.settings;
|
d9344f
|
10105 |
|
a9251b
|
10106 |
if (s && s.language && s.language_load !== false)
|
69d05c
|
10107 |
tinymce.ScriptLoader.add(this.urls[n] + '/langs/' + s.language + '.js');
|
d9344f
|
10108 |
},
|
S |
10109 |
|
|
10110 |
add : function(id, o) {
|
|
10111 |
this.items.push(o);
|
|
10112 |
this.lookup[id] = o;
|
|
10113 |
this.onAdd.dispatch(this, id, o);
|
|
10114 |
|
|
10115 |
return o;
|
|
10116 |
},
|
|
10117 |
|
|
10118 |
load : function(n, u, cb, s) {
|
|
10119 |
var t = this;
|
|
10120 |
|
|
10121 |
if (t.urls[n])
|
|
10122 |
return;
|
|
10123 |
|
|
10124 |
if (u.indexOf('/') != 0 && u.indexOf('://') == -1)
|
a9251b
|
10125 |
u = tinymce.baseURL + '/' + u;
|
d9344f
|
10126 |
|
S |
10127 |
t.urls[n] = u.substring(0, u.lastIndexOf('/'));
|
a9251b
|
10128 |
|
T |
10129 |
if (!t.lookup[n])
|
|
10130 |
tinymce.ScriptLoader.add(u, cb, s);
|
d9344f
|
10131 |
}
|
58fb65
|
10132 |
});
|
d9344f
|
10133 |
|
S |
10134 |
// Create plugin and theme managers
|
|
10135 |
tinymce.PluginManager = new tinymce.AddOnManager();
|
|
10136 |
tinymce.ThemeManager = new tinymce.AddOnManager();
|
58fb65
|
10137 |
}(tinymce));
|
A |
10138 |
|
|
10139 |
(function(tinymce) {
|
d9344f
|
10140 |
// Shorten names
|
69d05c
|
10141 |
var each = tinymce.each, extend = tinymce.extend,
|
A |
10142 |
DOM = tinymce.DOM, Event = tinymce.dom.Event,
|
|
10143 |
ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager,
|
|
10144 |
explode = tinymce.explode,
|
|
10145 |
Dispatcher = tinymce.util.Dispatcher, undefined, instanceCounter = 0;
|
d9344f
|
10146 |
|
69d05c
|
10147 |
// Setup some URLs where the editor API is located and where the document is
|
A |
10148 |
tinymce.documentBaseURL = window.location.href.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
|
|
10149 |
if (!/[\/\\]$/.test(tinymce.documentBaseURL))
|
|
10150 |
tinymce.documentBaseURL += '/';
|
|
10151 |
|
|
10152 |
tinymce.baseURL = new tinymce.util.URI(tinymce.documentBaseURL).toAbsolute(tinymce.baseURL);
|
|
10153 |
|
|
10154 |
tinymce.baseURI = new tinymce.util.URI(tinymce.baseURL);
|
|
10155 |
|
|
10156 |
// Add before unload listener
|
|
10157 |
// This was required since IE was leaking memory if you added and removed beforeunload listeners
|
|
10158 |
// with attachEvent/detatchEvent so this only adds one listener and instances can the attach to the onBeforeUnload event
|
|
10159 |
tinymce.onBeforeUnload = new Dispatcher(tinymce);
|
|
10160 |
|
|
10161 |
// Must be on window or IE will leak if the editor is placed in frame or iframe
|
|
10162 |
Event.add(window, 'beforeunload', function(e) {
|
|
10163 |
tinymce.onBeforeUnload.dispatch(tinymce, e);
|
|
10164 |
});
|
|
10165 |
|
|
10166 |
tinymce.onAddEditor = new Dispatcher(tinymce);
|
|
10167 |
|
|
10168 |
tinymce.onRemoveEditor = new Dispatcher(tinymce);
|
|
10169 |
|
|
10170 |
tinymce.EditorManager = extend(tinymce, {
|
|
10171 |
editors : [],
|
58fb65
|
10172 |
|
d9344f
|
10173 |
i18n : {},
|
69d05c
|
10174 |
|
d9344f
|
10175 |
activeEditor : null,
|
S |
10176 |
|
|
10177 |
init : function(s) {
|
69d05c
|
10178 |
var t = this, pl, sl = tinymce.ScriptLoader, e, el = [], ed;
|
d9344f
|
10179 |
|
S |
10180 |
function execCallback(se, n, s) {
|
|
10181 |
var f = se[n];
|
|
10182 |
|
|
10183 |
if (!f)
|
|
10184 |
return;
|
|
10185 |
|
|
10186 |
if (tinymce.is(f, 'string')) {
|
|
10187 |
s = f.replace(/\.\w+$/, '');
|
|
10188 |
s = s ? tinymce.resolve(s) : 0;
|
|
10189 |
f = tinymce.resolve(f);
|
|
10190 |
}
|
|
10191 |
|
|
10192 |
return f.apply(s || this, Array.prototype.slice.call(arguments, 2));
|
|
10193 |
};
|
|
10194 |
|
|
10195 |
s = extend({
|
|
10196 |
theme : "simple",
|
69d05c
|
10197 |
language : "en"
|
d9344f
|
10198 |
}, s);
|
S |
10199 |
|
|
10200 |
t.settings = s;
|
|
10201 |
|
|
10202 |
// Legacy call
|
|
10203 |
Event.add(document, 'init', function() {
|
|
10204 |
var l, co;
|
|
10205 |
|
|
10206 |
execCallback(s, 'onpageload');
|
|
10207 |
|
|
10208 |
switch (s.mode) {
|
|
10209 |
case "exact":
|
|
10210 |
l = s.elements || '';
|
|
10211 |
|
|
10212 |
if(l.length > 0) {
|
|
10213 |
each(explode(l), function(v) {
|
29da64
|
10214 |
if (DOM.get(v)) {
|
A |
10215 |
ed = new tinymce.Editor(v, s);
|
|
10216 |
el.push(ed);
|
|
10217 |
ed.render(1);
|
|
10218 |
} else {
|
d9344f
|
10219 |
each(document.forms, function(f) {
|
S |
10220 |
each(f.elements, function(e) {
|
|
10221 |
if (e.name === v) {
|
69d05c
|
10222 |
v = 'mce_editor_' + instanceCounter++;
|
d9344f
|
10223 |
DOM.setAttrib(e, 'id', v);
|
29da64
|
10224 |
|
A |
10225 |
ed = new tinymce.Editor(v, s);
|
|
10226 |
el.push(ed);
|
|
10227 |
ed.render(1);
|
d9344f
|
10228 |
}
|
S |
10229 |
});
|
|
10230 |
});
|
|
10231 |
}
|
|
10232 |
});
|
|
10233 |
}
|
|
10234 |
break;
|
|
10235 |
|
|
10236 |
case "textareas":
|
|
10237 |
case "specific_textareas":
|
|
10238 |
function hasClass(n, c) {
|
18240a
|
10239 |
return c.constructor === RegExp ? c.test(n.className) : DOM.hasClass(n, c);
|
d9344f
|
10240 |
};
|
S |
10241 |
|
|
10242 |
each(DOM.select('textarea'), function(v) {
|
|
10243 |
if (s.editor_deselector && hasClass(v, s.editor_deselector))
|
|
10244 |
return;
|
|
10245 |
|
|
10246 |
if (!s.editor_selector || hasClass(v, s.editor_selector)) {
|
18240a
|
10247 |
// Can we use the name
|
A |
10248 |
e = DOM.get(v.name);
|
|
10249 |
if (!v.id && !e)
|
|
10250 |
v.id = v.name;
|
d9344f
|
10251 |
|
S |
10252 |
// Generate unique name if missing or already exists
|
|
10253 |
if (!v.id || t.get(v.id))
|
|
10254 |
v.id = DOM.uniqueId();
|
|
10255 |
|
29da64
|
10256 |
ed = new tinymce.Editor(v.id, s);
|
A |
10257 |
el.push(ed);
|
|
10258 |
ed.render(1);
|
d9344f
|
10259 |
}
|
S |
10260 |
});
|
|
10261 |
break;
|
|
10262 |
}
|
|
10263 |
|
|
10264 |
// Call onInit when all editors are initialized
|
|
10265 |
if (s.oninit) {
|
|
10266 |
l = co = 0;
|
|
10267 |
|
69d05c
|
10268 |
each(el, function(ed) {
|
d9344f
|
10269 |
co++;
|
S |
10270 |
|
|
10271 |
if (!ed.initialized) {
|
|
10272 |
// Wait for it
|
|
10273 |
ed.onInit.add(function() {
|
|
10274 |
l++;
|
|
10275 |
|
|
10276 |
// All done
|
|
10277 |
if (l == co)
|
|
10278 |
execCallback(s, 'oninit');
|
|
10279 |
});
|
|
10280 |
} else
|
|
10281 |
l++;
|
|
10282 |
|
|
10283 |
// All done
|
|
10284 |
if (l == co)
|
|
10285 |
execCallback(s, 'oninit');
|
|
10286 |
});
|
|
10287 |
}
|
|
10288 |
});
|
|
10289 |
},
|
|
10290 |
|
|
10291 |
get : function(id) {
|
69d05c
|
10292 |
if (id === undefined)
|
A |
10293 |
return this.editors;
|
|
10294 |
|
d9344f
|
10295 |
return this.editors[id];
|
S |
10296 |
},
|
|
10297 |
|
|
10298 |
getInstanceById : function(id) {
|
|
10299 |
return this.get(id);
|
|
10300 |
},
|
|
10301 |
|
69d05c
|
10302 |
add : function(editor) {
|
A |
10303 |
var self = this, editors = self.editors;
|
d9344f
|
10304 |
|
69d05c
|
10305 |
// Add named and index editor instance
|
A |
10306 |
editors[editor.id] = editor;
|
|
10307 |
editors.push(editor);
|
|
10308 |
|
|
10309 |
self._setActive(editor);
|
|
10310 |
self.onAddEditor.dispatch(self, editor);
|
|
10311 |
|
|
10312 |
|
|
10313 |
return editor;
|
d9344f
|
10314 |
},
|
S |
10315 |
|
69d05c
|
10316 |
remove : function(editor) {
|
A |
10317 |
var t = this, i, editors = t.editors;
|
d9344f
|
10318 |
|
S |
10319 |
// Not in the collection
|
69d05c
|
10320 |
if (!editors[editor.id])
|
d9344f
|
10321 |
return null;
|
S |
10322 |
|
69d05c
|
10323 |
delete editors[editor.id];
|
d9344f
|
10324 |
|
69d05c
|
10325 |
for (i = 0; i < editors.length; i++) {
|
A |
10326 |
if (editors[i] == editor) {
|
|
10327 |
editors.splice(i, 1);
|
|
10328 |
break;
|
|
10329 |
}
|
d9344f
|
10330 |
}
|
S |
10331 |
|
69d05c
|
10332 |
// Select another editor since the active one was removed
|
A |
10333 |
if (t.activeEditor == editor)
|
|
10334 |
t._setActive(editors[0]);
|
d9344f
|
10335 |
|
69d05c
|
10336 |
editor.destroy();
|
A |
10337 |
t.onRemoveEditor.dispatch(t, editor);
|
|
10338 |
|
|
10339 |
return editor;
|
d9344f
|
10340 |
},
|
S |
10341 |
|
|
10342 |
execCommand : function(c, u, v) {
|
|
10343 |
var t = this, ed = t.get(v), w;
|
|
10344 |
|
|
10345 |
// Manager commands
|
|
10346 |
switch (c) {
|
|
10347 |
case "mceFocus":
|
|
10348 |
ed.focus();
|
|
10349 |
return true;
|
|
10350 |
|
|
10351 |
case "mceAddEditor":
|
|
10352 |
case "mceAddControl":
|
18240a
|
10353 |
if (!t.get(v))
|
A |
10354 |
new tinymce.Editor(v, t.settings).render();
|
|
10355 |
|
d9344f
|
10356 |
return true;
|
S |
10357 |
|
|
10358 |
case "mceAddFrameControl":
|
|
10359 |
w = v.window;
|
|
10360 |
|
|
10361 |
// Add tinyMCE global instance and tinymce namespace to specified window
|
|
10362 |
w.tinyMCE = tinyMCE;
|
|
10363 |
w.tinymce = tinymce;
|
|
10364 |
|
|
10365 |
tinymce.DOM.doc = w.document;
|
|
10366 |
tinymce.DOM.win = w;
|
|
10367 |
|
|
10368 |
ed = new tinymce.Editor(v.element_id, v);
|
|
10369 |
ed.render();
|
|
10370 |
|
|
10371 |
// Fix IE memory leaks
|
|
10372 |
if (tinymce.isIE) {
|
|
10373 |
function clr() {
|
|
10374 |
ed.destroy();
|
|
10375 |
w.detachEvent('onunload', clr);
|
|
10376 |
w = w.tinyMCE = w.tinymce = null; // IE leak
|
|
10377 |
};
|
|
10378 |
|
|
10379 |
w.attachEvent('onunload', clr);
|
|
10380 |
}
|
|
10381 |
|
|
10382 |
v.page_window = null;
|
|
10383 |
|
|
10384 |
return true;
|
|
10385 |
|
|
10386 |
case "mceRemoveEditor":
|
|
10387 |
case "mceRemoveControl":
|
29da64
|
10388 |
if (ed)
|
A |
10389 |
ed.remove();
|
|
10390 |
|
d9344f
|
10391 |
return true;
|
S |
10392 |
|
|
10393 |
case 'mceToggleEditor':
|
|
10394 |
if (!ed) {
|
|
10395 |
t.execCommand('mceAddControl', 0, v);
|
|
10396 |
return true;
|
|
10397 |
}
|
|
10398 |
|
|
10399 |
if (ed.isHidden())
|
|
10400 |
ed.show();
|
|
10401 |
else
|
|
10402 |
ed.hide();
|
|
10403 |
|
|
10404 |
return true;
|
|
10405 |
}
|
|
10406 |
|
|
10407 |
// Run command on active editor
|
|
10408 |
if (t.activeEditor)
|
|
10409 |
return t.activeEditor.execCommand(c, u, v);
|
|
10410 |
|
|
10411 |
return false;
|
|
10412 |
},
|
|
10413 |
|
|
10414 |
execInstanceCommand : function(id, c, u, v) {
|
|
10415 |
var ed = this.get(id);
|
|
10416 |
|
|
10417 |
if (ed)
|
|
10418 |
return ed.execCommand(c, u, v);
|
|
10419 |
|
|
10420 |
return false;
|
|
10421 |
},
|
|
10422 |
|
|
10423 |
triggerSave : function() {
|
|
10424 |
each(this.editors, function(e) {
|
|
10425 |
e.save();
|
|
10426 |
});
|
|
10427 |
},
|
|
10428 |
|
|
10429 |
addI18n : function(p, o) {
|
|
10430 |
var lo, i18n = this.i18n;
|
|
10431 |
|
|
10432 |
if (!tinymce.is(p, 'string')) {
|
|
10433 |
each(p, function(o, lc) {
|
|
10434 |
each(o, function(o, g) {
|
|
10435 |
each(o, function(o, k) {
|
|
10436 |
if (g === 'common')
|
|
10437 |
i18n[lc + '.' + k] = o;
|
|
10438 |
else
|
|
10439 |
i18n[lc + '.' + g + '.' + k] = o;
|
|
10440 |
});
|
|
10441 |
});
|
|
10442 |
});
|
|
10443 |
} else {
|
|
10444 |
each(o, function(o, k) {
|
|
10445 |
i18n[p + '.' + k] = o;
|
|
10446 |
});
|
|
10447 |
}
|
|
10448 |
},
|
|
10449 |
|
|
10450 |
// Private methods
|
|
10451 |
|
69d05c
|
10452 |
_setActive : function(editor) {
|
A |
10453 |
this.selectedInstance = this.activeEditor = editor;
|
d9344f
|
10454 |
}
|
58fb65
|
10455 |
});
|
29da64
|
10456 |
})(tinymce);
|
d9344f
|
10457 |
|
29da64
|
10458 |
(function(tinymce) {
|
69d05c
|
10459 |
// Shorten these names
|
A |
10460 |
var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend,
|
|
10461 |
Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isGecko = tinymce.isGecko,
|
|
10462 |
isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, is = tinymce.is,
|
|
10463 |
ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager,
|
|
10464 |
inArray = tinymce.inArray, grep = tinymce.grep, explode = tinymce.explode;
|
d9344f
|
10465 |
|
S |
10466 |
tinymce.create('tinymce.Editor', {
|
|
10467 |
Editor : function(id, s) {
|
|
10468 |
var t = this;
|
|
10469 |
|
|
10470 |
t.id = t.editorId = id;
|
58fb65
|
10471 |
|
d9344f
|
10472 |
t.execCommands = {};
|
S |
10473 |
t.queryStateCommands = {};
|
|
10474 |
t.queryValueCommands = {};
|
58fb65
|
10475 |
|
A |
10476 |
t.isNotDirty = false;
|
|
10477 |
|
d9344f
|
10478 |
t.plugins = {};
|
S |
10479 |
|
|
10480 |
// Add events to the editor
|
|
10481 |
each([
|
|
10482 |
'onPreInit',
|
58fb65
|
10483 |
|
d9344f
|
10484 |
'onBeforeRenderUI',
|
58fb65
|
10485 |
|
d9344f
|
10486 |
'onPostRender',
|
58fb65
|
10487 |
|
d9344f
|
10488 |
'onInit',
|
58fb65
|
10489 |
|
d9344f
|
10490 |
'onRemove',
|
58fb65
|
10491 |
|
d9344f
|
10492 |
'onActivate',
|
58fb65
|
10493 |
|
d9344f
|
10494 |
'onDeactivate',
|
58fb65
|
10495 |
|
d9344f
|
10496 |
'onClick',
|
58fb65
|
10497 |
|
d9344f
|
10498 |
'onEvent',
|
58fb65
|
10499 |
|
d9344f
|
10500 |
'onMouseUp',
|
58fb65
|
10501 |
|
d9344f
|
10502 |
'onMouseDown',
|
58fb65
|
10503 |
|
d9344f
|
10504 |
'onDblClick',
|
58fb65
|
10505 |
|
d9344f
|
10506 |
'onKeyDown',
|
58fb65
|
10507 |
|
d9344f
|
10508 |
'onKeyUp',
|
58fb65
|
10509 |
|
d9344f
|
10510 |
'onKeyPress',
|
58fb65
|
10511 |
|
d9344f
|
10512 |
'onContextMenu',
|
58fb65
|
10513 |
|
d9344f
|
10514 |
'onSubmit',
|
58fb65
|
10515 |
|
d9344f
|
10516 |
'onReset',
|
58fb65
|
10517 |
|
d9344f
|
10518 |
'onPaste',
|
58fb65
|
10519 |
|
d9344f
|
10520 |
'onPreProcess',
|
58fb65
|
10521 |
|
d9344f
|
10522 |
'onPostProcess',
|
58fb65
|
10523 |
|
d9344f
|
10524 |
'onBeforeSetContent',
|
58fb65
|
10525 |
|
d9344f
|
10526 |
'onBeforeGetContent',
|
58fb65
|
10527 |
|
d9344f
|
10528 |
'onSetContent',
|
58fb65
|
10529 |
|
d9344f
|
10530 |
'onGetContent',
|
58fb65
|
10531 |
|
d9344f
|
10532 |
'onLoadContent',
|
58fb65
|
10533 |
|
d9344f
|
10534 |
'onSaveContent',
|
58fb65
|
10535 |
|
d9344f
|
10536 |
'onNodeChange',
|
58fb65
|
10537 |
|
d9344f
|
10538 |
'onChange',
|
58fb65
|
10539 |
|
d9344f
|
10540 |
'onBeforeExecCommand',
|
58fb65
|
10541 |
|
d9344f
|
10542 |
'onExecCommand',
|
58fb65
|
10543 |
|
d9344f
|
10544 |
'onUndo',
|
58fb65
|
10545 |
|
d9344f
|
10546 |
'onRedo',
|
58fb65
|
10547 |
|
d9344f
|
10548 |
'onVisualAid',
|
58fb65
|
10549 |
|
d9344f
|
10550 |
'onSetProgressState'
|
S |
10551 |
], function(e) {
|
|
10552 |
t[e] = new Dispatcher(t);
|
|
10553 |
});
|
|
10554 |
|
|
10555 |
t.settings = s = extend({
|
|
10556 |
id : id,
|
|
10557 |
language : 'en',
|
|
10558 |
docs_language : 'en',
|
|
10559 |
theme : 'simple',
|
|
10560 |
skin : 'default',
|
|
10561 |
delta_width : 0,
|
|
10562 |
delta_height : 0,
|
|
10563 |
popup_css : '',
|
|
10564 |
plugins : '',
|
|
10565 |
document_base_url : tinymce.documentBaseURL,
|
|
10566 |
add_form_submit_trigger : 1,
|
|
10567 |
submit_patch : 1,
|
|
10568 |
add_unload_trigger : 1,
|
|
10569 |
convert_urls : 1,
|
|
10570 |
relative_urls : 1,
|
|
10571 |
remove_script_host : 1,
|
|
10572 |
table_inline_editing : 0,
|
|
10573 |
object_resizing : 1,
|
|
10574 |
cleanup : 1,
|
|
10575 |
accessibility_focus : 1,
|
|
10576 |
custom_shortcuts : 1,
|
|
10577 |
custom_undo_redo_keyboard_shortcuts : 1,
|
|
10578 |
custom_undo_redo_restore_selection : 1,
|
|
10579 |
custom_undo_redo : 1,
|
69d05c
|
10580 |
doctype : tinymce.isIE6 ? '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">' : '<!DOCTYPE>', // Use old doctype on IE 6 to avoid horizontal scroll
|
d9344f
|
10581 |
visual_table_class : 'mceItemTable',
|
S |
10582 |
visual : 1,
|
|
10583 |
font_size_style_values : 'xx-small,x-small,small,medium,large,x-large,xx-large',
|
|
10584 |
apply_source_formatting : 1,
|
|
10585 |
directionality : 'ltr',
|
|
10586 |
forced_root_block : 'p',
|
|
10587 |
hidden_input : 1,
|
|
10588 |
padd_empty_editor : 1,
|
|
10589 |
render_ui : 1,
|
|
10590 |
init_theme : 1,
|
|
10591 |
force_p_newlines : 1,
|
29da64
|
10592 |
indentation : '30px',
|
A |
10593 |
keep_styles : 1,
|
|
10594 |
fix_table_elements : 1,
|
69d05c
|
10595 |
inline_styles : 1,
|
a9251b
|
10596 |
convert_fonts_to_spans : true,
|
T |
10597 |
indent : 'simple',
|
|
10598 |
indent_before : 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr',
|
|
10599 |
indent_after : 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr',
|
|
10600 |
validate : true,
|
|
10601 |
entity_encoding : 'named',
|
|
10602 |
url_converter : t.convertURL,
|
|
10603 |
url_converter_scope : t,
|
|
10604 |
ie7_compat : true
|
d9344f
|
10605 |
}, s);
|
S |
10606 |
|
|
10607 |
t.documentBaseURI = new tinymce.util.URI(s.document_base_url || tinymce.documentBaseURL, {
|
|
10608 |
base_uri : tinyMCE.baseURI
|
|
10609 |
});
|
58fb65
|
10610 |
|
69d05c
|
10611 |
t.baseURI = tinymce.baseURI;
|
a9251b
|
10612 |
|
T |
10613 |
t.contentCSS = [];
|
d9344f
|
10614 |
|
S |
10615 |
// Call setup
|
|
10616 |
t.execCallback('setup', t);
|
|
10617 |
},
|
|
10618 |
|
|
10619 |
render : function(nst) {
|
|
10620 |
var t = this, s = t.settings, id = t.id, sl = tinymce.ScriptLoader;
|
|
10621 |
|
|
10622 |
// Page is not loaded yet, wait for it
|
|
10623 |
if (!Event.domLoaded) {
|
|
10624 |
Event.add(document, 'init', function() {
|
|
10625 |
t.render();
|
|
10626 |
});
|
|
10627 |
return;
|
|
10628 |
}
|
|
10629 |
|
69d05c
|
10630 |
tinyMCE.settings = s;
|
d9344f
|
10631 |
|
S |
10632 |
// Element not found, then skip initialization
|
|
10633 |
if (!t.getElement())
|
|
10634 |
return;
|
|
10635 |
|
2011be
|
10636 |
// Is a iPad/iPhone, then skip initialization. We need to sniff here since the
|
A |
10637 |
// browser says it has contentEditable support but there is no visible caret
|
|
10638 |
// We will remove this check ones Apple implements full contentEditable support
|
|
10639 |
if (tinymce.isIDevice)
|
|
10640 |
return;
|
|
10641 |
|
d9344f
|
10642 |
// Add hidden input for non input elements inside form elements
|
S |
10643 |
if (!/TEXTAREA|INPUT/i.test(t.getElement().nodeName) && s.hidden_input && DOM.getParent(id, 'form'))
|
|
10644 |
DOM.insertAfter(DOM.create('input', {type : 'hidden', name : id}), id);
|
|
10645 |
|
29da64
|
10646 |
if (tinymce.WindowManager)
|
A |
10647 |
t.windowManager = new tinymce.WindowManager(t);
|
d9344f
|
10648 |
|
S |
10649 |
if (s.encoding == 'xml') {
|
|
10650 |
t.onGetContent.add(function(ed, o) {
|
18240a
|
10651 |
if (o.save)
|
d9344f
|
10652 |
o.content = DOM.encode(o.content);
|
S |
10653 |
});
|
|
10654 |
}
|
|
10655 |
|
|
10656 |
if (s.add_form_submit_trigger) {
|
|
10657 |
t.onSubmit.addToTop(function() {
|
|
10658 |
if (t.initialized) {
|
|
10659 |
t.save();
|
|
10660 |
t.isNotDirty = 1;
|
|
10661 |
}
|
|
10662 |
});
|
|
10663 |
}
|
|
10664 |
|
29da64
|
10665 |
if (s.add_unload_trigger) {
|
d9344f
|
10666 |
t._beforeUnload = tinyMCE.onBeforeUnload.add(function() {
|
18240a
|
10667 |
if (t.initialized && !t.destroyed && !t.isHidden())
|
d9344f
|
10668 |
t.save({format : 'raw', no_events : true});
|
S |
10669 |
});
|
|
10670 |
}
|
|
10671 |
|
|
10672 |
tinymce.addUnload(t.destroy, t);
|
|
10673 |
|
|
10674 |
if (s.submit_patch) {
|
|
10675 |
t.onBeforeRenderUI.add(function() {
|
|
10676 |
var n = t.getElement().form;
|
|
10677 |
|
|
10678 |
if (!n)
|
|
10679 |
return;
|
|
10680 |
|
|
10681 |
// Already patched
|
|
10682 |
if (n._mceOldSubmit)
|
|
10683 |
return;
|
|
10684 |
|
|
10685 |
// Check page uses id="submit" or name="submit" for it's submit button
|
|
10686 |
if (!n.submit.nodeType && !n.submit.length) {
|
|
10687 |
t.formElement = n;
|
|
10688 |
n._mceOldSubmit = n.submit;
|
|
10689 |
n.submit = function() {
|
|
10690 |
// Save all instances
|
69d05c
|
10691 |
tinymce.triggerSave();
|
d9344f
|
10692 |
t.isNotDirty = 1;
|
S |
10693 |
|
29da64
|
10694 |
return t.formElement._mceOldSubmit(t.formElement);
|
d9344f
|
10695 |
};
|
S |
10696 |
}
|
|
10697 |
|
|
10698 |
n = null;
|
|
10699 |
});
|
|
10700 |
}
|
|
10701 |
|
|
10702 |
// Load scripts
|
|
10703 |
function loadScripts() {
|
a9251b
|
10704 |
if (s.language && s.language_load !== false)
|
d9344f
|
10705 |
sl.add(tinymce.baseURL + '/langs/' + s.language + '.js');
|
S |
10706 |
|
29da64
|
10707 |
if (s.theme && s.theme.charAt(0) != '-' && !ThemeManager.urls[s.theme])
|
d9344f
|
10708 |
ThemeManager.load(s.theme, 'themes/' + s.theme + '/editor_template' + tinymce.suffix + '.js');
|
S |
10709 |
|
|
10710 |
each(explode(s.plugins), function(p) {
|
|
10711 |
if (p && p.charAt(0) != '-' && !PluginManager.urls[p]) {
|
69d05c
|
10712 |
// Skip safari plugin, since it is removed as of 3.3b1
|
A |
10713 |
if (p == 'safari')
|
d9344f
|
10714 |
return;
|
S |
10715 |
|
|
10716 |
PluginManager.load(p, 'plugins/' + p + '/editor_plugin' + tinymce.suffix + '.js');
|
|
10717 |
}
|
|
10718 |
});
|
|
10719 |
|
|
10720 |
// Init when que is loaded
|
|
10721 |
sl.loadQueue(function() {
|
|
10722 |
if (!t.removed)
|
|
10723 |
t.init();
|
|
10724 |
});
|
|
10725 |
};
|
|
10726 |
|
58fb65
|
10727 |
loadScripts();
|
d9344f
|
10728 |
},
|
S |
10729 |
|
|
10730 |
init : function() {
|
a9251b
|
10731 |
var n, t = this, s = t.settings, w, h, e = t.getElement(), o, ti, u, bi, bc, re, i;
|
d9344f
|
10732 |
|
69d05c
|
10733 |
tinymce.add(t);
|
a9251b
|
10734 |
|
T |
10735 |
s.aria_label = s.aria_label || DOM.getAttrib(e, 'aria-label', t.getLang('aria.rich_text_area'));
|
d9344f
|
10736 |
|
29da64
|
10737 |
if (s.theme) {
|
A |
10738 |
s.theme = s.theme.replace(/-/, '');
|
|
10739 |
o = ThemeManager.get(s.theme);
|
|
10740 |
t.theme = new o();
|
d9344f
|
10741 |
|
29da64
|
10742 |
if (t.theme.init && s.init_theme)
|
A |
10743 |
t.theme.init(t, ThemeManager.urls[s.theme] || tinymce.documentBaseURL.replace(/\/$/, ''));
|
|
10744 |
}
|
d9344f
|
10745 |
|
S |
10746 |
// Create all plugins
|
|
10747 |
each(explode(s.plugins.replace(/\-/g, '')), function(p) {
|
|
10748 |
var c = PluginManager.get(p), u = PluginManager.urls[p] || tinymce.documentBaseURL.replace(/\/$/, ''), po;
|
|
10749 |
|
|
10750 |
if (c) {
|
|
10751 |
po = new c(t, u);
|
|
10752 |
|
|
10753 |
t.plugins[p] = po;
|
|
10754 |
|
|
10755 |
if (po.init)
|
|
10756 |
po.init(t, u);
|
|
10757 |
}
|
|
10758 |
});
|
|
10759 |
|
|
10760 |
// Setup popup CSS path(s)
|
29da64
|
10761 |
if (s.popup_css !== false) {
|
A |
10762 |
if (s.popup_css)
|
|
10763 |
s.popup_css = t.documentBaseURI.toAbsolute(s.popup_css);
|
|
10764 |
else
|
|
10765 |
s.popup_css = t.baseURI.toAbsolute("themes/" + s.theme + "/skins/" + s.skin + "/dialog.css");
|
|
10766 |
}
|
d9344f
|
10767 |
|
S |
10768 |
if (s.popup_css_add)
|
|
10769 |
s.popup_css += ',' + t.documentBaseURI.toAbsolute(s.popup_css_add);
|
|
10770 |
|
|
10771 |
t.controlManager = new tinymce.ControlManager(t);
|
58fb65
|
10772 |
|
d9344f
|
10773 |
if (s.custom_undo_redo) {
|
69d05c
|
10774 |
t.onBeforeExecCommand.add(function(ed, cmd, ui, val, a) {
|
a9251b
|
10775 |
if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint' && (!a || !a.skip_undo))
|
T |
10776 |
t.undoManager.beforeChange();
|
69d05c
|
10777 |
});
|
A |
10778 |
|
d9344f
|
10779 |
t.onExecCommand.add(function(ed, cmd, ui, val, a) {
|
S |
10780 |
if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint' && (!a || !a.skip_undo))
|
|
10781 |
t.undoManager.add();
|
|
10782 |
});
|
|
10783 |
}
|
|
10784 |
|
|
10785 |
t.onExecCommand.add(function(ed, c) {
|
|
10786 |
// Don't refresh the select lists until caret move
|
|
10787 |
if (!/^(FontName|FontSize)$/.test(c))
|
|
10788 |
t.nodeChanged();
|
|
10789 |
});
|
|
10790 |
|
|
10791 |
// Remove ghost selections on images and tables in Gecko
|
|
10792 |
if (isGecko) {
|
|
10793 |
function repaint(a, o) {
|
|
10794 |
if (!o || !o.initial)
|
|
10795 |
t.execCommand('mceRepaint');
|
|
10796 |
};
|
|
10797 |
|
|
10798 |
t.onUndo.add(repaint);
|
|
10799 |
t.onRedo.add(repaint);
|
|
10800 |
t.onSetContent.add(repaint);
|
|
10801 |
}
|
|
10802 |
|
|
10803 |
// Enables users to override the control factory
|
|
10804 |
t.onBeforeRenderUI.dispatch(t, t.controlManager);
|
|
10805 |
|
|
10806 |
// Measure box
|
|
10807 |
if (s.render_ui) {
|
18240a
|
10808 |
w = s.width || e.style.width || e.offsetWidth;
|
A |
10809 |
h = s.height || e.style.height || e.offsetHeight;
|
d9344f
|
10810 |
t.orgDisplay = e.style.display;
|
S |
10811 |
re = /^[0-9\.]+(|px)$/i;
|
|
10812 |
|
|
10813 |
if (re.test('' + w))
|
|
10814 |
w = Math.max(parseInt(w) + (o.deltaWidth || 0), 100);
|
|
10815 |
|
|
10816 |
if (re.test('' + h))
|
|
10817 |
h = Math.max(parseInt(h) + (o.deltaHeight || 0), 100);
|
|
10818 |
|
|
10819 |
// Render UI
|
|
10820 |
o = t.theme.renderUI({
|
|
10821 |
targetNode : e,
|
|
10822 |
width : w,
|
|
10823 |
height : h,
|
|
10824 |
deltaWidth : s.delta_width,
|
|
10825 |
deltaHeight : s.delta_height
|
|
10826 |
});
|
|
10827 |
|
|
10828 |
t.editorContainer = o.editorContainer;
|
|
10829 |
}
|
|
10830 |
|
29da64
|
10831 |
|
58fb65
|
10832 |
// User specified a document.domain value
|
A |
10833 |
if (document.domain && location.hostname != document.domain)
|
|
10834 |
tinymce.relaxedDomain = document.domain;
|
|
10835 |
|
d9344f
|
10836 |
// Resize editor
|
S |
10837 |
DOM.setStyles(o.sizeContainer || o.editorContainer, {
|
|
10838 |
width : w,
|
|
10839 |
height : h
|
|
10840 |
});
|
|
10841 |
|
a9251b
|
10842 |
// Load specified content CSS last
|
T |
10843 |
if (s.content_css) {
|
|
10844 |
tinymce.each(explode(s.content_css), function(u) {
|
|
10845 |
t.contentCSS.push(t.documentBaseURI.toAbsolute(u));
|
|
10846 |
});
|
|
10847 |
}
|
|
10848 |
|
29da64
|
10849 |
h = (o.iframeHeight || h) + (typeof(h) == 'number' ? (o.deltaHeight || 0) : '');
|
d9344f
|
10850 |
if (h < 100)
|
S |
10851 |
h = 100;
|
|
10852 |
|
58fb65
|
10853 |
t.iframeHTML = s.doctype + '<html><head xmlns="http://www.w3.org/1999/xhtml">';
|
A |
10854 |
|
|
10855 |
// We only need to override paths if we have to
|
|
10856 |
// IE has a bug where it remove site absolute urls to relative ones if this is specified
|
|
10857 |
if (s.document_base_url != tinymce.documentBaseURL)
|
|
10858 |
t.iframeHTML += '<base href="' + t.documentBaseURI.getURI() + '" />';
|
|
10859 |
|
a9251b
|
10860 |
// IE8 doesn't support carets behind images setting ie7_compat would force IE8+ to run in IE7 compat mode.
|
T |
10861 |
if (s.ie7_compat)
|
|
10862 |
t.iframeHTML += '<meta http-equiv="X-UA-Compatible" content="IE=7" />';
|
|
10863 |
else
|
|
10864 |
t.iframeHTML += '<meta http-equiv="X-UA-Compatible" content="IE=edge" />';
|
d9344f
|
10865 |
|
a9251b
|
10866 |
t.iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
|
T |
10867 |
|
|
10868 |
// Firefox 2 doesn't load stylesheets correctly this way
|
|
10869 |
if (!isGecko || !/Firefox\/2/.test(navigator.userAgent)) {
|
|
10870 |
for (i = 0; i < t.contentCSS.length; i++)
|
|
10871 |
t.iframeHTML += '<link type="text/css" rel="stylesheet" href="' + t.contentCSS[i] + '" />';
|
|
10872 |
|
|
10873 |
t.contentCSS = [];
|
|
10874 |
}
|
d9344f
|
10875 |
|
S |
10876 |
bi = s.body_id || 'tinymce';
|
|
10877 |
if (bi.indexOf('=') != -1) {
|
|
10878 |
bi = t.getParam('body_id', '', 'hash');
|
|
10879 |
bi = bi[t.id] || bi;
|
|
10880 |
}
|
|
10881 |
|
|
10882 |
bc = s.body_class || '';
|
|
10883 |
if (bc.indexOf('=') != -1) {
|
|
10884 |
bc = t.getParam('body_class', '', 'hash');
|
|
10885 |
bc = bc[t.id] || '';
|
|
10886 |
}
|
|
10887 |
|
|
10888 |
t.iframeHTML += '</head><body id="' + bi + '" class="mceContentBody ' + bc + '"></body></html>';
|
|
10889 |
|
|
10890 |
// Domain relaxing enabled, then set document domain
|
a9251b
|
10891 |
if (tinymce.relaxedDomain && (isIE || (tinymce.isOpera && parseFloat(opera.version()) < 11))) {
|
d9344f
|
10892 |
// We need to write the contents here in IE since multiple writes messes up refresh button and back button
|
a9251b
|
10893 |
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();})()';
|
d9344f
|
10894 |
}
|
S |
10895 |
|
|
10896 |
// Create iframe
|
a9251b
|
10897 |
// TODO: ACC add the appropriate description on this.
|
T |
10898 |
n = DOM.add(o.iframeContainer, 'iframe', {
|
d9344f
|
10899 |
id : t.id + "_ifr",
|
S |
10900 |
src : u || 'javascript:""', // Workaround for HTTPS warning in IE6/7
|
a9251b
|
10901 |
frameBorder : '0',
|
T |
10902 |
title : s.aria_label,
|
d9344f
|
10903 |
style : {
|
S |
10904 |
width : '100%',
|
|
10905 |
height : h
|
|
10906 |
}
|
|
10907 |
});
|
|
10908 |
|
|
10909 |
t.contentAreaContainer = o.iframeContainer;
|
|
10910 |
DOM.get(o.editorContainer).style.display = t.orgDisplay;
|
|
10911 |
DOM.get(t.id).style.display = 'none';
|
a9251b
|
10912 |
DOM.setAttrib(t.id, 'aria-hidden', true);
|
d9344f
|
10913 |
|
a9251b
|
10914 |
if (!tinymce.relaxedDomain || !u)
|
29da64
|
10915 |
t.setupIframe();
|
d9344f
|
10916 |
|
29da64
|
10917 |
e = n = o = null; // Cleanup
|
d9344f
|
10918 |
},
|
S |
10919 |
|
|
10920 |
setupIframe : function() {
|
|
10921 |
var t = this, s = t.settings, e = DOM.get(t.id), d = t.getDoc(), h, b;
|
|
10922 |
|
|
10923 |
// Setup iframe body
|
|
10924 |
if (!isIE || !tinymce.relaxedDomain) {
|
|
10925 |
d.open();
|
|
10926 |
d.write(t.iframeHTML);
|
|
10927 |
d.close();
|
a9251b
|
10928 |
|
T |
10929 |
if (tinymce.relaxedDomain)
|
|
10930 |
d.domain = tinymce.relaxedDomain;
|
d9344f
|
10931 |
}
|
S |
10932 |
|
|
10933 |
// Design mode needs to be added here Ctrl+A will fail otherwise
|
|
10934 |
if (!isIE) {
|
|
10935 |
try {
|
29da64
|
10936 |
if (!s.readonly)
|
A |
10937 |
d.designMode = 'On';
|
d9344f
|
10938 |
} catch (ex) {
|
S |
10939 |
// Will fail on Gecko if the editor is placed in an hidden container element
|
|
10940 |
// The design mode will be set ones the editor is focused
|
|
10941 |
}
|
|
10942 |
}
|
|
10943 |
|
|
10944 |
// IE needs to use contentEditable or it will display non secure items for HTTPS
|
|
10945 |
if (isIE) {
|
|
10946 |
// It will not steal focus if we hide it while setting contentEditable
|
|
10947 |
b = t.getBody();
|
|
10948 |
DOM.hide(b);
|
29da64
|
10949 |
|
A |
10950 |
if (!s.readonly)
|
|
10951 |
b.contentEditable = true;
|
|
10952 |
|
d9344f
|
10953 |
DOM.show(b);
|
S |
10954 |
}
|
|
10955 |
|
a9251b
|
10956 |
t.schema = new tinymce.html.Schema(s);
|
T |
10957 |
|
58fb65
|
10958 |
t.dom = new tinymce.dom.DOMUtils(t.getDoc(), {
|
d9344f
|
10959 |
keep_values : true,
|
S |
10960 |
url_converter : t.convertURL,
|
|
10961 |
url_converter_scope : t,
|
|
10962 |
hex_colors : s.force_hex_style_colors,
|
|
10963 |
class_filter : s.class_filter,
|
|
10964 |
update_styles : 1,
|
69d05c
|
10965 |
fix_ie_paragraphs : 1,
|
a9251b
|
10966 |
schema : t.schema
|
d9344f
|
10967 |
});
|
69d05c
|
10968 |
|
a9251b
|
10969 |
t.parser = new tinymce.html.DomParser(s, t.schema);
|
d9344f
|
10970 |
|
a9251b
|
10971 |
// Force anchor names closed
|
T |
10972 |
t.parser.addAttributeFilter('name', function(nodes, name) {
|
|
10973 |
var i = nodes.length, sibling, prevSibling, parent, node;
|
|
10974 |
|
|
10975 |
while (i--) {
|
|
10976 |
node = nodes[i];
|
|
10977 |
if (node.name === 'a' && node.firstChild) {
|
|
10978 |
parent = node.parent;
|
|
10979 |
|
|
10980 |
// Move children after current node
|
|
10981 |
sibling = node.lastChild;
|
|
10982 |
do {
|
|
10983 |
prevSibling = sibling.prev;
|
|
10984 |
parent.insert(sibling, node);
|
|
10985 |
sibling = prevSibling;
|
|
10986 |
} while (sibling);
|
|
10987 |
}
|
|
10988 |
}
|
|
10989 |
});
|
|
10990 |
|
|
10991 |
// Convert src and href into data-mce-src, data-mce-href and data-mce-style
|
|
10992 |
t.parser.addAttributeFilter('src,href,style', function(nodes, name) {
|
|
10993 |
var i = nodes.length, node, dom = t.dom, value;
|
|
10994 |
|
|
10995 |
while (i--) {
|
|
10996 |
node = nodes[i];
|
|
10997 |
value = node.attr(name);
|
|
10998 |
|
|
10999 |
if (name === "style")
|
|
11000 |
node.attr('data-mce-style', dom.serializeStyle(dom.parseStyle(value), node.name));
|
|
11001 |
else
|
|
11002 |
node.attr('data-mce-' + name, t.convertURL(value, name, node.name));
|
|
11003 |
}
|
|
11004 |
});
|
|
11005 |
|
|
11006 |
// Keep scripts from executing
|
|
11007 |
t.parser.addNodeFilter('script', function(nodes, name) {
|
|
11008 |
var i = nodes.length;
|
|
11009 |
|
|
11010 |
while (i--)
|
|
11011 |
nodes[i].attr('type', 'mce-text/javascript');
|
|
11012 |
});
|
|
11013 |
|
|
11014 |
t.parser.addNodeFilter('#cdata', function(nodes, name) {
|
|
11015 |
var i = nodes.length, node;
|
|
11016 |
|
|
11017 |
while (i--) {
|
|
11018 |
node = nodes[i];
|
|
11019 |
node.type = 8;
|
|
11020 |
node.name = '#comment';
|
|
11021 |
node.value = '[CDATA[' + node.value + ']]';
|
|
11022 |
}
|
|
11023 |
});
|
|
11024 |
|
|
11025 |
t.parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', function(nodes, name) {
|
|
11026 |
var i = nodes.length, node, nonEmptyElements = t.schema.getNonEmptyElements();
|
|
11027 |
|
|
11028 |
while (i--) {
|
|
11029 |
node = nodes[i];
|
|
11030 |
|
|
11031 |
if (node.isEmpty(nonEmptyElements))
|
|
11032 |
node.empty().append(new tinymce.html.Node('br', 1)).shortEnded = true;
|
|
11033 |
}
|
|
11034 |
});
|
|
11035 |
|
|
11036 |
t.serializer = new tinymce.dom.Serializer(s, t.dom, t.schema);
|
d9344f
|
11037 |
|
S |
11038 |
t.selection = new tinymce.dom.Selection(t.dom, t.getWin(), t.serializer);
|
58fb65
|
11039 |
|
69d05c
|
11040 |
t.formatter = new tinymce.Formatter(this);
|
A |
11041 |
|
|
11042 |
// Register default formats
|
|
11043 |
t.formatter.register({
|
|
11044 |
alignleft : [
|
|
11045 |
{selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}},
|
a9251b
|
11046 |
{selector : 'img,table', collapsed : false, styles : {'float' : 'left'}}
|
69d05c
|
11047 |
],
|
A |
11048 |
|
|
11049 |
aligncenter : [
|
|
11050 |
{selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}},
|
a9251b
|
11051 |
{selector : 'img', collapsed : false, styles : {display : 'block', marginLeft : 'auto', marginRight : 'auto'}},
|
T |
11052 |
{selector : 'table', collapsed : false, styles : {marginLeft : 'auto', marginRight : 'auto'}}
|
69d05c
|
11053 |
],
|
A |
11054 |
|
|
11055 |
alignright : [
|
|
11056 |
{selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}},
|
a9251b
|
11057 |
{selector : 'img,table', collapsed : false, styles : {'float' : 'right'}}
|
69d05c
|
11058 |
],
|
A |
11059 |
|
|
11060 |
alignfull : [
|
|
11061 |
{selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'justify'}}
|
|
11062 |
],
|
|
11063 |
|
|
11064 |
bold : [
|
a9251b
|
11065 |
{inline : 'strong', remove : 'all'},
|
69d05c
|
11066 |
{inline : 'span', styles : {fontWeight : 'bold'}},
|
a9251b
|
11067 |
{inline : 'b', remove : 'all'}
|
69d05c
|
11068 |
],
|
A |
11069 |
|
|
11070 |
italic : [
|
a9251b
|
11071 |
{inline : 'em', remove : 'all'},
|
69d05c
|
11072 |
{inline : 'span', styles : {fontStyle : 'italic'}},
|
a9251b
|
11073 |
{inline : 'i', remove : 'all'}
|
69d05c
|
11074 |
],
|
A |
11075 |
|
|
11076 |
underline : [
|
|
11077 |
{inline : 'span', styles : {textDecoration : 'underline'}, exact : true},
|
a9251b
|
11078 |
{inline : 'u', remove : 'all'}
|
69d05c
|
11079 |
],
|
A |
11080 |
|
|
11081 |
strikethrough : [
|
|
11082 |
{inline : 'span', styles : {textDecoration : 'line-through'}, exact : true},
|
a9251b
|
11083 |
{inline : 'strike', remove : 'all'}
|
69d05c
|
11084 |
],
|
A |
11085 |
|
a9251b
|
11086 |
forecolor : {inline : 'span', styles : {color : '%value'}, wrap_links : false},
|
T |
11087 |
hilitecolor : {inline : 'span', styles : {backgroundColor : '%value'}, wrap_links : false},
|
69d05c
|
11088 |
fontname : {inline : 'span', styles : {fontFamily : '%value'}},
|
A |
11089 |
fontsize : {inline : 'span', styles : {fontSize : '%value'}},
|
2011be
|
11090 |
fontsize_class : {inline : 'span', attributes : {'class' : '%value'}},
|
799907
|
11091 |
blockquote : {block : 'blockquote', wrapper : 1, remove : 'all'},
|
a9251b
|
11092 |
subscript : {inline : 'sub'},
|
T |
11093 |
superscript : {inline : 'sup'},
|
69d05c
|
11094 |
|
A |
11095 |
removeformat : [
|
|
11096 |
{selector : 'b,strong,em,i,font,u,strike', remove : 'all', split : true, expand : false, block_expand : true, deep : true},
|
|
11097 |
{selector : 'span', attributes : ['style', 'class'], remove : 'empty', split : true, expand : false, deep : true},
|
|
11098 |
{selector : '*', attributes : ['style', 'class'], split : false, expand : false, deep : true}
|
|
11099 |
]
|
|
11100 |
});
|
|
11101 |
|
|
11102 |
// Register default block formats
|
|
11103 |
each('p h1 h2 h3 h4 h5 h6 div address pre div code dt dd samp'.split(/\s/), function(name) {
|
799907
|
11104 |
t.formatter.register(name, {block : name, remove : 'all'});
|
69d05c
|
11105 |
});
|
A |
11106 |
|
|
11107 |
// Register user defined formats
|
|
11108 |
t.formatter.register(t.settings.formats);
|
|
11109 |
|
|
11110 |
t.undoManager = new tinymce.UndoManager(t);
|
|
11111 |
|
|
11112 |
// Pass through
|
|
11113 |
t.undoManager.onAdd.add(function(um, l) {
|
a9251b
|
11114 |
if (um.hasUndo())
|
69d05c
|
11115 |
return t.onChange.dispatch(t, l, um);
|
A |
11116 |
});
|
|
11117 |
|
|
11118 |
t.undoManager.onUndo.add(function(um, l) {
|
|
11119 |
return t.onUndo.dispatch(t, l, um);
|
|
11120 |
});
|
|
11121 |
|
|
11122 |
t.undoManager.onRedo.add(function(um, l) {
|
|
11123 |
return t.onRedo.dispatch(t, l, um);
|
|
11124 |
});
|
|
11125 |
|
d9344f
|
11126 |
t.forceBlocks = new tinymce.ForceBlocks(t, {
|
S |
11127 |
forced_root_block : s.forced_root_block
|
|
11128 |
});
|
69d05c
|
11129 |
|
d9344f
|
11130 |
t.editorCommands = new tinymce.EditorCommands(t);
|
S |
11131 |
|
|
11132 |
// Pass through
|
|
11133 |
t.serializer.onPreProcess.add(function(se, o) {
|
|
11134 |
return t.onPreProcess.dispatch(t, o, se);
|
|
11135 |
});
|
|
11136 |
|
|
11137 |
t.serializer.onPostProcess.add(function(se, o) {
|
|
11138 |
return t.onPostProcess.dispatch(t, o, se);
|
|
11139 |
});
|
|
11140 |
|
|
11141 |
t.onPreInit.dispatch(t);
|
|
11142 |
|
|
11143 |
if (!s.gecko_spellcheck)
|
|
11144 |
t.getBody().spellcheck = 0;
|
|
11145 |
|
29da64
|
11146 |
if (!s.readonly)
|
A |
11147 |
t._addEvents();
|
d9344f
|
11148 |
|
S |
11149 |
t.controlManager.onPostRender.dispatch(t, t.controlManager);
|
|
11150 |
t.onPostRender.dispatch(t);
|
|
11151 |
|
|
11152 |
if (s.directionality)
|
|
11153 |
t.getBody().dir = s.directionality;
|
|
11154 |
|
|
11155 |
if (s.nowrap)
|
|
11156 |
t.getBody().style.whiteSpace = "nowrap";
|
|
11157 |
|
|
11158 |
if (s.handle_node_change_callback) {
|
|
11159 |
t.onNodeChange.add(function(ed, cm, n) {
|
|
11160 |
t.execCallback('handle_node_change_callback', t.id, n, -1, -1, true, t.selection.isCollapsed());
|
|
11161 |
});
|
|
11162 |
}
|
|
11163 |
|
|
11164 |
if (s.save_callback) {
|
|
11165 |
t.onSaveContent.add(function(ed, o) {
|
|
11166 |
var h = t.execCallback('save_callback', t.id, o.content, t.getBody());
|
|
11167 |
|
|
11168 |
if (h)
|
|
11169 |
o.content = h;
|
|
11170 |
});
|
|
11171 |
}
|
|
11172 |
|
|
11173 |
if (s.onchange_callback) {
|
|
11174 |
t.onChange.add(function(ed, l) {
|
|
11175 |
t.execCallback('onchange_callback', t, l);
|
|
11176 |
});
|
|
11177 |
}
|
|
11178 |
|
a9251b
|
11179 |
if (s.protect) {
|
T |
11180 |
t.onBeforeSetContent.add(function(ed, o) {
|
|
11181 |
if (s.protect) {
|
|
11182 |
each(s.protect, function(pattern) {
|
|
11183 |
o.content = o.content.replace(pattern, function(str) {
|
|
11184 |
return '<!--mce:protected ' + escape(str) + '-->';
|
|
11185 |
});
|
|
11186 |
});
|
|
11187 |
}
|
|
11188 |
});
|
|
11189 |
}
|
|
11190 |
|
d9344f
|
11191 |
if (s.convert_newlines_to_brs) {
|
S |
11192 |
t.onBeforeSetContent.add(function(ed, o) {
|
|
11193 |
if (o.initial)
|
|
11194 |
o.content = o.content.replace(/\r?\n/g, '<br />');
|
|
11195 |
});
|
|
11196 |
}
|
|
11197 |
|
|
11198 |
if (s.preformatted) {
|
|
11199 |
t.onPostProcess.add(function(ed, o) {
|
|
11200 |
o.content = o.content.replace(/^\s*<pre.*?>/, '');
|
|
11201 |
o.content = o.content.replace(/<\/pre>\s*$/, '');
|
|
11202 |
|
|
11203 |
if (o.set)
|
|
11204 |
o.content = '<pre class="mceItemHidden">' + o.content + '</pre>';
|
|
11205 |
});
|
|
11206 |
}
|
|
11207 |
|
|
11208 |
if (s.verify_css_classes) {
|
|
11209 |
t.serializer.attribValueFilter = function(n, v) {
|
|
11210 |
var s, cl;
|
|
11211 |
|
|
11212 |
if (n == 'class') {
|
|
11213 |
// Build regexp for classes
|
|
11214 |
if (!t.classesRE) {
|
|
11215 |
cl = t.dom.getClasses();
|
|
11216 |
|
|
11217 |
if (cl.length > 0) {
|
|
11218 |
s = '';
|
|
11219 |
|
|
11220 |
each (cl, function(o) {
|
|
11221 |
s += (s ? '|' : '') + o['class'];
|
|
11222 |
});
|
|
11223 |
|
|
11224 |
t.classesRE = new RegExp('(' + s + ')', 'gi');
|
|
11225 |
}
|
|
11226 |
}
|
|
11227 |
|
|
11228 |
return !t.classesRE || /(\bmceItem\w+\b|\bmceTemp\w+\b)/g.test(v) || t.classesRE.test(v) ? v : '';
|
|
11229 |
}
|
|
11230 |
|
|
11231 |
return v;
|
|
11232 |
};
|
|
11233 |
}
|
|
11234 |
|
|
11235 |
if (s.cleanup_callback) {
|
|
11236 |
t.onBeforeSetContent.add(function(ed, o) {
|
|
11237 |
o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);
|
|
11238 |
});
|
|
11239 |
|
|
11240 |
t.onPreProcess.add(function(ed, o) {
|
|
11241 |
if (o.set)
|
|
11242 |
t.execCallback('cleanup_callback', 'insert_to_editor_dom', o.node, o);
|
|
11243 |
|
|
11244 |
if (o.get)
|
|
11245 |
t.execCallback('cleanup_callback', 'get_from_editor_dom', o.node, o);
|
|
11246 |
});
|
|
11247 |
|
|
11248 |
t.onPostProcess.add(function(ed, o) {
|
|
11249 |
if (o.set)
|
|
11250 |
o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);
|
|
11251 |
|
|
11252 |
if (o.get)
|
|
11253 |
o.content = t.execCallback('cleanup_callback', 'get_from_editor', o.content, o);
|
|
11254 |
});
|
|
11255 |
}
|
|
11256 |
|
|
11257 |
if (s.save_callback) {
|
|
11258 |
t.onGetContent.add(function(ed, o) {
|
|
11259 |
if (o.save)
|
|
11260 |
o.content = t.execCallback('save_callback', t.id, o.content, t.getBody());
|
|
11261 |
});
|
|
11262 |
}
|
|
11263 |
|
|
11264 |
if (s.handle_event_callback) {
|
|
11265 |
t.onEvent.add(function(ed, e, o) {
|
|
11266 |
if (t.execCallback('handle_event_callback', e, ed, o) === false)
|
|
11267 |
Event.cancel(e);
|
|
11268 |
});
|
|
11269 |
}
|
|
11270 |
|
29da64
|
11271 |
// Add visual aids when new contents is added
|
d9344f
|
11272 |
t.onSetContent.add(function() {
|
29da64
|
11273 |
t.addVisual(t.getBody());
|
d9344f
|
11274 |
});
|
S |
11275 |
|
|
11276 |
// Remove empty contents
|
|
11277 |
if (s.padd_empty_editor) {
|
|
11278 |
t.onPostProcess.add(function(ed, o) {
|
29da64
|
11279 |
o.content = o.content.replace(/^(<p[^>]*>( | |\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/, '');
|
d9344f
|
11280 |
});
|
S |
11281 |
}
|
|
11282 |
|
|
11283 |
if (isGecko) {
|
29da64
|
11284 |
// Fix gecko link bug, when a link is placed at the end of block elements there is
|
A |
11285 |
// no way to move the caret behind the link. This fix adds a bogus br element after the link
|
|
11286 |
function fixLinks(ed, o) {
|
|
11287 |
each(ed.dom.select('a'), function(n) {
|
|
11288 |
var pn = n.parentNode;
|
|
11289 |
|
|
11290 |
if (ed.dom.isBlock(pn) && pn.lastChild === n)
|
a9251b
|
11291 |
ed.dom.add(pn, 'br', {'data-mce-bogus' : 1});
|
29da64
|
11292 |
});
|
A |
11293 |
};
|
|
11294 |
|
|
11295 |
t.onExecCommand.add(function(ed, cmd) {
|
|
11296 |
if (cmd === 'CreateLink')
|
|
11297 |
fixLinks(ed);
|
|
11298 |
});
|
|
11299 |
|
|
11300 |
t.onSetContent.add(t.selection.onSetContent.add(fixLinks));
|
|
11301 |
|
|
11302 |
if (!s.readonly) {
|
|
11303 |
try {
|
|
11304 |
// Design mode must be set here once again to fix a bug where
|
|
11305 |
// Ctrl+A/Delete/Backspace didn't work if the editor was added using mceAddControl then removed then added again
|
|
11306 |
d.designMode = 'Off';
|
|
11307 |
d.designMode = 'On';
|
|
11308 |
} catch (ex) {
|
|
11309 |
// Will fail on Gecko if the editor is placed in an hidden container element
|
|
11310 |
// The design mode will be set ones the editor is focused
|
|
11311 |
}
|
d9344f
|
11312 |
}
|
S |
11313 |
}
|
|
11314 |
|
|
11315 |
// A small timeout was needed since firefox will remove. Bug: #1838304
|
|
11316 |
setTimeout(function () {
|
|
11317 |
if (t.removed)
|
|
11318 |
return;
|
|
11319 |
|
a9251b
|
11320 |
t.load({initial : true, format : 'html'});
|
d9344f
|
11321 |
t.startContent = t.getContent({format : 'raw'});
|
a9251b
|
11322 |
t.undoManager.add();
|
d9344f
|
11323 |
t.initialized = true;
|
S |
11324 |
|
|
11325 |
t.onInit.dispatch(t);
|
|
11326 |
t.execCallback('setupcontent_callback', t.id, t.getBody(), t.getDoc());
|
|
11327 |
t.execCallback('init_instance_callback', t);
|
|
11328 |
t.focus(true);
|
|
11329 |
t.nodeChanged({initial : 1});
|
|
11330 |
|
|
11331 |
// Load specified content CSS last
|
a9251b
|
11332 |
each(t.contentCSS, function(u) {
|
T |
11333 |
t.dom.loadCSS(u);
|
|
11334 |
});
|
d9344f
|
11335 |
|
S |
11336 |
// Handle auto focus
|
|
11337 |
if (s.auto_focus) {
|
|
11338 |
setTimeout(function () {
|
69d05c
|
11339 |
var ed = tinymce.get(s.auto_focus);
|
d9344f
|
11340 |
|
S |
11341 |
ed.selection.select(ed.getBody(), 1);
|
|
11342 |
ed.selection.collapse(1);
|
|
11343 |
ed.getWin().focus();
|
|
11344 |
}, 100);
|
|
11345 |
}
|
|
11346 |
}, 1);
|
|
11347 |
|
|
11348 |
e = null;
|
|
11349 |
},
|
|
11350 |
|
29da64
|
11351 |
|
d9344f
|
11352 |
focus : function(sf) {
|
2011be
|
11353 |
var oed, t = this, ce = t.settings.content_editable, ieRng, controlElm, doc = t.getDoc();
|
d9344f
|
11354 |
|
S |
11355 |
if (!sf) {
|
2011be
|
11356 |
// Get selected control element
|
A |
11357 |
ieRng = t.selection.getRng();
|
|
11358 |
if (ieRng.item) {
|
|
11359 |
controlElm = ieRng.item(0);
|
|
11360 |
}
|
|
11361 |
|
69d05c
|
11362 |
// Is not content editable
|
A |
11363 |
if (!ce)
|
18240a
|
11364 |
t.getWin().focus();
|
2011be
|
11365 |
|
A |
11366 |
// Restore selected control element
|
|
11367 |
// This is needed when for example an image is selected within a
|
|
11368 |
// layer a call to focus will then remove the control selection
|
|
11369 |
if (controlElm && controlElm.ownerDocument == doc) {
|
|
11370 |
ieRng = doc.body.createControlRange();
|
|
11371 |
ieRng.addElement(controlElm);
|
|
11372 |
ieRng.select();
|
|
11373 |
}
|
d9344f
|
11374 |
|
29da64
|
11375 |
}
|
d9344f
|
11376 |
|
69d05c
|
11377 |
if (tinymce.activeEditor != t) {
|
A |
11378 |
if ((oed = tinymce.activeEditor) != null)
|
d9344f
|
11379 |
oed.onDeactivate.dispatch(oed, t);
|
S |
11380 |
|
|
11381 |
t.onActivate.dispatch(t, oed);
|
|
11382 |
}
|
|
11383 |
|
69d05c
|
11384 |
tinymce._setActive(t);
|
d9344f
|
11385 |
},
|
S |
11386 |
|
|
11387 |
execCallback : function(n) {
|
|
11388 |
var t = this, f = t.settings[n], s;
|
|
11389 |
|
|
11390 |
if (!f)
|
|
11391 |
return;
|
|
11392 |
|
|
11393 |
// Look through lookup
|
|
11394 |
if (t.callbackLookup && (s = t.callbackLookup[n])) {
|
|
11395 |
f = s.func;
|
|
11396 |
s = s.scope;
|
|
11397 |
}
|
|
11398 |
|
|
11399 |
if (is(f, 'string')) {
|
|
11400 |
s = f.replace(/\.\w+$/, '');
|
|
11401 |
s = s ? tinymce.resolve(s) : 0;
|
|
11402 |
f = tinymce.resolve(f);
|
|
11403 |
t.callbackLookup = t.callbackLookup || {};
|
|
11404 |
t.callbackLookup[n] = {func : f, scope : s};
|
|
11405 |
}
|
|
11406 |
|
|
11407 |
return f.apply(s || t, Array.prototype.slice.call(arguments, 1));
|
|
11408 |
},
|
|
11409 |
|
|
11410 |
translate : function(s) {
|
69d05c
|
11411 |
var c = this.settings.language || 'en', i18n = tinymce.i18n;
|
d9344f
|
11412 |
|
S |
11413 |
if (!s)
|
|
11414 |
return '';
|
|
11415 |
|
|
11416 |
return i18n[c + '.' + s] || s.replace(/{\#([^}]+)\}/g, function(a, b) {
|
|
11417 |
return i18n[c + '.' + b] || '{#' + b + '}';
|
|
11418 |
});
|
|
11419 |
},
|
|
11420 |
|
|
11421 |
getLang : function(n, dv) {
|
69d05c
|
11422 |
return tinymce.i18n[(this.settings.language || 'en') + '.' + n] || (is(dv) ? dv : '{#' + n + '}');
|
d9344f
|
11423 |
},
|
S |
11424 |
|
|
11425 |
getParam : function(n, dv, ty) {
|
|
11426 |
var tr = tinymce.trim, v = is(this.settings[n]) ? this.settings[n] : dv, o;
|
|
11427 |
|
|
11428 |
if (ty === 'hash') {
|
|
11429 |
o = {};
|
|
11430 |
|
|
11431 |
if (is(v, 'string')) {
|
|
11432 |
each(v.indexOf('=') > 0 ? v.split(/[;,](?![^=;,]*(?:[;,]|$))/) : v.split(','), function(v) {
|
|
11433 |
v = v.split('=');
|
|
11434 |
|
|
11435 |
if (v.length > 1)
|
|
11436 |
o[tr(v[0])] = tr(v[1]);
|
|
11437 |
else
|
|
11438 |
o[tr(v[0])] = tr(v);
|
|
11439 |
});
|
|
11440 |
} else
|
|
11441 |
o = v;
|
|
11442 |
|
|
11443 |
return o;
|
|
11444 |
}
|
|
11445 |
|
|
11446 |
return v;
|
|
11447 |
},
|
|
11448 |
|
|
11449 |
nodeChanged : function(o) {
|
a9251b
|
11450 |
var t = this, s = t.selection, n = s.getStart() || t.getBody();
|
d9344f
|
11451 |
|
S |
11452 |
// Fix for bug #1896577 it seems that this can not be fired while the editor is loading
|
|
11453 |
if (t.initialized) {
|
69d05c
|
11454 |
o = o || {};
|
A |
11455 |
n = isIE && n.ownerDocument != t.getDoc() ? t.getBody() : n; // Fix for IE initial state
|
|
11456 |
|
|
11457 |
// Get parents and add them to object
|
|
11458 |
o.parents = [];
|
|
11459 |
t.dom.getParent(n, function(node) {
|
|
11460 |
if (node.nodeName == 'BODY')
|
|
11461 |
return true;
|
|
11462 |
|
|
11463 |
o.parents.push(node);
|
|
11464 |
});
|
|
11465 |
|
d9344f
|
11466 |
t.onNodeChange.dispatch(
|
S |
11467 |
t,
|
|
11468 |
o ? o.controlManager || t.controlManager : t.controlManager,
|
69d05c
|
11469 |
n,
|
d9344f
|
11470 |
s.isCollapsed(),
|
S |
11471 |
o
|
|
11472 |
);
|
|
11473 |
}
|
|
11474 |
},
|
|
11475 |
|
|
11476 |
addButton : function(n, s) {
|
|
11477 |
var t = this;
|
|
11478 |
|
|
11479 |
t.buttons = t.buttons || {};
|
|
11480 |
t.buttons[n] = s;
|
|
11481 |
},
|
|
11482 |
|
a9251b
|
11483 |
addCommand : function(name, callback, scope) {
|
T |
11484 |
this.execCommands[name] = {func : callback, scope : scope || this};
|
d9344f
|
11485 |
},
|
S |
11486 |
|
a9251b
|
11487 |
addQueryStateHandler : function(name, callback, scope) {
|
T |
11488 |
this.queryStateCommands[name] = {func : callback, scope : scope || this};
|
d9344f
|
11489 |
},
|
S |
11490 |
|
a9251b
|
11491 |
addQueryValueHandler : function(name, callback, scope) {
|
T |
11492 |
this.queryValueCommands[name] = {func : callback, scope : scope || this};
|
d9344f
|
11493 |
},
|
S |
11494 |
|
|
11495 |
addShortcut : function(pa, desc, cmd_func, sc) {
|
|
11496 |
var t = this, c;
|
|
11497 |
|
|
11498 |
if (!t.settings.custom_shortcuts)
|
|
11499 |
return false;
|
|
11500 |
|
|
11501 |
t.shortcuts = t.shortcuts || {};
|
|
11502 |
|
|
11503 |
if (is(cmd_func, 'string')) {
|
|
11504 |
c = cmd_func;
|
|
11505 |
|
|
11506 |
cmd_func = function() {
|
|
11507 |
t.execCommand(c, false, null);
|
|
11508 |
};
|
|
11509 |
}
|
|
11510 |
|
|
11511 |
if (is(cmd_func, 'object')) {
|
|
11512 |
c = cmd_func;
|
|
11513 |
|
|
11514 |
cmd_func = function() {
|
|
11515 |
t.execCommand(c[0], c[1], c[2]);
|
|
11516 |
};
|
|
11517 |
}
|
|
11518 |
|
|
11519 |
each(explode(pa), function(pa) {
|
|
11520 |
var o = {
|
|
11521 |
func : cmd_func,
|
|
11522 |
scope : sc || this,
|
|
11523 |
desc : desc,
|
|
11524 |
alt : false,
|
|
11525 |
ctrl : false,
|
|
11526 |
shift : false
|
|
11527 |
};
|
|
11528 |
|
|
11529 |
each(explode(pa, '+'), function(v) {
|
|
11530 |
switch (v) {
|
|
11531 |
case 'alt':
|
|
11532 |
case 'ctrl':
|
|
11533 |
case 'shift':
|
|
11534 |
o[v] = true;
|
|
11535 |
break;
|
|
11536 |
|
|
11537 |
default:
|
|
11538 |
o.charCode = v.charCodeAt(0);
|
|
11539 |
o.keyCode = v.toUpperCase().charCodeAt(0);
|
|
11540 |
}
|
|
11541 |
});
|
|
11542 |
|
|
11543 |
t.shortcuts[(o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode] = o;
|
|
11544 |
});
|
|
11545 |
|
|
11546 |
return true;
|
|
11547 |
},
|
|
11548 |
|
|
11549 |
execCommand : function(cmd, ui, val, a) {
|
18240a
|
11550 |
var t = this, s = 0, o, st;
|
d9344f
|
11551 |
|
S |
11552 |
if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(cmd) && (!a || !a.skip_focus))
|
|
11553 |
t.focus();
|
|
11554 |
|
|
11555 |
o = {};
|
|
11556 |
t.onBeforeExecCommand.dispatch(t, cmd, ui, val, o);
|
|
11557 |
if (o.terminate)
|
|
11558 |
return false;
|
|
11559 |
|
18240a
|
11560 |
// Command callback
|
d9344f
|
11561 |
if (t.execCallback('execcommand_callback', t.id, t.selection.getNode(), cmd, ui, val)) {
|
S |
11562 |
t.onExecCommand.dispatch(t, cmd, ui, val, a);
|
|
11563 |
return true;
|
|
11564 |
}
|
|
11565 |
|
|
11566 |
// Registred commands
|
|
11567 |
if (o = t.execCommands[cmd]) {
|
18240a
|
11568 |
st = o.func.call(o.scope, ui, val);
|
A |
11569 |
|
|
11570 |
// Fall through on true
|
|
11571 |
if (st !== true) {
|
|
11572 |
t.onExecCommand.dispatch(t, cmd, ui, val, a);
|
|
11573 |
return st;
|
|
11574 |
}
|
d9344f
|
11575 |
}
|
S |
11576 |
|
|
11577 |
// Plugin commands
|
|
11578 |
each(t.plugins, function(p) {
|
|
11579 |
if (p.execCommand && p.execCommand(cmd, ui, val)) {
|
|
11580 |
t.onExecCommand.dispatch(t, cmd, ui, val, a);
|
|
11581 |
s = 1;
|
|
11582 |
return false;
|
|
11583 |
}
|
|
11584 |
});
|
|
11585 |
|
|
11586 |
if (s)
|
|
11587 |
return true;
|
|
11588 |
|
|
11589 |
// Theme commands
|
29da64
|
11590 |
if (t.theme && t.theme.execCommand && t.theme.execCommand(cmd, ui, val)) {
|
d9344f
|
11591 |
t.onExecCommand.dispatch(t, cmd, ui, val, a);
|
S |
11592 |
return true;
|
|
11593 |
}
|
|
11594 |
|
|
11595 |
// Editor commands
|
|
11596 |
if (t.editorCommands.execCommand(cmd, ui, val)) {
|
|
11597 |
t.onExecCommand.dispatch(t, cmd, ui, val, a);
|
|
11598 |
return true;
|
|
11599 |
}
|
|
11600 |
|
|
11601 |
// Browser commands
|
|
11602 |
t.getDoc().execCommand(cmd, ui, val);
|
|
11603 |
t.onExecCommand.dispatch(t, cmd, ui, val, a);
|
|
11604 |
},
|
|
11605 |
|
69d05c
|
11606 |
queryCommandState : function(cmd) {
|
18240a
|
11607 |
var t = this, o, s;
|
d9344f
|
11608 |
|
S |
11609 |
// Is hidden then return undefined
|
|
11610 |
if (t._isHidden())
|
|
11611 |
return;
|
|
11612 |
|
|
11613 |
// Registred commands
|
69d05c
|
11614 |
if (o = t.queryStateCommands[cmd]) {
|
18240a
|
11615 |
s = o.func.call(o.scope);
|
A |
11616 |
|
|
11617 |
// Fall though on true
|
|
11618 |
if (s !== true)
|
|
11619 |
return s;
|
|
11620 |
}
|
d9344f
|
11621 |
|
S |
11622 |
// Registred commands
|
69d05c
|
11623 |
o = t.editorCommands.queryCommandState(cmd);
|
d9344f
|
11624 |
if (o !== -1)
|
S |
11625 |
return o;
|
|
11626 |
|
|
11627 |
// Browser commands
|
|
11628 |
try {
|
69d05c
|
11629 |
return this.getDoc().queryCommandState(cmd);
|
d9344f
|
11630 |
} catch (ex) {
|
S |
11631 |
// Fails sometimes see bug: 1896577
|
|
11632 |
}
|
|
11633 |
},
|
|
11634 |
|
|
11635 |
queryCommandValue : function(c) {
|
18240a
|
11636 |
var t = this, o, s;
|
d9344f
|
11637 |
|
S |
11638 |
// Is hidden then return undefined
|
|
11639 |
if (t._isHidden())
|
|
11640 |
return;
|
|
11641 |
|
|
11642 |
// Registred commands
|
18240a
|
11643 |
if (o = t.queryValueCommands[c]) {
|
A |
11644 |
s = o.func.call(o.scope);
|
|
11645 |
|
|
11646 |
// Fall though on true
|
|
11647 |
if (s !== true)
|
|
11648 |
return s;
|
|
11649 |
}
|
d9344f
|
11650 |
|
S |
11651 |
// Registred commands
|
|
11652 |
o = t.editorCommands.queryCommandValue(c);
|
|
11653 |
if (is(o))
|
|
11654 |
return o;
|
|
11655 |
|
|
11656 |
// Browser commands
|
|
11657 |
try {
|
|
11658 |
return this.getDoc().queryCommandValue(c);
|
|
11659 |
} catch (ex) {
|
|
11660 |
// Fails sometimes see bug: 1896577
|
|
11661 |
}
|
|
11662 |
},
|
|
11663 |
|
|
11664 |
show : function() {
|
|
11665 |
var t = this;
|
|
11666 |
|
|
11667 |
DOM.show(t.getContainer());
|
|
11668 |
DOM.hide(t.id);
|
|
11669 |
t.load();
|
|
11670 |
},
|
|
11671 |
|
|
11672 |
hide : function() {
|
|
11673 |
var t = this, d = t.getDoc();
|
|
11674 |
|
|
11675 |
// Fixed bug where IE has a blinking cursor left from the editor
|
|
11676 |
if (isIE && d)
|
|
11677 |
d.execCommand('SelectAll');
|
|
11678 |
|
|
11679 |
// We must save before we hide so Safari doesn't crash
|
|
11680 |
t.save();
|
|
11681 |
DOM.hide(t.getContainer());
|
|
11682 |
DOM.setStyle(t.id, 'display', t.orgDisplay);
|
|
11683 |
},
|
|
11684 |
|
|
11685 |
isHidden : function() {
|
|
11686 |
return !DOM.isHidden(this.id);
|
|
11687 |
},
|
|
11688 |
|
|
11689 |
setProgressState : function(b, ti, o) {
|
|
11690 |
this.onSetProgressState.dispatch(this, b, ti, o);
|
|
11691 |
|
|
11692 |
return b;
|
|
11693 |
},
|
|
11694 |
|
|
11695 |
load : function(o) {
|
|
11696 |
var t = this, e = t.getElement(), h;
|
|
11697 |
|
29da64
|
11698 |
if (e) {
|
A |
11699 |
o = o || {};
|
|
11700 |
o.load = true;
|
d9344f
|
11701 |
|
29da64
|
11702 |
// Double encode existing entities in the value
|
A |
11703 |
h = t.setContent(is(e.value) ? e.value : e.innerHTML, o);
|
|
11704 |
o.element = e;
|
d9344f
|
11705 |
|
29da64
|
11706 |
if (!o.no_events)
|
A |
11707 |
t.onLoadContent.dispatch(t, o);
|
d9344f
|
11708 |
|
29da64
|
11709 |
o.element = e = null;
|
d9344f
|
11710 |
|
29da64
|
11711 |
return h;
|
A |
11712 |
}
|
d9344f
|
11713 |
},
|
S |
11714 |
|
|
11715 |
save : function(o) {
|
|
11716 |
var t = this, e = t.getElement(), h, f;
|
|
11717 |
|
29da64
|
11718 |
if (!e || !t.initialized)
|
d9344f
|
11719 |
return;
|
S |
11720 |
|
|
11721 |
o = o || {};
|
|
11722 |
o.save = true;
|
|
11723 |
|
18240a
|
11724 |
// Add undo level will trigger onchange event
|
A |
11725 |
if (!o.no_events) {
|
a9251b
|
11726 |
t.undoManager.typing = false;
|
18240a
|
11727 |
t.undoManager.add();
|
A |
11728 |
}
|
|
11729 |
|
d9344f
|
11730 |
o.element = e;
|
S |
11731 |
h = o.content = t.getContent(o);
|
|
11732 |
|
|
11733 |
if (!o.no_events)
|
|
11734 |
t.onSaveContent.dispatch(t, o);
|
|
11735 |
|
|
11736 |
h = o.content;
|
|
11737 |
|
|
11738 |
if (!/TEXTAREA|INPUT/i.test(e.nodeName)) {
|
|
11739 |
e.innerHTML = h;
|
|
11740 |
|
|
11741 |
// Update hidden form element
|
|
11742 |
if (f = DOM.getParent(t.id, 'form')) {
|
|
11743 |
each(f.elements, function(e) {
|
|
11744 |
if (e.name == t.id) {
|
|
11745 |
e.value = h;
|
|
11746 |
return false;
|
|
11747 |
}
|
|
11748 |
});
|
|
11749 |
}
|
|
11750 |
} else
|
|
11751 |
e.value = h;
|
|
11752 |
|
|
11753 |
o.element = e = null;
|
|
11754 |
|
|
11755 |
return h;
|
|
11756 |
},
|
|
11757 |
|
a9251b
|
11758 |
setContent : function(content, args) {
|
T |
11759 |
var self = this, rootNode, body = self.getBody();
|
d9344f
|
11760 |
|
a9251b
|
11761 |
// Setup args object
|
T |
11762 |
args = args || {};
|
|
11763 |
args.format = args.format || 'html';
|
|
11764 |
args.set = true;
|
|
11765 |
args.content = content;
|
d9344f
|
11766 |
|
a9251b
|
11767 |
// Do preprocessing
|
T |
11768 |
if (!args.no_events)
|
|
11769 |
self.onBeforeSetContent.dispatch(self, args);
|
|
11770 |
|
|
11771 |
content = args.content;
|
d9344f
|
11772 |
|
S |
11773 |
// Padd empty content in Gecko and Safari. Commands will otherwise fail on the content
|
|
11774 |
// It will also be impossible to place the caret in the editor unless there is a BR element present
|
a9251b
|
11775 |
if (!tinymce.isIE && (content.length === 0 || /^\s+$/.test(content))) {
|
T |
11776 |
body.innerHTML = '<br data-mce-bogus="1" />';
|
|
11777 |
return;
|
d9344f
|
11778 |
}
|
S |
11779 |
|
a9251b
|
11780 |
// Parse and serialize the html
|
T |
11781 |
if (args.format !== 'raw') {
|
|
11782 |
content = new tinymce.html.Serializer({}, self.schema).serialize(
|
|
11783 |
self.parser.parse(content)
|
|
11784 |
);
|
d9344f
|
11785 |
}
|
S |
11786 |
|
a9251b
|
11787 |
// Set the new cleaned contents to the editor
|
T |
11788 |
args.content = tinymce.trim(content);
|
|
11789 |
self.dom.setHTML(body, args.content);
|
d9344f
|
11790 |
|
a9251b
|
11791 |
// Do post processing
|
T |
11792 |
if (!args.no_events)
|
|
11793 |
self.onSetContent.dispatch(self, args);
|
|
11794 |
|
|
11795 |
return args.content;
|
d9344f
|
11796 |
},
|
S |
11797 |
|
a9251b
|
11798 |
getContent : function(args) {
|
T |
11799 |
var self = this, content;
|
d9344f
|
11800 |
|
a9251b
|
11801 |
// Setup args object
|
T |
11802 |
args = args || {};
|
|
11803 |
args.format = args.format || 'html';
|
|
11804 |
args.get = true;
|
d9344f
|
11805 |
|
a9251b
|
11806 |
// Do preprocessing
|
T |
11807 |
if (!args.no_events)
|
|
11808 |
self.onBeforeGetContent.dispatch(self, args);
|
d9344f
|
11809 |
|
a9251b
|
11810 |
// Get raw contents or by default the cleaned contents
|
T |
11811 |
if (args.format == 'raw')
|
|
11812 |
content = self.getBody().innerHTML;
|
|
11813 |
else
|
|
11814 |
content = self.serializer.serialize(self.getBody(), args);
|
d9344f
|
11815 |
|
a9251b
|
11816 |
args.content = tinymce.trim(content);
|
18240a
|
11817 |
|
a9251b
|
11818 |
// Do post processing
|
T |
11819 |
if (!args.no_events)
|
|
11820 |
self.onGetContent.dispatch(self, args);
|
d9344f
|
11821 |
|
a9251b
|
11822 |
return args.content;
|
d9344f
|
11823 |
},
|
S |
11824 |
|
|
11825 |
isDirty : function() {
|
a9251b
|
11826 |
var self = this;
|
d9344f
|
11827 |
|
a9251b
|
11828 |
return tinymce.trim(self.startContent) != tinymce.trim(self.getContent({format : 'raw', no_events : 1})) && !self.isNotDirty;
|
d9344f
|
11829 |
},
|
S |
11830 |
|
|
11831 |
getContainer : function() {
|
|
11832 |
var t = this;
|
|
11833 |
|
|
11834 |
if (!t.container)
|
|
11835 |
t.container = DOM.get(t.editorContainer || t.id + '_parent');
|
|
11836 |
|
|
11837 |
return t.container;
|
|
11838 |
},
|
|
11839 |
|
|
11840 |
getContentAreaContainer : function() {
|
|
11841 |
return this.contentAreaContainer;
|
|
11842 |
},
|
|
11843 |
|
|
11844 |
getElement : function() {
|
|
11845 |
return DOM.get(this.settings.content_element || this.id);
|
|
11846 |
},
|
|
11847 |
|
|
11848 |
getWin : function() {
|
|
11849 |
var t = this, e;
|
|
11850 |
|
|
11851 |
if (!t.contentWindow) {
|
|
11852 |
e = DOM.get(t.id + "_ifr");
|
|
11853 |
|
|
11854 |
if (e)
|
|
11855 |
t.contentWindow = e.contentWindow;
|
|
11856 |
}
|
|
11857 |
|
|
11858 |
return t.contentWindow;
|
|
11859 |
},
|
|
11860 |
|
|
11861 |
getDoc : function() {
|
|
11862 |
var t = this, w;
|
|
11863 |
|
|
11864 |
if (!t.contentDocument) {
|
|
11865 |
w = t.getWin();
|
|
11866 |
|
|
11867 |
if (w)
|
|
11868 |
t.contentDocument = w.document;
|
|
11869 |
}
|
|
11870 |
|
|
11871 |
return t.contentDocument;
|
|
11872 |
},
|
|
11873 |
|
|
11874 |
getBody : function() {
|
|
11875 |
return this.bodyElement || this.getDoc().body;
|
|
11876 |
},
|
|
11877 |
|
|
11878 |
convertURL : function(u, n, e) {
|
|
11879 |
var t = this, s = t.settings;
|
|
11880 |
|
|
11881 |
// Use callback instead
|
|
11882 |
if (s.urlconverter_callback)
|
|
11883 |
return t.execCallback('urlconverter_callback', u, e, true, n);
|
|
11884 |
|
|
11885 |
// Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs
|
|
11886 |
if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0)
|
|
11887 |
return u;
|
|
11888 |
|
|
11889 |
// Convert to relative
|
|
11890 |
if (s.relative_urls)
|
|
11891 |
return t.documentBaseURI.toRelative(u);
|
|
11892 |
|
|
11893 |
// Convert to absolute
|
|
11894 |
u = t.documentBaseURI.toAbsolute(u, s.remove_script_host);
|
|
11895 |
|
|
11896 |
return u;
|
|
11897 |
},
|
|
11898 |
|
|
11899 |
addVisual : function(e) {
|
|
11900 |
var t = this, s = t.settings;
|
|
11901 |
|
|
11902 |
e = e || t.getBody();
|
|
11903 |
|
|
11904 |
if (!is(t.hasVisual))
|
|
11905 |
t.hasVisual = s.visual;
|
|
11906 |
|
|
11907 |
each(t.dom.select('table,a', e), function(e) {
|
|
11908 |
var v;
|
|
11909 |
|
|
11910 |
switch (e.nodeName) {
|
|
11911 |
case 'TABLE':
|
|
11912 |
v = t.dom.getAttrib(e, 'border');
|
|
11913 |
|
|
11914 |
if (!v || v == '0') {
|
|
11915 |
if (t.hasVisual)
|
|
11916 |
t.dom.addClass(e, s.visual_table_class);
|
|
11917 |
else
|
|
11918 |
t.dom.removeClass(e, s.visual_table_class);
|
|
11919 |
}
|
|
11920 |
|
|
11921 |
return;
|
|
11922 |
|
|
11923 |
case 'A':
|
|
11924 |
v = t.dom.getAttrib(e, 'name');
|
|
11925 |
|
|
11926 |
if (v) {
|
|
11927 |
if (t.hasVisual)
|
|
11928 |
t.dom.addClass(e, 'mceItemAnchor');
|
|
11929 |
else
|
|
11930 |
t.dom.removeClass(e, 'mceItemAnchor');
|
|
11931 |
}
|
|
11932 |
|
|
11933 |
return;
|
|
11934 |
}
|
|
11935 |
});
|
|
11936 |
|
|
11937 |
t.onVisualAid.dispatch(t, e, t.hasVisual);
|
|
11938 |
},
|
|
11939 |
|
|
11940 |
remove : function() {
|
|
11941 |
var t = this, e = t.getContainer();
|
|
11942 |
|
|
11943 |
t.removed = 1; // Cancels post remove event execution
|
|
11944 |
t.hide();
|
|
11945 |
|
|
11946 |
t.execCallback('remove_instance_callback', t);
|
|
11947 |
t.onRemove.dispatch(t);
|
|
11948 |
|
|
11949 |
// Clear all execCommand listeners this is required to avoid errors if the editor was removed inside another command
|
|
11950 |
t.onExecCommand.listeners = [];
|
|
11951 |
|
69d05c
|
11952 |
tinymce.remove(t);
|
d9344f
|
11953 |
DOM.remove(e);
|
S |
11954 |
},
|
|
11955 |
|
|
11956 |
destroy : function(s) {
|
|
11957 |
var t = this;
|
|
11958 |
|
|
11959 |
// One time is enough
|
|
11960 |
if (t.destroyed)
|
|
11961 |
return;
|
|
11962 |
|
|
11963 |
if (!s) {
|
|
11964 |
tinymce.removeUnload(t.destroy);
|
|
11965 |
tinyMCE.onBeforeUnload.remove(t._beforeUnload);
|
|
11966 |
|
|
11967 |
// Manual destroy
|
29da64
|
11968 |
if (t.theme && t.theme.destroy)
|
d9344f
|
11969 |
t.theme.destroy();
|
S |
11970 |
|
|
11971 |
// Destroy controls, selection and dom
|
|
11972 |
t.controlManager.destroy();
|
|
11973 |
t.selection.destroy();
|
|
11974 |
t.dom.destroy();
|
|
11975 |
|
|
11976 |
// Remove all events
|
18240a
|
11977 |
|
A |
11978 |
// Don't clear the window or document if content editable
|
|
11979 |
// is enabled since other instances might still be present
|
|
11980 |
if (!t.settings.content_editable) {
|
|
11981 |
Event.clear(t.getWin());
|
|
11982 |
Event.clear(t.getDoc());
|
|
11983 |
}
|
|
11984 |
|
d9344f
|
11985 |
Event.clear(t.getBody());
|
S |
11986 |
Event.clear(t.formElement);
|
|
11987 |
}
|
|
11988 |
|
|
11989 |
if (t.formElement) {
|
|
11990 |
t.formElement.submit = t.formElement._mceOldSubmit;
|
|
11991 |
t.formElement._mceOldSubmit = null;
|
|
11992 |
}
|
|
11993 |
|
|
11994 |
t.contentAreaContainer = t.formElement = t.container = t.settings.content_element = t.bodyElement = t.contentDocument = t.contentWindow = null;
|
|
11995 |
|
|
11996 |
if (t.selection)
|
|
11997 |
t.selection = t.selection.win = t.selection.dom = t.selection.dom.doc = null;
|
|
11998 |
|
|
11999 |
t.destroyed = 1;
|
|
12000 |
},
|
|
12001 |
|
|
12002 |
// Internal functions
|
|
12003 |
|
|
12004 |
_addEvents : function() {
|
|
12005 |
// 'focus', 'blur', 'dblclick', 'beforedeactivate', submit, reset
|
a9251b
|
12006 |
var t = this, i, s = t.settings, dom = t.dom, lo = {
|
d9344f
|
12007 |
mouseup : 'onMouseUp',
|
S |
12008 |
mousedown : 'onMouseDown',
|
|
12009 |
click : 'onClick',
|
|
12010 |
keyup : 'onKeyUp',
|
|
12011 |
keydown : 'onKeyDown',
|
|
12012 |
keypress : 'onKeyPress',
|
|
12013 |
submit : 'onSubmit',
|
|
12014 |
reset : 'onReset',
|
|
12015 |
contextmenu : 'onContextMenu',
|
|
12016 |
dblclick : 'onDblClick',
|
|
12017 |
paste : 'onPaste' // Doesn't work in all browsers yet
|
|
12018 |
};
|
|
12019 |
|
|
12020 |
function eventHandler(e, o) {
|
|
12021 |
var ty = e.type;
|
|
12022 |
|
|
12023 |
// Don't fire events when it's removed
|
|
12024 |
if (t.removed)
|
|
12025 |
return;
|
|
12026 |
|
|
12027 |
// Generic event handler
|
|
12028 |
if (t.onEvent.dispatch(t, e, o) !== false) {
|
|
12029 |
// Specific event handler
|
|
12030 |
t[lo[e.fakeType || e.type]].dispatch(t, e, o);
|
|
12031 |
}
|
|
12032 |
};
|
|
12033 |
|
|
12034 |
// Add DOM events
|
|
12035 |
each(lo, function(v, k) {
|
|
12036 |
switch (k) {
|
|
12037 |
case 'contextmenu':
|
a9251b
|
12038 |
dom.bind(t.getDoc(), k, eventHandler);
|
d9344f
|
12039 |
break;
|
S |
12040 |
|
|
12041 |
case 'paste':
|
a9251b
|
12042 |
dom.bind(t.getBody(), k, function(e) {
|
29da64
|
12043 |
eventHandler(e);
|
d9344f
|
12044 |
});
|
S |
12045 |
break;
|
|
12046 |
|
|
12047 |
case 'submit':
|
|
12048 |
case 'reset':
|
a9251b
|
12049 |
dom.bind(t.getElement().form || DOM.getParent(t.id, 'form'), k, eventHandler);
|
d9344f
|
12050 |
break;
|
S |
12051 |
|
|
12052 |
default:
|
a9251b
|
12053 |
dom.bind(s.content_editable ? t.getBody() : t.getDoc(), k, eventHandler);
|
d9344f
|
12054 |
}
|
S |
12055 |
});
|
|
12056 |
|
a9251b
|
12057 |
dom.bind(s.content_editable ? t.getBody() : (isGecko ? t.getDoc() : t.getWin()), 'focus', function(e) {
|
d9344f
|
12058 |
t.focus(true);
|
S |
12059 |
});
|
|
12060 |
|
29da64
|
12061 |
|
d9344f
|
12062 |
// Fixes bug where a specified document_base_uri could result in broken images
|
S |
12063 |
// This will also fix drag drop of images in Gecko
|
|
12064 |
if (tinymce.isGecko) {
|
a9251b
|
12065 |
dom.bind(t.getDoc(), 'DOMNodeInserted', function(e) {
|
d9344f
|
12066 |
var v;
|
S |
12067 |
|
|
12068 |
e = e.target;
|
|
12069 |
|
a9251b
|
12070 |
if (e.nodeType === 1 && e.nodeName === 'IMG' && (v = e.getAttribute('data-mce-src')))
|
d9344f
|
12071 |
e.src = t.documentBaseURI.toAbsolute(v);
|
S |
12072 |
});
|
|
12073 |
}
|
|
12074 |
|
|
12075 |
// Set various midas options in Gecko
|
|
12076 |
if (isGecko) {
|
|
12077 |
function setOpts() {
|
|
12078 |
var t = this, d = t.getDoc(), s = t.settings;
|
|
12079 |
|
29da64
|
12080 |
if (isGecko && !s.readonly) {
|
d9344f
|
12081 |
if (t._isHidden()) {
|
S |
12082 |
try {
|
|
12083 |
if (!s.content_editable)
|
|
12084 |
d.designMode = 'On';
|
|
12085 |
} catch (ex) {
|
|
12086 |
// Fails if it's hidden
|
|
12087 |
}
|
|
12088 |
}
|
|
12089 |
|
|
12090 |
try {
|
|
12091 |
// Try new Gecko method
|
|
12092 |
d.execCommand("styleWithCSS", 0, false);
|
|
12093 |
} catch (ex) {
|
|
12094 |
// Use old method
|
|
12095 |
if (!t._isHidden())
|
18240a
|
12096 |
try {d.execCommand("useCSS", 0, true);} catch (ex) {}
|
d9344f
|
12097 |
}
|
S |
12098 |
|
|
12099 |
if (!s.table_inline_editing)
|
|
12100 |
try {d.execCommand('enableInlineTableEditing', false, false);} catch (ex) {}
|
|
12101 |
|
|
12102 |
if (!s.object_resizing)
|
|
12103 |
try {d.execCommand('enableObjectResizing', false, false);} catch (ex) {}
|
|
12104 |
}
|
|
12105 |
};
|
|
12106 |
|
|
12107 |
t.onBeforeExecCommand.add(setOpts);
|
|
12108 |
t.onMouseDown.add(setOpts);
|
|
12109 |
}
|
|
12110 |
|
69d05c
|
12111 |
// Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250
|
A |
12112 |
// WebKit can't even do simple things like selecting an image
|
|
12113 |
// This also fixes so it's possible to select mceItemAnchors
|
|
12114 |
if (tinymce.isWebKit) {
|
|
12115 |
t.onClick.add(function(ed, e) {
|
|
12116 |
e = e.target;
|
|
12117 |
|
|
12118 |
// Needs tobe the setBaseAndExtend or it will fail to select floated images
|
a9251b
|
12119 |
if (e.nodeName == 'IMG' || (e.nodeName == 'A' && dom.hasClass(e, 'mceItemAnchor'))) {
|
69d05c
|
12120 |
t.selection.getSel().setBaseAndExtent(e, 0, e, 1);
|
a9251b
|
12121 |
t.nodeChanged();
|
T |
12122 |
}
|
69d05c
|
12123 |
});
|
A |
12124 |
}
|
|
12125 |
|
d9344f
|
12126 |
// Add node change handlers
|
S |
12127 |
t.onMouseUp.add(t.nodeChanged);
|
2011be
|
12128 |
//t.onClick.add(t.nodeChanged);
|
d9344f
|
12129 |
t.onKeyUp.add(function(ed, e) {
|
29da64
|
12130 |
var c = e.keyCode;
|
A |
12131 |
|
|
12132 |
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)
|
d9344f
|
12133 |
t.nodeChanged();
|
S |
12134 |
});
|
|
12135 |
|
|
12136 |
// Add reset handler
|
|
12137 |
t.onReset.add(function() {
|
|
12138 |
t.setContent(t.startContent, {format : 'raw'});
|
|
12139 |
});
|
|
12140 |
|
|
12141 |
// Add shortcuts
|
|
12142 |
if (s.custom_shortcuts) {
|
|
12143 |
if (s.custom_undo_redo_keyboard_shortcuts) {
|
|
12144 |
t.addShortcut('ctrl+z', t.getLang('undo_desc'), 'Undo');
|
|
12145 |
t.addShortcut('ctrl+y', t.getLang('redo_desc'), 'Redo');
|
|
12146 |
}
|
|
12147 |
|
|
12148 |
// Add default shortcuts for gecko
|
2011be
|
12149 |
t.addShortcut('ctrl+b', t.getLang('bold_desc'), 'Bold');
|
A |
12150 |
t.addShortcut('ctrl+i', t.getLang('italic_desc'), 'Italic');
|
|
12151 |
t.addShortcut('ctrl+u', t.getLang('underline_desc'), 'Underline');
|
d9344f
|
12152 |
|
S |
12153 |
// BlockFormat shortcuts keys
|
|
12154 |
for (i=1; i<=6; i++)
|
69d05c
|
12155 |
t.addShortcut('ctrl+' + i, '', ['FormatBlock', false, 'h' + i]);
|
d9344f
|
12156 |
|
S |
12157 |
t.addShortcut('ctrl+7', '', ['FormatBlock', false, '<p>']);
|
|
12158 |
t.addShortcut('ctrl+8', '', ['FormatBlock', false, '<div>']);
|
|
12159 |
t.addShortcut('ctrl+9', '', ['FormatBlock', false, '<address>']);
|
|
12160 |
|
|
12161 |
function find(e) {
|
|
12162 |
var v = null;
|
|
12163 |
|
|
12164 |
if (!e.altKey && !e.ctrlKey && !e.metaKey)
|
|
12165 |
return v;
|
|
12166 |
|
|
12167 |
each(t.shortcuts, function(o) {
|
29da64
|
12168 |
if (tinymce.isMac && o.ctrl != e.metaKey)
|
A |
12169 |
return;
|
|
12170 |
else if (!tinymce.isMac && o.ctrl != e.ctrlKey)
|
d9344f
|
12171 |
return;
|
S |
12172 |
|
|
12173 |
if (o.alt != e.altKey)
|
|
12174 |
return;
|
|
12175 |
|
|
12176 |
if (o.shift != e.shiftKey)
|
|
12177 |
return;
|
|
12178 |
|
|
12179 |
if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) {
|
|
12180 |
v = o;
|
|
12181 |
return false;
|
|
12182 |
}
|
|
12183 |
});
|
|
12184 |
|
|
12185 |
return v;
|
|
12186 |
};
|
|
12187 |
|
|
12188 |
t.onKeyUp.add(function(ed, e) {
|
|
12189 |
var o = find(e);
|
|
12190 |
|
|
12191 |
if (o)
|
|
12192 |
return Event.cancel(e);
|
|
12193 |
});
|
|
12194 |
|
|
12195 |
t.onKeyPress.add(function(ed, e) {
|
|
12196 |
var o = find(e);
|
|
12197 |
|
|
12198 |
if (o)
|
|
12199 |
return Event.cancel(e);
|
|
12200 |
});
|
|
12201 |
|
|
12202 |
t.onKeyDown.add(function(ed, e) {
|
|
12203 |
var o = find(e);
|
|
12204 |
|
|
12205 |
if (o) {
|
|
12206 |
o.func.call(o.scope);
|
|
12207 |
return Event.cancel(e);
|
|
12208 |
}
|
|
12209 |
});
|
|
12210 |
}
|
|
12211 |
|
|
12212 |
if (tinymce.isIE) {
|
|
12213 |
// Fix so resize will only update the width and height attributes not the styles of an image
|
|
12214 |
// It will also block mceItemNoResize items
|
a9251b
|
12215 |
dom.bind(t.getDoc(), 'controlselect', function(e) {
|
d9344f
|
12216 |
var re = t.resizeInfo, cb;
|
S |
12217 |
|
|
12218 |
e = e.target;
|
|
12219 |
|
|
12220 |
// Don't do this action for non image elements
|
|
12221 |
if (e.nodeName !== 'IMG')
|
|
12222 |
return;
|
|
12223 |
|
|
12224 |
if (re)
|
a9251b
|
12225 |
dom.unbind(re.node, re.ev, re.cb);
|
d9344f
|
12226 |
|
a9251b
|
12227 |
if (!dom.hasClass(e, 'mceItemNoResize')) {
|
d9344f
|
12228 |
ev = 'resizeend';
|
a9251b
|
12229 |
cb = dom.bind(e, ev, function(e) {
|
d9344f
|
12230 |
var v;
|
S |
12231 |
|
|
12232 |
e = e.target;
|
|
12233 |
|
a9251b
|
12234 |
if (v = dom.getStyle(e, 'width')) {
|
T |
12235 |
dom.setAttrib(e, 'width', v.replace(/[^0-9%]+/g, ''));
|
|
12236 |
dom.setStyle(e, 'width', '');
|
d9344f
|
12237 |
}
|
S |
12238 |
|
a9251b
|
12239 |
if (v = dom.getStyle(e, 'height')) {
|
T |
12240 |
dom.setAttrib(e, 'height', v.replace(/[^0-9%]+/g, ''));
|
|
12241 |
dom.setStyle(e, 'height', '');
|
d9344f
|
12242 |
}
|
S |
12243 |
});
|
|
12244 |
} else {
|
|
12245 |
ev = 'resizestart';
|
a9251b
|
12246 |
cb = dom.bind(e, 'resizestart', Event.cancel, Event);
|
d9344f
|
12247 |
}
|
S |
12248 |
|
|
12249 |
re = t.resizeInfo = {
|
|
12250 |
node : e,
|
|
12251 |
ev : ev,
|
|
12252 |
cb : cb
|
|
12253 |
};
|
|
12254 |
});
|
|
12255 |
|
|
12256 |
t.onKeyDown.add(function(ed, e) {
|
a9251b
|
12257 |
var sel;
|
T |
12258 |
|
d9344f
|
12259 |
switch (e.keyCode) {
|
S |
12260 |
case 8:
|
a9251b
|
12261 |
sel = t.getDoc().selection;
|
T |
12262 |
|
d9344f
|
12263 |
// Fix IE control + backspace browser bug
|
a9251b
|
12264 |
if (sel.createRange && sel.createRange().item) {
|
T |
12265 |
ed.dom.remove(sel.createRange().item(0));
|
d9344f
|
12266 |
return Event.cancel(e);
|
S |
12267 |
}
|
|
12268 |
}
|
|
12269 |
});
|
|
12270 |
}
|
|
12271 |
|
|
12272 |
if (tinymce.isOpera) {
|
|
12273 |
t.onClick.add(function(ed, e) {
|
|
12274 |
Event.prevent(e);
|
|
12275 |
});
|
|
12276 |
}
|
|
12277 |
|
|
12278 |
// Add custom undo/redo handlers
|
|
12279 |
if (s.custom_undo_redo) {
|
|
12280 |
function addUndo() {
|
a9251b
|
12281 |
t.undoManager.typing = false;
|
d9344f
|
12282 |
t.undoManager.add();
|
S |
12283 |
};
|
|
12284 |
|
a9251b
|
12285 |
dom.bind(t.getDoc(), 'focusout', function(e) {
|
69d05c
|
12286 |
if (!t.removed && t.undoManager.typing)
|
A |
12287 |
addUndo();
|
|
12288 |
});
|
d9344f
|
12289 |
|
a9251b
|
12290 |
// Add undo level when contents is drag/dropped within the editor
|
T |
12291 |
t.dom.bind(t.dom.getRoot(), 'dragend', function(e) {
|
|
12292 |
addUndo();
|
|
12293 |
});
|
|
12294 |
|
d9344f
|
12295 |
t.onKeyUp.add(function(ed, e) {
|
a9251b
|
12296 |
var rng, parent, bookmark;
|
T |
12297 |
|
|
12298 |
// Fix for bug #3168, to remove odd ".." nodes from the DOM we need to get/set the HTML of the parent node.
|
|
12299 |
if (isIE && e.keyCode == 8) {
|
|
12300 |
rng = t.selection.getRng();
|
|
12301 |
if (rng.parentElement) {
|
|
12302 |
parent = rng.parentElement();
|
|
12303 |
bookmark = t.selection.getBookmark();
|
|
12304 |
parent.innerHTML = parent.innerHTML;
|
|
12305 |
t.selection.moveToBookmark(bookmark);
|
|
12306 |
}
|
|
12307 |
}
|
|
12308 |
|
69d05c
|
12309 |
if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.ctrlKey)
|
A |
12310 |
addUndo();
|
d9344f
|
12311 |
});
|
S |
12312 |
|
|
12313 |
t.onKeyDown.add(function(ed, e) {
|
a9251b
|
12314 |
var rng, parent, bookmark, keyCode = e.keyCode;
|
2011be
|
12315 |
|
A |
12316 |
// IE has a really odd bug where the DOM might include an node that doesn't have
|
|
12317 |
// a proper structure. If you try to access nodeValue it would throw an illegal value exception.
|
|
12318 |
// This seems to only happen when you delete contents and it seems to be avoidable if you refresh the element
|
|
12319 |
// after you delete contents from it. See: #3008923
|
a9251b
|
12320 |
if (isIE && keyCode == 46) {
|
2011be
|
12321 |
rng = t.selection.getRng();
|
A |
12322 |
|
|
12323 |
if (rng.parentElement) {
|
|
12324 |
parent = rng.parentElement();
|
|
12325 |
|
a9251b
|
12326 |
if (!t.undoManager.typing) {
|
T |
12327 |
t.undoManager.beforeChange();
|
|
12328 |
t.undoManager.typing = true;
|
|
12329 |
t.undoManager.add();
|
|
12330 |
}
|
2011be
|
12331 |
|
A |
12332 |
// Select next word when ctrl key is used in combo with delete
|
|
12333 |
if (e.ctrlKey) {
|
|
12334 |
rng.moveEnd('word', 1);
|
|
12335 |
rng.select();
|
|
12336 |
}
|
|
12337 |
|
|
12338 |
// Delete contents
|
|
12339 |
t.selection.getSel().clear();
|
|
12340 |
|
|
12341 |
// Check if we are within the same parent
|
|
12342 |
if (rng.parentElement() == parent) {
|
a9251b
|
12343 |
bookmark = t.selection.getBookmark();
|
T |
12344 |
|
2011be
|
12345 |
try {
|
A |
12346 |
// Update the HTML and hopefully it will remove the artifacts
|
|
12347 |
parent.innerHTML = parent.innerHTML;
|
|
12348 |
} catch (ex) {
|
|
12349 |
// And since it's IE it can sometimes produce an unknown runtime error
|
|
12350 |
}
|
|
12351 |
|
|
12352 |
// Restore the caret position
|
a9251b
|
12353 |
t.selection.moveToBookmark(bookmark);
|
2011be
|
12354 |
}
|
A |
12355 |
|
|
12356 |
// Block the default delete behavior since it might be broken
|
|
12357 |
e.preventDefault();
|
|
12358 |
return;
|
|
12359 |
}
|
|
12360 |
}
|
|
12361 |
|
a9251b
|
12362 |
// Is caracter positon keys left,right,up,down,home,end,pgdown,pgup,enter
|
T |
12363 |
if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode == 13 || keyCode == 45) {
|
|
12364 |
// Add position before enter key is pressed, used by IE since it still uses the default browser behavior
|
|
12365 |
// Todo: Remove this once we normalize enter behavior on IE
|
|
12366 |
if (tinymce.isIE && keyCode == 13)
|
|
12367 |
t.undoManager.beforeChange();
|
|
12368 |
|
69d05c
|
12369 |
if (t.undoManager.typing)
|
A |
12370 |
addUndo();
|
d9344f
|
12371 |
|
S |
12372 |
return;
|
|
12373 |
}
|
|
12374 |
|
a9251b
|
12375 |
// If key isn't shift,ctrl,alt,capslock,metakey
|
T |
12376 |
if ((keyCode < 16 || keyCode > 20) && keyCode != 224 && keyCode != 91 && !t.undoManager.typing) {
|
|
12377 |
t.undoManager.beforeChange();
|
d9344f
|
12378 |
t.undoManager.add();
|
a9251b
|
12379 |
t.undoManager.typing = true;
|
d9344f
|
12380 |
}
|
S |
12381 |
});
|
|
12382 |
|
69d05c
|
12383 |
t.onMouseDown.add(function() {
|
A |
12384 |
if (t.undoManager.typing)
|
|
12385 |
addUndo();
|
a9251b
|
12386 |
});
|
T |
12387 |
}
|
|
12388 |
|
|
12389 |
// Bug fix for FireFox keeping styles from end of selection instead of start.
|
|
12390 |
if (tinymce.isGecko) {
|
|
12391 |
function getAttributeApplyFunction() {
|
|
12392 |
var template = t.dom.getAttribs(t.selection.getStart().cloneNode(false));
|
|
12393 |
|
|
12394 |
return function() {
|
|
12395 |
var target = t.selection.getStart();
|
|
12396 |
t.dom.removeAllAttribs(target);
|
|
12397 |
each(template, function(attr) {
|
|
12398 |
target.setAttributeNode(attr.cloneNode(true));
|
|
12399 |
});
|
|
12400 |
};
|
|
12401 |
}
|
|
12402 |
|
|
12403 |
function isSelectionAcrossElements() {
|
|
12404 |
var s = t.selection;
|
|
12405 |
|
|
12406 |
return !s.isCollapsed() && s.getStart() != s.getEnd();
|
|
12407 |
}
|
|
12408 |
|
|
12409 |
t.onKeyPress.add(function(ed, e) {
|
|
12410 |
var applyAttributes;
|
|
12411 |
|
|
12412 |
if ((e.keyCode == 8 || e.keyCode == 46) && isSelectionAcrossElements()) {
|
|
12413 |
applyAttributes = getAttributeApplyFunction();
|
|
12414 |
t.getDoc().execCommand('delete', false, null);
|
|
12415 |
applyAttributes();
|
|
12416 |
|
|
12417 |
return Event.cancel(e);
|
|
12418 |
}
|
|
12419 |
});
|
|
12420 |
|
|
12421 |
t.dom.bind(t.getDoc(), 'cut', function(e) {
|
|
12422 |
var applyAttributes;
|
|
12423 |
|
|
12424 |
if (isSelectionAcrossElements()) {
|
|
12425 |
applyAttributes = getAttributeApplyFunction();
|
|
12426 |
t.onKeyUp.addToTop(Event.cancel, Event);
|
|
12427 |
|
|
12428 |
setTimeout(function() {
|
|
12429 |
applyAttributes();
|
|
12430 |
t.onKeyUp.remove(Event.cancel, Event);
|
|
12431 |
}, 0);
|
|
12432 |
}
|
d9344f
|
12433 |
});
|
S |
12434 |
}
|
|
12435 |
},
|
|
12436 |
|
|
12437 |
_isHidden : function() {
|
|
12438 |
var s;
|
|
12439 |
|
|
12440 |
if (!isGecko)
|
|
12441 |
return 0;
|
|
12442 |
|
|
12443 |
// Weird, wheres that cursor selection?
|
|
12444 |
s = this.selection.getSel();
|
|
12445 |
return (!s || !s.rangeCount || s.rangeCount == 0);
|
|
12446 |
}
|
58fb65
|
12447 |
});
|
29da64
|
12448 |
})(tinymce);
|
69d05c
|
12449 |
|
29da64
|
12450 |
(function(tinymce) {
|
69d05c
|
12451 |
// Added for compression purposes
|
A |
12452 |
var each = tinymce.each, undefined, TRUE = true, FALSE = false;
|
d9344f
|
12453 |
|
69d05c
|
12454 |
tinymce.EditorCommands = function(editor) {
|
A |
12455 |
var dom = editor.dom,
|
|
12456 |
selection = editor.selection,
|
|
12457 |
commands = {state: {}, exec : {}, value : {}},
|
|
12458 |
settings = editor.settings,
|
|
12459 |
bookmark;
|
d9344f
|
12460 |
|
69d05c
|
12461 |
function execCommand(command, ui, value) {
|
A |
12462 |
var func;
|
d9344f
|
12463 |
|
69d05c
|
12464 |
command = command.toLowerCase();
|
A |
12465 |
if (func = commands.exec[command]) {
|
|
12466 |
func(command, ui, value);
|
|
12467 |
return TRUE;
|
d9344f
|
12468 |
}
|
S |
12469 |
|
69d05c
|
12470 |
return FALSE;
|
A |
12471 |
};
|
d9344f
|
12472 |
|
69d05c
|
12473 |
function queryCommandState(command) {
|
A |
12474 |
var func;
|
d9344f
|
12475 |
|
69d05c
|
12476 |
command = command.toLowerCase();
|
A |
12477 |
if (func = commands.state[command])
|
|
12478 |
return func(command);
|
d9344f
|
12479 |
|
S |
12480 |
return -1;
|
69d05c
|
12481 |
};
|
d9344f
|
12482 |
|
69d05c
|
12483 |
function queryCommandValue(command) {
|
A |
12484 |
var func;
|
d9344f
|
12485 |
|
69d05c
|
12486 |
command = command.toLowerCase();
|
A |
12487 |
if (func = commands.value[command])
|
|
12488 |
return func(command);
|
d9344f
|
12489 |
|
69d05c
|
12490 |
return FALSE;
|
A |
12491 |
};
|
d9344f
|
12492 |
|
69d05c
|
12493 |
function addCommands(command_list, type) {
|
A |
12494 |
type = type || 'exec';
|
29da64
|
12495 |
|
69d05c
|
12496 |
each(command_list, function(callback, command) {
|
A |
12497 |
each(command.toLowerCase().split(','), function(command) {
|
|
12498 |
commands[type][command] = callback;
|
|
12499 |
});
|
|
12500 |
});
|
|
12501 |
};
|
d9344f
|
12502 |
|
69d05c
|
12503 |
// Expose public methods
|
A |
12504 |
tinymce.extend(this, {
|
|
12505 |
execCommand : execCommand,
|
|
12506 |
queryCommandState : queryCommandState,
|
|
12507 |
queryCommandValue : queryCommandValue,
|
|
12508 |
addCommands : addCommands
|
|
12509 |
});
|
d9344f
|
12510 |
|
69d05c
|
12511 |
// Private methods
|
d9344f
|
12512 |
|
69d05c
|
12513 |
function execNativeCommand(command, ui, value) {
|
A |
12514 |
if (ui === undefined)
|
|
12515 |
ui = FALSE;
|
d9344f
|
12516 |
|
69d05c
|
12517 |
if (value === undefined)
|
A |
12518 |
value = null;
|
29da64
|
12519 |
|
69d05c
|
12520 |
return editor.getDoc().execCommand(command, ui, value);
|
A |
12521 |
};
|
d9344f
|
12522 |
|
69d05c
|
12523 |
function isFormatMatch(name) {
|
A |
12524 |
return editor.formatter.match(name);
|
|
12525 |
};
|
d9344f
|
12526 |
|
69d05c
|
12527 |
function toggleFormat(name, value) {
|
A |
12528 |
editor.formatter.toggle(name, value ? {value : value} : undefined);
|
|
12529 |
};
|
d9344f
|
12530 |
|
69d05c
|
12531 |
function storeSelection(type) {
|
A |
12532 |
bookmark = selection.getBookmark(type);
|
|
12533 |
};
|
d9344f
|
12534 |
|
69d05c
|
12535 |
function restoreSelection() {
|
A |
12536 |
selection.moveToBookmark(bookmark);
|
|
12537 |
};
|
d9344f
|
12538 |
|
69d05c
|
12539 |
// Add execCommand overrides
|
A |
12540 |
addCommands({
|
|
12541 |
// Ignore these, added for compatibility
|
|
12542 |
'mceResetDesignMode,mceBeginUndoLevel' : function() {},
|
d9344f
|
12543 |
|
69d05c
|
12544 |
// Add undo manager logic
|
A |
12545 |
'mceEndUndoLevel,mceAddUndoLevel' : function() {
|
|
12546 |
editor.undoManager.add();
|
|
12547 |
},
|
d9344f
|
12548 |
|
69d05c
|
12549 |
'Cut,Copy,Paste' : function(command) {
|
A |
12550 |
var doc = editor.getDoc(), failed;
|
d9344f
|
12551 |
|
69d05c
|
12552 |
// Try executing the native command
|
A |
12553 |
try {
|
|
12554 |
execNativeCommand(command);
|
|
12555 |
} catch (ex) {
|
|
12556 |
// Command failed
|
|
12557 |
failed = TRUE;
|
d9344f
|
12558 |
}
|
S |
12559 |
|
69d05c
|
12560 |
// Present alert message about clipboard access not being available
|
2011be
|
12561 |
if (failed || !doc.queryCommandSupported(command)) {
|
69d05c
|
12562 |
if (tinymce.isGecko) {
|
A |
12563 |
editor.windowManager.confirm(editor.getLang('clipboard_msg'), function(state) {
|
|
12564 |
if (state)
|
|
12565 |
open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', '_blank');
|
|
12566 |
});
|
|
12567 |
} else
|
|
12568 |
editor.windowManager.alert(editor.getLang('clipboard_no_support'));
|
|
12569 |
}
|
|
12570 |
},
|
d9344f
|
12571 |
|
69d05c
|
12572 |
// Override unlink command
|
A |
12573 |
unlink : function(command) {
|
|
12574 |
if (selection.isCollapsed())
|
|
12575 |
selection.select(selection.getNode());
|
d9344f
|
12576 |
|
69d05c
|
12577 |
execNativeCommand(command);
|
A |
12578 |
selection.collapse(FALSE);
|
|
12579 |
},
|
d9344f
|
12580 |
|
69d05c
|
12581 |
// Override justify commands to use the text formatter engine
|
A |
12582 |
'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull' : function(command) {
|
|
12583 |
var align = command.substring(7);
|
|
12584 |
|
|
12585 |
// Remove all other alignments first
|
|
12586 |
each('left,center,right,full'.split(','), function(name) {
|
|
12587 |
if (align != name)
|
|
12588 |
editor.formatter.remove('align' + name);
|
|
12589 |
});
|
|
12590 |
|
|
12591 |
toggleFormat('align' + align);
|
a9251b
|
12592 |
execCommand('mceRepaint');
|
69d05c
|
12593 |
},
|
A |
12594 |
|
|
12595 |
// Override list commands to fix WebKit bug
|
|
12596 |
'InsertUnorderedList,InsertOrderedList' : function(command) {
|
|
12597 |
var listElm, listParent;
|
|
12598 |
|
|
12599 |
execNativeCommand(command);
|
|
12600 |
|
|
12601 |
// WebKit produces lists within block elements so we need to split them
|
|
12602 |
// we will replace the native list creation logic to custom logic later on
|
|
12603 |
// TODO: Remove this when the list creation logic is removed
|
|
12604 |
listElm = dom.getParent(selection.getNode(), 'ol,ul');
|
|
12605 |
if (listElm) {
|
|
12606 |
listParent = listElm.parentNode;
|
|
12607 |
|
|
12608 |
// If list is within a text block then split that block
|
|
12609 |
if (/^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) {
|
|
12610 |
storeSelection();
|
|
12611 |
dom.split(listParent, listElm);
|
|
12612 |
restoreSelection();
|
d9344f
|
12613 |
}
|
69d05c
|
12614 |
}
|
A |
12615 |
},
|
d9344f
|
12616 |
|
69d05c
|
12617 |
// Override commands to use the text formatter engine
|
a9251b
|
12618 |
'Bold,Italic,Underline,Strikethrough,Superscript,Subscript' : function(command) {
|
69d05c
|
12619 |
toggleFormat(command);
|
A |
12620 |
},
|
|
12621 |
|
|
12622 |
// Override commands to use the text formatter engine
|
|
12623 |
'ForeColor,HiliteColor,FontName' : function(command, ui, value) {
|
|
12624 |
toggleFormat(command, value);
|
|
12625 |
},
|
|
12626 |
|
|
12627 |
FontSize : function(command, ui, value) {
|
|
12628 |
var fontClasses, fontSizes;
|
|
12629 |
|
|
12630 |
// Convert font size 1-7 to styles
|
|
12631 |
if (value >= 1 && value <= 7) {
|
|
12632 |
fontSizes = tinymce.explode(settings.font_size_style_values);
|
|
12633 |
fontClasses = tinymce.explode(settings.font_size_classes);
|
|
12634 |
|
|
12635 |
if (fontClasses)
|
|
12636 |
value = fontClasses[value - 1] || value;
|
|
12637 |
else
|
|
12638 |
value = fontSizes[value - 1] || value;
|
|
12639 |
}
|
|
12640 |
|
|
12641 |
toggleFormat(command, value);
|
|
12642 |
},
|
|
12643 |
|
|
12644 |
RemoveFormat : function(command) {
|
|
12645 |
editor.formatter.remove(command);
|
|
12646 |
},
|
|
12647 |
|
|
12648 |
mceBlockQuote : function(command) {
|
|
12649 |
toggleFormat('blockquote');
|
|
12650 |
},
|
|
12651 |
|
|
12652 |
FormatBlock : function(command, ui, value) {
|
a9251b
|
12653 |
return toggleFormat(value || 'p');
|
69d05c
|
12654 |
},
|
A |
12655 |
|
|
12656 |
mceCleanup : function() {
|
2011be
|
12657 |
var bookmark = selection.getBookmark();
|
A |
12658 |
|
69d05c
|
12659 |
editor.setContent(editor.getContent({cleanup : TRUE}), {cleanup : TRUE});
|
2011be
|
12660 |
|
A |
12661 |
selection.moveToBookmark(bookmark);
|
69d05c
|
12662 |
},
|
A |
12663 |
|
|
12664 |
mceRemoveNode : function(command, ui, value) {
|
|
12665 |
var node = value || selection.getNode();
|
|
12666 |
|
|
12667 |
// Make sure that the body node isn't removed
|
2011be
|
12668 |
if (node != editor.getBody()) {
|
69d05c
|
12669 |
storeSelection();
|
A |
12670 |
editor.dom.remove(node, TRUE);
|
|
12671 |
restoreSelection();
|
|
12672 |
}
|
|
12673 |
},
|
|
12674 |
|
|
12675 |
mceSelectNodeDepth : function(command, ui, value) {
|
|
12676 |
var counter = 0;
|
|
12677 |
|
|
12678 |
dom.getParent(selection.getNode(), function(node) {
|
|
12679 |
if (node.nodeType == 1 && counter++ == value) {
|
|
12680 |
selection.select(node);
|
|
12681 |
return FALSE;
|
|
12682 |
}
|
|
12683 |
}, editor.getBody());
|
|
12684 |
},
|
|
12685 |
|
|
12686 |
mceSelectNode : function(command, ui, value) {
|
|
12687 |
selection.select(value);
|
|
12688 |
},
|
|
12689 |
|
|
12690 |
mceInsertContent : function(command, ui, value) {
|
a9251b
|
12691 |
var caretNode, rng, rootNode, parent, node, rng, nodeRect, viewPortRect, args;
|
T |
12692 |
|
|
12693 |
function findSuitableCaretNode(node, root_node, next) {
|
|
12694 |
var walker = new tinymce.dom.TreeWalker(next ? node.nextSibling : node.previousSibling, root_node);
|
|
12695 |
|
|
12696 |
while ((node = walker.current())) {
|
|
12697 |
if ((node.nodeType == 3 && tinymce.trim(node.nodeValue).length) || node.nodeName == 'BR' || node.nodeName == 'IMG')
|
|
12698 |
return node;
|
|
12699 |
|
|
12700 |
if (next)
|
|
12701 |
walker.next();
|
|
12702 |
else
|
|
12703 |
walker.prev();
|
|
12704 |
}
|
|
12705 |
};
|
|
12706 |
|
|
12707 |
args = {content: value, format: 'html'};
|
|
12708 |
selection.onBeforeSetContent.dispatch(selection, args);
|
|
12709 |
value = args.content;
|
|
12710 |
|
|
12711 |
// Add caret at end of contents if it's missing
|
|
12712 |
if (value.indexOf('{$caret}') == -1)
|
|
12713 |
value += '{$caret}';
|
|
12714 |
|
|
12715 |
// Set the content at selection to a span and replace it's contents with the value
|
|
12716 |
selection.setContent('<span id="__mce">\uFEFF</span>', {no_events : false});
|
|
12717 |
dom.setOuterHTML('__mce', value.replace(/\{\$caret\}/, '<span data-mce-type="bookmark" id="__mce">\uFEFF</span>'));
|
|
12718 |
|
|
12719 |
caretNode = dom.select('#__mce')[0];
|
|
12720 |
rootNode = dom.getRoot();
|
|
12721 |
|
|
12722 |
// Move the caret into the last suitable location within the previous sibling if it's a block since the block might be split
|
|
12723 |
if (caretNode.previousSibling && dom.isBlock(caretNode.previousSibling) || caretNode.parentNode == rootNode) {
|
|
12724 |
node = findSuitableCaretNode(caretNode, rootNode);
|
|
12725 |
if (node) {
|
|
12726 |
if (node.nodeName == 'BR')
|
|
12727 |
node.parentNode.insertBefore(caretNode, node);
|
|
12728 |
else
|
|
12729 |
dom.insertAfter(caretNode, node);
|
|
12730 |
}
|
|
12731 |
}
|
|
12732 |
|
|
12733 |
// Find caret root parent and clean it up using the serializer to avoid nesting
|
|
12734 |
while (caretNode) {
|
|
12735 |
if (caretNode === rootNode) {
|
|
12736 |
// Clean up the parent element by parsing and serializing it
|
|
12737 |
// This will remove invalid elements/attributes and fix nesting issues
|
|
12738 |
dom.setOuterHTML(parent,
|
|
12739 |
new tinymce.html.Serializer({}, editor.schema).serialize(
|
|
12740 |
editor.parser.parse(dom.getOuterHTML(parent))
|
|
12741 |
)
|
|
12742 |
);
|
|
12743 |
|
|
12744 |
break;
|
|
12745 |
}
|
|
12746 |
|
|
12747 |
parent = caretNode;
|
|
12748 |
caretNode = caretNode.parentNode;
|
|
12749 |
}
|
|
12750 |
|
|
12751 |
// Find caret after cleanup and move selection to that location
|
|
12752 |
caretNode = dom.select('#__mce')[0];
|
|
12753 |
if (caretNode) {
|
|
12754 |
node = findSuitableCaretNode(caretNode, rootNode) || findSuitableCaretNode(caretNode, rootNode, true);
|
|
12755 |
dom.remove(caretNode);
|
|
12756 |
|
|
12757 |
if (node) {
|
|
12758 |
rng = dom.createRng();
|
|
12759 |
|
|
12760 |
if (node.nodeType == 3) {
|
|
12761 |
rng.setStart(node, node.length);
|
|
12762 |
rng.setEnd(node, node.length);
|
|
12763 |
} else {
|
|
12764 |
if (node.nodeName == 'BR') {
|
|
12765 |
rng.setStartBefore(node);
|
|
12766 |
rng.setEndBefore(node);
|
|
12767 |
} else {
|
|
12768 |
rng.setStartAfter(node);
|
|
12769 |
rng.setEndAfter(node);
|
|
12770 |
}
|
|
12771 |
}
|
|
12772 |
|
|
12773 |
selection.setRng(rng);
|
|
12774 |
|
|
12775 |
// Scroll range into view scrollIntoView on element can't be used since it will scroll the main view port as well
|
|
12776 |
if (!tinymce.isIE) {
|
|
12777 |
node = dom.create('span', null, '\u00a0');
|
|
12778 |
rng.insertNode(node);
|
|
12779 |
nodeRect = dom.getRect(node);
|
|
12780 |
viewPortRect = dom.getViewPort(editor.getWin());
|
|
12781 |
|
|
12782 |
// Check if node is out side the viewport if it is then scroll to it
|
|
12783 |
if ((nodeRect.y > viewPortRect.y + viewPortRect.h || nodeRect.y < viewPortRect.y) ||
|
|
12784 |
(nodeRect.x > viewPortRect.x + viewPortRect.w || nodeRect.x < viewPortRect.x)) {
|
|
12785 |
editor.getBody().scrollLeft = nodeRect.x;
|
|
12786 |
editor.getBody().scrollTop = nodeRect.y;
|
|
12787 |
}
|
|
12788 |
|
|
12789 |
dom.remove(node);
|
|
12790 |
}
|
|
12791 |
|
|
12792 |
// Make sure that the selection is collapsed after we removed the node fixes a WebKit bug
|
|
12793 |
// where WebKit would place the endContainer/endOffset at a different location than the startContainer/startOffset
|
|
12794 |
selection.collapse(true);
|
|
12795 |
}
|
|
12796 |
}
|
|
12797 |
|
|
12798 |
selection.onSetContent.dispatch(selection, args);
|
|
12799 |
editor.addVisual();
|
69d05c
|
12800 |
},
|
A |
12801 |
|
|
12802 |
mceInsertRawHTML : function(command, ui, value) {
|
|
12803 |
selection.setContent('tiny_mce_marker');
|
a9251b
|
12804 |
editor.setContent(editor.getContent().replace(/tiny_mce_marker/g, function() { return value }));
|
69d05c
|
12805 |
},
|
A |
12806 |
|
|
12807 |
mceSetContent : function(command, ui, value) {
|
|
12808 |
editor.setContent(value);
|
|
12809 |
},
|
|
12810 |
|
|
12811 |
'Indent,Outdent' : function(command) {
|
|
12812 |
var intentValue, indentUnit, value;
|
|
12813 |
|
|
12814 |
// Setup indent level
|
|
12815 |
intentValue = settings.indentation;
|
|
12816 |
indentUnit = /[a-z%]+$/i.exec(intentValue);
|
|
12817 |
intentValue = parseInt(intentValue);
|
|
12818 |
|
|
12819 |
if (!queryCommandState('InsertUnorderedList') && !queryCommandState('InsertOrderedList')) {
|
|
12820 |
each(selection.getSelectedBlocks(), function(element) {
|
|
12821 |
if (command == 'outdent') {
|
|
12822 |
value = Math.max(0, parseInt(element.style.paddingLeft || 0) - intentValue);
|
|
12823 |
dom.setStyle(element, 'paddingLeft', value ? value + indentUnit : '');
|
|
12824 |
} else
|
|
12825 |
dom.setStyle(element, 'paddingLeft', (parseInt(element.style.paddingLeft || 0) + intentValue) + indentUnit);
|
|
12826 |
});
|
|
12827 |
} else
|
|
12828 |
execNativeCommand(command);
|
|
12829 |
},
|
|
12830 |
|
|
12831 |
mceRepaint : function() {
|
|
12832 |
var bookmark;
|
|
12833 |
|
|
12834 |
if (tinymce.isGecko) {
|
|
12835 |
try {
|
|
12836 |
storeSelection(TRUE);
|
|
12837 |
|
|
12838 |
if (selection.getSel())
|
|
12839 |
selection.getSel().selectAllChildren(editor.getBody());
|
|
12840 |
|
|
12841 |
selection.collapse(TRUE);
|
|
12842 |
restoreSelection();
|
|
12843 |
} catch (ex) {
|
|
12844 |
// Ignore
|
|
12845 |
}
|
|
12846 |
}
|
|
12847 |
},
|
|
12848 |
|
|
12849 |
mceToggleFormat : function(command, ui, value) {
|
|
12850 |
editor.formatter.toggle(value);
|
|
12851 |
},
|
|
12852 |
|
|
12853 |
InsertHorizontalRule : function() {
|
a9251b
|
12854 |
editor.execCommand('mceInsertContent', false, '<hr />');
|
69d05c
|
12855 |
},
|
A |
12856 |
|
|
12857 |
mceToggleVisualAid : function() {
|
|
12858 |
editor.hasVisual = !editor.hasVisual;
|
|
12859 |
editor.addVisual();
|
|
12860 |
},
|
|
12861 |
|
|
12862 |
mceReplaceContent : function(command, ui, value) {
|
a9251b
|
12863 |
editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, selection.getContent({format : 'text'})));
|
69d05c
|
12864 |
},
|
A |
12865 |
|
|
12866 |
mceInsertLink : function(command, ui, value) {
|
a9251b
|
12867 |
var link = dom.getParent(selection.getNode(), 'a'), img, floatVal;
|
69d05c
|
12868 |
|
A |
12869 |
if (tinymce.is(value, 'string'))
|
|
12870 |
value = {href : value};
|
|
12871 |
|
a9251b
|
12872 |
// Spaces are never valid in URLs and it's a very common mistake for people to make so we fix it here.
|
T |
12873 |
value.href = value.href.replace(' ', '%20');
|
|
12874 |
|
69d05c
|
12875 |
if (!link) {
|
a9251b
|
12876 |
// WebKit can't create links on float images for some odd reason so just remove it and restore it later
|
T |
12877 |
if (tinymce.isWebKit) {
|
|
12878 |
img = dom.getParent(selection.getNode(), 'img');
|
|
12879 |
|
|
12880 |
if (img) {
|
|
12881 |
floatVal = img.style.cssFloat;
|
|
12882 |
img.style.cssFloat = null;
|
|
12883 |
}
|
|
12884 |
}
|
|
12885 |
|
69d05c
|
12886 |
execNativeCommand('CreateLink', FALSE, 'javascript:mctmp(0);');
|
a9251b
|
12887 |
|
T |
12888 |
// Restore float value
|
|
12889 |
if (floatVal)
|
|
12890 |
img.style.cssFloat = floatVal;
|
|
12891 |
|
|
12892 |
each(dom.select("a[href='javascript:mctmp(0);']"), function(link) {
|
69d05c
|
12893 |
dom.setAttribs(link, value);
|
A |
12894 |
});
|
d9344f
|
12895 |
} else {
|
69d05c
|
12896 |
if (value.href)
|
A |
12897 |
dom.setAttribs(link, value);
|
|
12898 |
else
|
2011be
|
12899 |
editor.dom.remove(link, TRUE);
|
d9344f
|
12900 |
}
|
2011be
|
12901 |
},
|
A |
12902 |
|
|
12903 |
selectAll : function() {
|
a9251b
|
12904 |
var root = dom.getRoot(), rng = dom.createRng();
|
T |
12905 |
|
2011be
|
12906 |
rng.setStart(root, 0);
|
A |
12907 |
rng.setEnd(root, root.childNodes.length);
|
a9251b
|
12908 |
|
2011be
|
12909 |
editor.selection.setRng(rng);
|
d9344f
|
12910 |
}
|
69d05c
|
12911 |
});
|
d9344f
|
12912 |
|
69d05c
|
12913 |
// Add queryCommandState overrides
|
A |
12914 |
addCommands({
|
|
12915 |
// Override justify commands
|
|
12916 |
'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull' : function(command) {
|
|
12917 |
return isFormatMatch('align' + command.substring(7));
|
|
12918 |
},
|
d9344f
|
12919 |
|
a9251b
|
12920 |
'Bold,Italic,Underline,Strikethrough,Superscript,Subscript' : function(command) {
|
69d05c
|
12921 |
return isFormatMatch(command);
|
A |
12922 |
},
|
d9344f
|
12923 |
|
69d05c
|
12924 |
mceBlockQuote : function() {
|
A |
12925 |
return isFormatMatch('blockquote');
|
|
12926 |
},
|
d9344f
|
12927 |
|
69d05c
|
12928 |
Outdent : function() {
|
A |
12929 |
var node;
|
d9344f
|
12930 |
|
69d05c
|
12931 |
if (settings.inline_styles) {
|
A |
12932 |
if ((node = dom.getParent(selection.getStart(), dom.isBlock)) && parseInt(node.style.paddingLeft) > 0)
|
|
12933 |
return TRUE;
|
|
12934 |
|
|
12935 |
if ((node = dom.getParent(selection.getEnd(), dom.isBlock)) && parseInt(node.style.paddingLeft) > 0)
|
|
12936 |
return TRUE;
|
d9344f
|
12937 |
}
|
S |
12938 |
|
69d05c
|
12939 |
return queryCommandState('InsertUnorderedList') || queryCommandState('InsertOrderedList') || (!settings.inline_styles && !!dom.getParent(selection.getNode(), 'BLOCKQUOTE'));
|
A |
12940 |
},
|
d9344f
|
12941 |
|
69d05c
|
12942 |
'InsertUnorderedList,InsertOrderedList' : function(command) {
|
A |
12943 |
return dom.getParent(selection.getNode(), command == 'insertunorderedlist' ? 'UL' : 'OL');
|
d9344f
|
12944 |
}
|
69d05c
|
12945 |
}, 'state');
|
d9344f
|
12946 |
|
69d05c
|
12947 |
// Add queryCommandValue overrides
|
A |
12948 |
addCommands({
|
|
12949 |
'FontSize,FontName' : function(command) {
|
|
12950 |
var value = 0, parent;
|
d9344f
|
12951 |
|
69d05c
|
12952 |
if (parent = dom.getParent(selection.getNode(), 'span')) {
|
A |
12953 |
if (command == 'fontsize')
|
|
12954 |
value = parent.style.fontSize;
|
|
12955 |
else
|
|
12956 |
value = parent.style.fontFamily.replace(/, /g, ',').replace(/[\'\"]/g, '').toLowerCase();
|
d9344f
|
12957 |
}
|
S |
12958 |
|
69d05c
|
12959 |
return value;
|
d9344f
|
12960 |
}
|
69d05c
|
12961 |
}, 'value');
|
d9344f
|
12962 |
|
69d05c
|
12963 |
// Add undo manager logic
|
A |
12964 |
if (settings.custom_undo_redo) {
|
|
12965 |
addCommands({
|
|
12966 |
Undo : function() {
|
|
12967 |
editor.undoManager.undo();
|
|
12968 |
},
|
d9344f
|
12969 |
|
69d05c
|
12970 |
Redo : function() {
|
A |
12971 |
editor.undoManager.redo();
|
d9344f
|
12972 |
}
|
S |
12973 |
});
|
29da64
|
12974 |
}
|
69d05c
|
12975 |
};
|
29da64
|
12976 |
})(tinymce);
|
a9251b
|
12977 |
|
29da64
|
12978 |
(function(tinymce) {
|
69d05c
|
12979 |
var Dispatcher = tinymce.util.Dispatcher;
|
d9344f
|
12980 |
|
69d05c
|
12981 |
tinymce.UndoManager = function(editor) {
|
A |
12982 |
var self, index = 0, data = [];
|
|
12983 |
|
|
12984 |
function getContent() {
|
|
12985 |
return tinymce.trim(editor.getContent({format : 'raw', no_events : 1}));
|
|
12986 |
};
|
|
12987 |
|
|
12988 |
return self = {
|
a9251b
|
12989 |
typing : false,
|
69d05c
|
12990 |
|
A |
12991 |
onAdd : new Dispatcher(self),
|
a9251b
|
12992 |
|
69d05c
|
12993 |
onUndo : new Dispatcher(self),
|
a9251b
|
12994 |
|
69d05c
|
12995 |
onRedo : new Dispatcher(self),
|
a9251b
|
12996 |
|
T |
12997 |
beforeChange : function() {
|
|
12998 |
// Set before bookmark on previous level
|
|
12999 |
if (data[index])
|
|
13000 |
data[index].beforeBookmark = editor.selection.getBookmark(2, true);
|
|
13001 |
},
|
69d05c
|
13002 |
|
A |
13003 |
add : function(level) {
|
|
13004 |
var i, settings = editor.settings, lastLevel;
|
|
13005 |
|
|
13006 |
level = level || {};
|
|
13007 |
level.content = getContent();
|
|
13008 |
|
|
13009 |
// Add undo level if needed
|
|
13010 |
lastLevel = data[index];
|
a9251b
|
13011 |
if (lastLevel && lastLevel.content == level.content)
|
T |
13012 |
return null;
|
69d05c
|
13013 |
|
A |
13014 |
// Time to compress
|
|
13015 |
if (settings.custom_undo_redo_levels) {
|
|
13016 |
if (data.length > settings.custom_undo_redo_levels) {
|
|
13017 |
for (i = 0; i < data.length - 1; i++)
|
|
13018 |
data[i] = data[i + 1];
|
|
13019 |
|
|
13020 |
data.length--;
|
|
13021 |
index = data.length;
|
|
13022 |
}
|
|
13023 |
}
|
|
13024 |
|
|
13025 |
// Get a non intrusive normalized bookmark
|
|
13026 |
level.bookmark = editor.selection.getBookmark(2, true);
|
|
13027 |
|
|
13028 |
// Crop array if needed
|
a9251b
|
13029 |
if (index < data.length - 1)
|
T |
13030 |
data.length = index + 1;
|
69d05c
|
13031 |
|
A |
13032 |
data.push(level);
|
|
13033 |
index = data.length - 1;
|
|
13034 |
|
|
13035 |
self.onAdd.dispatch(self, level);
|
|
13036 |
editor.isNotDirty = 0;
|
|
13037 |
|
|
13038 |
return level;
|
|
13039 |
},
|
|
13040 |
|
|
13041 |
undo : function() {
|
|
13042 |
var level, i;
|
|
13043 |
|
|
13044 |
if (self.typing) {
|
|
13045 |
self.add();
|
a9251b
|
13046 |
self.typing = false;
|
69d05c
|
13047 |
}
|
A |
13048 |
|
|
13049 |
if (index > 0) {
|
|
13050 |
level = data[--index];
|
|
13051 |
|
|
13052 |
editor.setContent(level.content, {format : 'raw'});
|
a9251b
|
13053 |
editor.selection.moveToBookmark(level.beforeBookmark);
|
69d05c
|
13054 |
|
A |
13055 |
self.onUndo.dispatch(self, level);
|
|
13056 |
}
|
|
13057 |
|
|
13058 |
return level;
|
|
13059 |
},
|
|
13060 |
|
|
13061 |
redo : function() {
|
|
13062 |
var level;
|
|
13063 |
|
|
13064 |
if (index < data.length - 1) {
|
|
13065 |
level = data[++index];
|
|
13066 |
|
|
13067 |
editor.setContent(level.content, {format : 'raw'});
|
|
13068 |
editor.selection.moveToBookmark(level.bookmark);
|
|
13069 |
|
|
13070 |
self.onRedo.dispatch(self, level);
|
|
13071 |
}
|
|
13072 |
|
|
13073 |
return level;
|
|
13074 |
},
|
|
13075 |
|
|
13076 |
clear : function() {
|
|
13077 |
data = [];
|
a9251b
|
13078 |
index = 0;
|
T |
13079 |
self.typing = false;
|
69d05c
|
13080 |
},
|
A |
13081 |
|
|
13082 |
hasUndo : function() {
|
a9251b
|
13083 |
return index > 0 || this.typing;
|
69d05c
|
13084 |
},
|
A |
13085 |
|
|
13086 |
hasRedo : function() {
|
a9251b
|
13087 |
return index < data.length - 1 && !this.typing;
|
69d05c
|
13088 |
}
|
A |
13089 |
};
|
|
13090 |
};
|
|
13091 |
})(tinymce);
|
|
13092 |
|
|
13093 |
(function(tinymce) {
|
|
13094 |
// Shorten names
|
|
13095 |
var Event = tinymce.dom.Event,
|
|
13096 |
isIE = tinymce.isIE,
|
|
13097 |
isGecko = tinymce.isGecko,
|
|
13098 |
isOpera = tinymce.isOpera,
|
|
13099 |
each = tinymce.each,
|
|
13100 |
extend = tinymce.extend,
|
|
13101 |
TRUE = true,
|
|
13102 |
FALSE = false;
|
29da64
|
13103 |
|
2011be
|
13104 |
function cloneFormats(node) {
|
A |
13105 |
var clone, temp, inner;
|
|
13106 |
|
|
13107 |
do {
|
|
13108 |
if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(node.nodeName)) {
|
|
13109 |
if (clone) {
|
|
13110 |
temp = node.cloneNode(false);
|
|
13111 |
temp.appendChild(clone);
|
|
13112 |
clone = temp;
|
|
13113 |
} else {
|
|
13114 |
clone = inner = node.cloneNode(false);
|
|
13115 |
}
|
|
13116 |
|
|
13117 |
clone.removeAttribute('id');
|
|
13118 |
}
|
|
13119 |
} while (node = node.parentNode);
|
|
13120 |
|
|
13121 |
if (clone)
|
|
13122 |
return {wrapper : clone, inner : inner};
|
|
13123 |
};
|
|
13124 |
|
58fb65
|
13125 |
// Checks if the selection/caret is at the end of the specified block element
|
A |
13126 |
function isAtEnd(rng, par) {
|
|
13127 |
var rng2 = par.ownerDocument.createRange();
|
|
13128 |
|
|
13129 |
rng2.setStart(rng.endContainer, rng.endOffset);
|
|
13130 |
rng2.setEndAfter(par);
|
|
13131 |
|
|
13132 |
// Get number of characters to the right of the cursor if it's zero then we are at the end and need to merge the next block element
|
|
13133 |
return rng2.cloneContents().textContent.length == 0;
|
|
13134 |
};
|
|
13135 |
|
69d05c
|
13136 |
function splitList(selection, dom, li) {
|
A |
13137 |
var listBlock, block;
|
|
13138 |
|
a9251b
|
13139 |
if (dom.isEmpty(li)) {
|
69d05c
|
13140 |
listBlock = dom.getParent(li, 'ul,ol');
|
A |
13141 |
|
|
13142 |
if (!dom.getParent(listBlock.parentNode, 'ul,ol')) {
|
|
13143 |
dom.split(listBlock, li);
|
a9251b
|
13144 |
block = dom.create('p', 0, '<br data-mce-bogus="1" />');
|
69d05c
|
13145 |
dom.replace(block, li);
|
A |
13146 |
selection.select(block, 1);
|
|
13147 |
}
|
|
13148 |
|
|
13149 |
return FALSE;
|
|
13150 |
}
|
|
13151 |
|
|
13152 |
return TRUE;
|
29da64
|
13153 |
};
|
d9344f
|
13154 |
|
S |
13155 |
tinymce.create('tinymce.ForceBlocks', {
|
|
13156 |
ForceBlocks : function(ed) {
|
|
13157 |
var t = this, s = ed.settings, elm;
|
|
13158 |
|
|
13159 |
t.editor = ed;
|
|
13160 |
t.dom = ed.dom;
|
|
13161 |
elm = (s.forced_root_block || 'p').toLowerCase();
|
|
13162 |
s.element = elm.toUpperCase();
|
|
13163 |
|
|
13164 |
ed.onPreInit.add(t.setup, t);
|
|
13165 |
|
|
13166 |
if (s.forced_root_block) {
|
|
13167 |
ed.onInit.add(t.forceRoots, t);
|
|
13168 |
ed.onSetContent.add(t.forceRoots, t);
|
|
13169 |
ed.onBeforeGetContent.add(t.forceRoots, t);
|
a9251b
|
13170 |
ed.onExecCommand.add(function(ed, cmd) {
|
T |
13171 |
if (cmd == 'mceInsertContent') {
|
|
13172 |
t.forceRoots();
|
|
13173 |
ed.nodeChanged();
|
|
13174 |
}
|
|
13175 |
});
|
d9344f
|
13176 |
}
|
S |
13177 |
},
|
|
13178 |
|
|
13179 |
setup : function() {
|
69d05c
|
13180 |
var t = this, ed = t.editor, s = ed.settings, dom = ed.dom, selection = ed.selection;
|
d9344f
|
13181 |
|
S |
13182 |
// Force root blocks when typing and when getting output
|
|
13183 |
if (s.forced_root_block) {
|
69d05c
|
13184 |
ed.onBeforeExecCommand.add(t.forceRoots, t);
|
d9344f
|
13185 |
ed.onKeyUp.add(t.forceRoots, t);
|
S |
13186 |
ed.onPreProcess.add(t.forceRoots, t);
|
|
13187 |
}
|
|
13188 |
|
|
13189 |
if (s.force_br_newlines) {
|
|
13190 |
// Force IE to produce BRs on enter
|
|
13191 |
if (isIE) {
|
|
13192 |
ed.onKeyPress.add(function(ed, e) {
|
69d05c
|
13193 |
var n;
|
d9344f
|
13194 |
|
69d05c
|
13195 |
if (e.keyCode == 13 && selection.getNode().nodeName != 'LI') {
|
A |
13196 |
selection.setContent('<br id="__" /> ', {format : 'raw'});
|
|
13197 |
n = dom.get('__');
|
d9344f
|
13198 |
n.removeAttribute('id');
|
69d05c
|
13199 |
selection.select(n);
|
A |
13200 |
selection.collapse();
|
d9344f
|
13201 |
return Event.cancel(e);
|
S |
13202 |
}
|
|
13203 |
});
|
|
13204 |
}
|
|
13205 |
}
|
|
13206 |
|
2011be
|
13207 |
if (s.force_p_newlines) {
|
A |
13208 |
if (!isIE) {
|
|
13209 |
ed.onKeyPress.add(function(ed, e) {
|
|
13210 |
if (e.keyCode == 13 && !e.shiftKey && !t.insertPara(e))
|
|
13211 |
Event.cancel(e);
|
|
13212 |
});
|
|
13213 |
} else {
|
|
13214 |
// Ungly hack to for IE to preserve the formatting when you press
|
|
13215 |
// enter at the end of a block element with formatted contents
|
|
13216 |
// This logic overrides the browsers default logic with
|
|
13217 |
// custom logic that enables us to control the output
|
|
13218 |
tinymce.addUnload(function() {
|
|
13219 |
t._previousFormats = 0; // Fix IE leak
|
|
13220 |
});
|
|
13221 |
|
|
13222 |
ed.onKeyPress.add(function(ed, e) {
|
|
13223 |
t._previousFormats = 0;
|
|
13224 |
|
|
13225 |
// Clone the current formats, this will later be applied to the new block contents
|
|
13226 |
if (e.keyCode == 13 && !e.shiftKey && ed.selection.isCollapsed() && s.keep_styles)
|
|
13227 |
t._previousFormats = cloneFormats(ed.selection.getStart());
|
|
13228 |
});
|
|
13229 |
|
|
13230 |
ed.onKeyUp.add(function(ed, e) {
|
|
13231 |
// Let IE break the element and the wrap the new caret location in the previous formats
|
|
13232 |
if (e.keyCode == 13 && !e.shiftKey) {
|
|
13233 |
var parent = ed.selection.getStart(), fmt = t._previousFormats;
|
|
13234 |
|
|
13235 |
// Parent is an empty block
|
a9251b
|
13236 |
if (!parent.hasChildNodes() && fmt) {
|
2011be
|
13237 |
parent = dom.getParent(parent, dom.isBlock);
|
A |
13238 |
|
a9251b
|
13239 |
if (parent && parent.nodeName != 'LI') {
|
2011be
|
13240 |
parent.innerHTML = '';
|
a9251b
|
13241 |
|
2011be
|
13242 |
if (t._previousFormats) {
|
A |
13243 |
parent.appendChild(fmt.wrapper);
|
|
13244 |
fmt.inner.innerHTML = '\uFEFF';
|
|
13245 |
} else
|
|
13246 |
parent.innerHTML = '\uFEFF';
|
|
13247 |
|
|
13248 |
selection.select(parent, 1);
|
a9251b
|
13249 |
selection.collapse(true);
|
2011be
|
13250 |
ed.getDoc().execCommand('Delete', false, null);
|
a9251b
|
13251 |
t._previousFormats = 0;
|
2011be
|
13252 |
}
|
A |
13253 |
}
|
|
13254 |
}
|
|
13255 |
});
|
|
13256 |
}
|
d9344f
|
13257 |
|
S |
13258 |
if (isGecko) {
|
|
13259 |
ed.onKeyDown.add(function(ed, e) {
|
|
13260 |
if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey)
|
|
13261 |
t.backspaceDelete(e, e.keyCode == 8);
|
|
13262 |
});
|
|
13263 |
}
|
|
13264 |
}
|
|
13265 |
|
69d05c
|
13266 |
// Workaround for missing shift+enter support, http://bugs.webkit.org/show_bug.cgi?id=16973
|
A |
13267 |
if (tinymce.isWebKit) {
|
|
13268 |
function insertBr(ed) {
|
|
13269 |
var rng = selection.getRng(), br, div = dom.create('div', null, ' '), divYPos, vpHeight = dom.getViewPort(ed.getWin()).h;
|
d9344f
|
13270 |
|
69d05c
|
13271 |
// Insert BR element
|
A |
13272 |
rng.insertNode(br = dom.create('br'));
|
|
13273 |
|
|
13274 |
// Place caret after BR
|
|
13275 |
rng.setStartAfter(br);
|
|
13276 |
rng.setEndAfter(br);
|
|
13277 |
selection.setRng(rng);
|
|
13278 |
|
|
13279 |
// Could not place caret after BR then insert an nbsp entity and move the caret
|
|
13280 |
if (selection.getSel().focusNode == br.previousSibling) {
|
|
13281 |
selection.select(dom.insertAfter(dom.doc.createTextNode('\u00a0'), br));
|
|
13282 |
selection.collapse(TRUE);
|
|
13283 |
}
|
|
13284 |
|
|
13285 |
// Create a temporary DIV after the BR and get the position as it
|
|
13286 |
// seems like getPos() returns 0 for text nodes and BR elements.
|
|
13287 |
dom.insertAfter(div, br);
|
|
13288 |
divYPos = dom.getPos(div).y;
|
|
13289 |
dom.remove(div);
|
|
13290 |
|
|
13291 |
// Scroll to new position, scrollIntoView can't be used due to bug: http://bugs.webkit.org/show_bug.cgi?id=16117
|
|
13292 |
if (divYPos > vpHeight) // It is not necessary to scroll if the DIV is inside the view port.
|
|
13293 |
ed.getWin().scrollTo(0, divYPos);
|
|
13294 |
};
|
|
13295 |
|
|
13296 |
ed.onKeyPress.add(function(ed, e) {
|
2011be
|
13297 |
if (e.keyCode == 13 && (e.shiftKey || (s.force_br_newlines && !dom.getParent(selection.getNode(), 'h1,h2,h3,h4,h5,h6,ol,ul')))) {
|
69d05c
|
13298 |
insertBr(ed);
|
A |
13299 |
Event.cancel(e);
|
|
13300 |
}
|
d9344f
|
13301 |
});
|
69d05c
|
13302 |
}
|
58fb65
|
13303 |
|
29da64
|
13304 |
// IE specific fixes
|
A |
13305 |
if (isIE) {
|
|
13306 |
// Replaces IE:s auto generated paragraphs with the specified element name
|
|
13307 |
if (s.element != 'P') {
|
|
13308 |
ed.onKeyPress.add(function(ed, e) {
|
69d05c
|
13309 |
t.lastElm = selection.getNode().nodeName;
|
29da64
|
13310 |
});
|
d9344f
|
13311 |
|
29da64
|
13312 |
ed.onKeyUp.add(function(ed, e) {
|
69d05c
|
13313 |
var bl, n = selection.getNode(), b = ed.getBody();
|
d9344f
|
13314 |
|
29da64
|
13315 |
if (b.childNodes.length === 1 && n.nodeName == 'P') {
|
69d05c
|
13316 |
n = dom.rename(n, s.element);
|
A |
13317 |
selection.select(n);
|
|
13318 |
selection.collapse();
|
d9344f
|
13319 |
ed.nodeChanged();
|
29da64
|
13320 |
} else if (e.keyCode == 13 && !e.shiftKey && t.lastElm != 'P') {
|
69d05c
|
13321 |
bl = dom.getParent(n, 'p');
|
29da64
|
13322 |
|
A |
13323 |
if (bl) {
|
69d05c
|
13324 |
dom.rename(bl, s.element);
|
29da64
|
13325 |
ed.nodeChanged();
|
A |
13326 |
}
|
d9344f
|
13327 |
}
|
29da64
|
13328 |
});
|
A |
13329 |
}
|
d9344f
|
13330 |
}
|
S |
13331 |
},
|
|
13332 |
|
|
13333 |
find : function(n, t, s) {
|
69d05c
|
13334 |
var ed = this.editor, w = ed.getDoc().createTreeWalker(n, 4, null, FALSE), c = -1;
|
d9344f
|
13335 |
|
S |
13336 |
while (n = w.nextNode()) {
|
|
13337 |
c++;
|
|
13338 |
|
|
13339 |
// Index by node
|
|
13340 |
if (t == 0 && n == s)
|
|
13341 |
return c;
|
|
13342 |
|
|
13343 |
// Node by index
|
|
13344 |
if (t == 1 && c == s)
|
|
13345 |
return n;
|
|
13346 |
}
|
|
13347 |
|
|
13348 |
return -1;
|
|
13349 |
},
|
|
13350 |
|
|
13351 |
forceRoots : function(ed, e) {
|
|
13352 |
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;
|
29da64
|
13353 |
var nx, bl, bp, sp, le, nl = b.childNodes, i, n, eid;
|
d9344f
|
13354 |
|
S |
13355 |
// Fix for bug #1863847
|
29da64
|
13356 |
//if (e && e.keyCode == 13)
|
69d05c
|
13357 |
// return TRUE;
|
d9344f
|
13358 |
|
S |
13359 |
// Wrap non blocks into blocks
|
|
13360 |
for (i = nl.length - 1; i >= 0; i--) {
|
|
13361 |
nx = nl[i];
|
69d05c
|
13362 |
|
A |
13363 |
// Ignore internal elements
|
a9251b
|
13364 |
if (nx.nodeType === 1 && nx.getAttribute('data-mce-type')) {
|
69d05c
|
13365 |
bl = null;
|
A |
13366 |
continue;
|
|
13367 |
}
|
d9344f
|
13368 |
|
S |
13369 |
// Is text or non block element
|
58fb65
|
13370 |
if (nx.nodeType === 3 || (!t.dom.isBlock(nx) && nx.nodeType !== 8 && !/^(script|mce:script|style|mce:style)$/i.test(nx.nodeName))) {
|
d9344f
|
13371 |
if (!bl) {
|
S |
13372 |
// Create new block but ignore whitespace
|
|
13373 |
if (nx.nodeType != 3 || /[^\s]/g.test(nx.nodeValue)) {
|
|
13374 |
// Store selection
|
|
13375 |
if (si == -2 && r) {
|
a9251b
|
13376 |
if (!isIE || r.setStart) {
|
29da64
|
13377 |
// If selection is element then mark it
|
A |
13378 |
if (r.startContainer.nodeType == 1 && (n = r.startContainer.childNodes[r.startOffset]) && n.nodeType == 1) {
|
|
13379 |
// Save the id of the selected element
|
|
13380 |
eid = n.getAttribute("id");
|
|
13381 |
n.setAttribute("id", "__mce");
|
|
13382 |
} else {
|
|
13383 |
// If element is inside body, might not be the case in contentEdiable mode
|
|
13384 |
if (ed.dom.getParent(r.startContainer, function(e) {return e === b;})) {
|
|
13385 |
so = r.startOffset;
|
|
13386 |
eo = r.endOffset;
|
|
13387 |
si = t.find(b, 0, r.startContainer);
|
|
13388 |
ei = t.find(b, 0, r.endContainer);
|
|
13389 |
}
|
18240a
|
13390 |
}
|
d9344f
|
13391 |
} else {
|
2011be
|
13392 |
// Force control range into text range
|
A |
13393 |
if (r.item) {
|
|
13394 |
tr = d.body.createTextRange();
|
|
13395 |
tr.moveToElementText(r.item(0));
|
|
13396 |
r = tr;
|
|
13397 |
}
|
|
13398 |
|
d9344f
|
13399 |
tr = d.body.createTextRange();
|
S |
13400 |
tr.moveToElementText(b);
|
|
13401 |
tr.collapse(1);
|
|
13402 |
bp = tr.move('character', c) * -1;
|
|
13403 |
|
|
13404 |
tr = r.duplicate();
|
|
13405 |
tr.collapse(1);
|
|
13406 |
sp = tr.move('character', c) * -1;
|
|
13407 |
|
|
13408 |
tr = r.duplicate();
|
|
13409 |
tr.collapse(0);
|
|
13410 |
le = (tr.move('character', c) * -1) - sp;
|
|
13411 |
|
|
13412 |
si = sp - bp;
|
|
13413 |
ei = le;
|
|
13414 |
}
|
|
13415 |
}
|
|
13416 |
|
58fb65
|
13417 |
// Uses replaceChild instead of cloneNode since it removes selected attribute from option elements on IE
|
A |
13418 |
// See: http://support.microsoft.com/kb/829907
|
d9344f
|
13419 |
bl = ed.dom.create(ed.settings.forced_root_block);
|
S |
13420 |
nx.parentNode.replaceChild(bl, nx);
|
58fb65
|
13421 |
bl.appendChild(nx);
|
d9344f
|
13422 |
}
|
S |
13423 |
} else {
|
|
13424 |
if (bl.hasChildNodes())
|
|
13425 |
bl.insertBefore(nx, bl.firstChild);
|
|
13426 |
else
|
|
13427 |
bl.appendChild(nx);
|
|
13428 |
}
|
|
13429 |
} else
|
|
13430 |
bl = null; // Time to create new block
|
|
13431 |
}
|
|
13432 |
|
|
13433 |
// Restore selection
|
|
13434 |
if (si != -2) {
|
a9251b
|
13435 |
if (!isIE || r.setStart) {
|
18240a
|
13436 |
bl = b.getElementsByTagName(ed.settings.element)[0];
|
d9344f
|
13437 |
r = d.createRange();
|
S |
13438 |
|
|
13439 |
// Select last location or generated block
|
|
13440 |
if (si != -1)
|
|
13441 |
r.setStart(t.find(b, 1, si), so);
|
|
13442 |
else
|
|
13443 |
r.setStart(bl, 0);
|
|
13444 |
|
|
13445 |
// Select last location or generated block
|
|
13446 |
if (ei != -1)
|
|
13447 |
r.setEnd(t.find(b, 1, ei), eo);
|
|
13448 |
else
|
|
13449 |
r.setEnd(bl, 0);
|
|
13450 |
|
|
13451 |
if (s) {
|
|
13452 |
s.removeAllRanges();
|
|
13453 |
s.addRange(r);
|
|
13454 |
}
|
|
13455 |
} else {
|
|
13456 |
try {
|
|
13457 |
r = s.createRange();
|
|
13458 |
r.moveToElementText(b);
|
|
13459 |
r.collapse(1);
|
|
13460 |
r.moveStart('character', si);
|
|
13461 |
r.moveEnd('character', ei);
|
|
13462 |
r.select();
|
|
13463 |
} catch (ex) {
|
|
13464 |
// Ignore
|
|
13465 |
}
|
|
13466 |
}
|
a9251b
|
13467 |
} else if ((!isIE || r.setStart) && (n = ed.dom.get('__mce'))) {
|
29da64
|
13468 |
// Restore the id of the selected element
|
A |
13469 |
if (eid)
|
|
13470 |
n.setAttribute('id', eid);
|
|
13471 |
else
|
|
13472 |
n.removeAttribute('id');
|
|
13473 |
|
|
13474 |
// Move caret before selected element
|
|
13475 |
r = d.createRange();
|
|
13476 |
r.setStartBefore(n);
|
|
13477 |
r.setEndBefore(n);
|
|
13478 |
se.setRng(r);
|
d9344f
|
13479 |
}
|
S |
13480 |
},
|
|
13481 |
|
|
13482 |
getParentBlock : function(n) {
|
|
13483 |
var d = this.dom;
|
|
13484 |
|
|
13485 |
return d.getParent(n, d.isBlock);
|
|
13486 |
},
|
|
13487 |
|
|
13488 |
insertPara : function(e) {
|
18240a
|
13489 |
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;
|
29da64
|
13490 |
var rb, ra, dir, sn, so, en, eo, sb, eb, bn, bef, aft, sc, ec, n, vp = dom.getViewPort(ed.getWin()), y, ch, car;
|
a9251b
|
13491 |
|
T |
13492 |
ed.undoManager.beforeChange();
|
d9344f
|
13493 |
|
S |
13494 |
// If root blocks are forced then use Operas default behavior since it's really good
|
|
13495 |
// Removed due to bug: #1853816
|
|
13496 |
// if (se.forced_root_block && isOpera)
|
69d05c
|
13497 |
// return TRUE;
|
d9344f
|
13498 |
|
S |
13499 |
// Setup before range
|
|
13500 |
rb = d.createRange();
|
|
13501 |
|
|
13502 |
// If is before the first block element and in body, then move it into first block element
|
|
13503 |
rb.setStart(s.anchorNode, s.anchorOffset);
|
69d05c
|
13504 |
rb.collapse(TRUE);
|
d9344f
|
13505 |
|
S |
13506 |
// Setup after range
|
|
13507 |
ra = d.createRange();
|
|
13508 |
|
|
13509 |
// If is before the first block element and in body, then move it into first block element
|
|
13510 |
ra.setStart(s.focusNode, s.focusOffset);
|
69d05c
|
13511 |
ra.collapse(TRUE);
|
d9344f
|
13512 |
|
S |
13513 |
// Setup start/end points
|
|
13514 |
dir = rb.compareBoundaryPoints(rb.START_TO_END, ra) < 0;
|
|
13515 |
sn = dir ? s.anchorNode : s.focusNode;
|
|
13516 |
so = dir ? s.anchorOffset : s.focusOffset;
|
|
13517 |
en = dir ? s.focusNode : s.anchorNode;
|
|
13518 |
eo = dir ? s.focusOffset : s.anchorOffset;
|
18240a
|
13519 |
|
A |
13520 |
// If selection is in empty table cell
|
|
13521 |
if (sn === en && /^(TD|TH)$/.test(sn.nodeName)) {
|
58fb65
|
13522 |
if (sn.firstChild.nodeName == 'BR')
|
A |
13523 |
dom.remove(sn.firstChild); // Remove BR
|
18240a
|
13524 |
|
A |
13525 |
// Create two new block elements
|
58fb65
|
13526 |
if (sn.childNodes.length == 0) {
|
A |
13527 |
ed.dom.add(sn, se.element, null, '<br />');
|
|
13528 |
aft = ed.dom.add(sn, se.element, null, '<br />');
|
|
13529 |
} else {
|
|
13530 |
n = sn.innerHTML;
|
|
13531 |
sn.innerHTML = '';
|
|
13532 |
ed.dom.add(sn, se.element, null, n);
|
|
13533 |
aft = ed.dom.add(sn, se.element, null, '<br />');
|
|
13534 |
}
|
18240a
|
13535 |
|
A |
13536 |
// Move caret into the last one
|
|
13537 |
r = d.createRange();
|
|
13538 |
r.selectNodeContents(aft);
|
|
13539 |
r.collapse(1);
|
|
13540 |
ed.selection.setRng(r);
|
|
13541 |
|
69d05c
|
13542 |
return FALSE;
|
18240a
|
13543 |
}
|
d9344f
|
13544 |
|
S |
13545 |
// If the caret is in an invalid location in FF we need to move it into the first block
|
|
13546 |
if (sn == b && en == b && b.firstChild && ed.dom.isBlock(b.firstChild)) {
|
|
13547 |
sn = en = sn.firstChild;
|
|
13548 |
so = eo = 0;
|
|
13549 |
rb = d.createRange();
|
|
13550 |
rb.setStart(sn, 0);
|
|
13551 |
ra = d.createRange();
|
|
13552 |
ra.setStart(en, 0);
|
|
13553 |
}
|
|
13554 |
|
|
13555 |
// Never use body as start or end node
|
|
13556 |
sn = sn.nodeName == "HTML" ? d.body : sn; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
|
|
13557 |
sn = sn.nodeName == "BODY" ? sn.firstChild : sn;
|
|
13558 |
en = en.nodeName == "HTML" ? d.body : en; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
|
|
13559 |
en = en.nodeName == "BODY" ? en.firstChild : en;
|
|
13560 |
|
|
13561 |
// Get start and end blocks
|
|
13562 |
sb = t.getParentBlock(sn);
|
|
13563 |
eb = t.getParentBlock(en);
|
|
13564 |
bn = sb ? sb.nodeName : se.element; // Get block name to create
|
|
13565 |
|
|
13566 |
// Return inside list use default browser behavior
|
69d05c
|
13567 |
if (n = t.dom.getParent(sb, 'li,pre')) {
|
A |
13568 |
if (n.nodeName == 'LI')
|
|
13569 |
return splitList(ed.selection, t.dom, n);
|
|
13570 |
|
|
13571 |
return TRUE;
|
|
13572 |
}
|
d9344f
|
13573 |
|
S |
13574 |
// If caption or absolute layers then always generate new blocks within
|
29da64
|
13575 |
if (sb && (sb.nodeName == 'CAPTION' || /absolute|relative|fixed/gi.test(dom.getStyle(sb, 'position', 1)))) {
|
d9344f
|
13576 |
bn = se.element;
|
S |
13577 |
sb = null;
|
|
13578 |
}
|
|
13579 |
|
|
13580 |
// If caption or absolute layers then always generate new blocks within
|
29da64
|
13581 |
if (eb && (eb.nodeName == 'CAPTION' || /absolute|relative|fixed/gi.test(dom.getStyle(sb, 'position', 1)))) {
|
d9344f
|
13582 |
bn = se.element;
|
S |
13583 |
eb = null;
|
|
13584 |
}
|
|
13585 |
|
|
13586 |
// Use P instead
|
29da64
|
13587 |
if (/(TD|TABLE|TH|CAPTION)/.test(bn) || (sb && bn == "DIV" && /left|right/gi.test(dom.getStyle(sb, 'float', 1)))) {
|
d9344f
|
13588 |
bn = se.element;
|
S |
13589 |
sb = eb = null;
|
|
13590 |
}
|
|
13591 |
|
|
13592 |
// Setup new before and after blocks
|
|
13593 |
bef = (sb && sb.nodeName == bn) ? sb.cloneNode(0) : ed.dom.create(bn);
|
|
13594 |
aft = (eb && eb.nodeName == bn) ? eb.cloneNode(0) : ed.dom.create(bn);
|
|
13595 |
|
|
13596 |
// Remove id from after clone
|
|
13597 |
aft.removeAttribute('id');
|
|
13598 |
|
|
13599 |
// Is header and cursor is at the end, then force paragraph under
|
58fb65
|
13600 |
if (/^(H[1-6])$/.test(bn) && isAtEnd(r, sb))
|
d9344f
|
13601 |
aft = ed.dom.create(se.element);
|
S |
13602 |
|
|
13603 |
// Find start chop node
|
|
13604 |
n = sc = sn;
|
|
13605 |
do {
|
|
13606 |
if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
|
|
13607 |
break;
|
|
13608 |
|
|
13609 |
sc = n;
|
|
13610 |
} while ((n = n.previousSibling ? n.previousSibling : n.parentNode));
|
|
13611 |
|
|
13612 |
// Find end chop node
|
|
13613 |
n = ec = en;
|
|
13614 |
do {
|
|
13615 |
if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
|
|
13616 |
break;
|
|
13617 |
|
|
13618 |
ec = n;
|
|
13619 |
} while ((n = n.nextSibling ? n.nextSibling : n.parentNode));
|
|
13620 |
|
|
13621 |
// Place first chop part into before block element
|
|
13622 |
if (sc.nodeName == bn)
|
|
13623 |
rb.setStart(sc, 0);
|
|
13624 |
else
|
|
13625 |
rb.setStartBefore(sc);
|
|
13626 |
|
|
13627 |
rb.setEnd(sn, so);
|
|
13628 |
bef.appendChild(rb.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari
|
|
13629 |
|
|
13630 |
// Place secnd chop part within new block element
|
|
13631 |
try {
|
|
13632 |
ra.setEndAfter(ec);
|
|
13633 |
} catch(ex) {
|
|
13634 |
//console.debug(s.focusNode, s.focusOffset);
|
|
13635 |
}
|
|
13636 |
|
|
13637 |
ra.setStart(en, eo);
|
|
13638 |
aft.appendChild(ra.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari
|
|
13639 |
|
|
13640 |
// Create range around everything
|
|
13641 |
r = d.createRange();
|
|
13642 |
if (!sc.previousSibling && sc.parentNode.nodeName == bn) {
|
|
13643 |
r.setStartBefore(sc.parentNode);
|
|
13644 |
} else {
|
|
13645 |
if (rb.startContainer.nodeName == bn && rb.startOffset == 0)
|
|
13646 |
r.setStartBefore(rb.startContainer);
|
|
13647 |
else
|
|
13648 |
r.setStart(rb.startContainer, rb.startOffset);
|
|
13649 |
}
|
|
13650 |
|
|
13651 |
if (!ec.nextSibling && ec.parentNode.nodeName == bn)
|
|
13652 |
r.setEndAfter(ec.parentNode);
|
|
13653 |
else
|
|
13654 |
r.setEnd(ra.endContainer, ra.endOffset);
|
|
13655 |
|
|
13656 |
// Delete and replace it with new block elements
|
|
13657 |
r.deleteContents();
|
|
13658 |
|
|
13659 |
if (isOpera)
|
|
13660 |
ed.getWin().scrollTo(0, vp.y);
|
|
13661 |
|
|
13662 |
// Never wrap blocks in blocks
|
|
13663 |
if (bef.firstChild && bef.firstChild.nodeName == bn)
|
|
13664 |
bef.innerHTML = bef.firstChild.innerHTML;
|
|
13665 |
|
|
13666 |
if (aft.firstChild && aft.firstChild.nodeName == bn)
|
|
13667 |
aft.innerHTML = aft.firstChild.innerHTML;
|
|
13668 |
|
|
13669 |
// Padd empty blocks
|
a9251b
|
13670 |
if (dom.isEmpty(bef))
|
d9344f
|
13671 |
bef.innerHTML = '<br />';
|
S |
13672 |
|
29da64
|
13673 |
function appendStyles(e, en) {
|
A |
13674 |
var nl = [], nn, n, i;
|
|
13675 |
|
|
13676 |
e.innerHTML = '';
|
|
13677 |
|
|
13678 |
// Make clones of style elements
|
|
13679 |
if (se.keep_styles) {
|
|
13680 |
n = en;
|
|
13681 |
do {
|
|
13682 |
// We only want style specific elements
|
|
13683 |
if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(n.nodeName)) {
|
69d05c
|
13684 |
nn = n.cloneNode(FALSE);
|
29da64
|
13685 |
dom.setAttrib(nn, 'id', ''); // Remove ID since it needs to be unique
|
A |
13686 |
nl.push(nn);
|
|
13687 |
}
|
|
13688 |
} while (n = n.parentNode);
|
|
13689 |
}
|
|
13690 |
|
|
13691 |
// Append style elements to aft
|
|
13692 |
if (nl.length > 0) {
|
|
13693 |
for (i = nl.length - 1, nn = e; i >= 0; i--)
|
|
13694 |
nn = nn.appendChild(nl[i]);
|
|
13695 |
|
|
13696 |
// Padd most inner style element
|
a9251b
|
13697 |
nl[0].innerHTML = isOpera ? '\u00a0' : '<br />'; // Extra space for Opera so that the caret can move there
|
29da64
|
13698 |
return nl[0]; // Move caret to most inner element
|
A |
13699 |
} else
|
a9251b
|
13700 |
e.innerHTML = isOpera ? '\u00a0' : '<br />'; // Extra space for Opera so that the caret can move there
|
29da64
|
13701 |
};
|
A |
13702 |
|
|
13703 |
// Fill empty afterblook with current style
|
a9251b
|
13704 |
if (dom.isEmpty(aft))
|
29da64
|
13705 |
car = appendStyles(aft, en);
|
d9344f
|
13706 |
|
18240a
|
13707 |
// Opera needs this one backwards for older versions
|
A |
13708 |
if (isOpera && parseFloat(opera.version()) < 9.5) {
|
d9344f
|
13709 |
r.insertNode(bef);
|
S |
13710 |
r.insertNode(aft);
|
|
13711 |
} else {
|
|
13712 |
r.insertNode(aft);
|
|
13713 |
r.insertNode(bef);
|
|
13714 |
}
|
|
13715 |
|
|
13716 |
// Normalize
|
|
13717 |
aft.normalize();
|
|
13718 |
bef.normalize();
|
|
13719 |
|
18240a
|
13720 |
function first(n) {
|
69d05c
|
13721 |
return d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, FALSE).nextNode() || n;
|
18240a
|
13722 |
};
|
A |
13723 |
|
d9344f
|
13724 |
// Move cursor and scroll into view
|
S |
13725 |
r = d.createRange();
|
29da64
|
13726 |
r.selectNodeContents(isGecko ? first(car || aft) : car || aft);
|
d9344f
|
13727 |
r.collapse(1);
|
S |
13728 |
s.removeAllRanges();
|
|
13729 |
s.addRange(r);
|
|
13730 |
|
|
13731 |
// 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
|
|
13732 |
y = ed.dom.getPos(aft).y;
|
a9251b
|
13733 |
//ch = aft.clientHeight;
|
d9344f
|
13734 |
|
S |
13735 |
// Is element within viewport
|
a9251b
|
13736 |
if (y < vp.y || y + 25 > vp.y + vp.h) {
|
29da64
|
13737 |
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
|
a9251b
|
13738 |
|
T |
13739 |
/*console.debug(
|
|
13740 |
'Element: y=' + y + ', h=' + ch + ', ' +
|
|
13741 |
'Viewport: y=' + vp.y + ", h=" + vp.h + ', bottom=' + (vp.y + vp.h)
|
|
13742 |
);*/
|
d9344f
|
13743 |
}
|
a9251b
|
13744 |
|
T |
13745 |
ed.undoManager.add();
|
d9344f
|
13746 |
|
69d05c
|
13747 |
return FALSE;
|
d9344f
|
13748 |
},
|
S |
13749 |
|
|
13750 |
backspaceDelete : function(e, bs) {
|
2011be
|
13751 |
var t = this, ed = t.editor, b = ed.getBody(), dom = ed.dom, n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn, walker;
|
A |
13752 |
|
|
13753 |
// Delete when caret is behind a element doesn't work correctly on Gecko see #3011651
|
|
13754 |
if (!bs && r.collapsed && sc.nodeType == 1 && r.startOffset == sc.childNodes.length) {
|
|
13755 |
walker = new tinymce.dom.TreeWalker(sc.lastChild, sc);
|
|
13756 |
|
|
13757 |
// Walk the dom backwards until we find a text node
|
|
13758 |
for (n = sc.lastChild; n; n = walker.prev()) {
|
|
13759 |
if (n.nodeType == 3) {
|
|
13760 |
r.setStart(n, n.nodeValue.length);
|
|
13761 |
r.collapse(true);
|
|
13762 |
se.setRng(r);
|
|
13763 |
return;
|
|
13764 |
}
|
|
13765 |
}
|
|
13766 |
}
|
d9344f
|
13767 |
|
S |
13768 |
// The caret sometimes gets stuck in Gecko if you delete empty paragraphs
|
|
13769 |
// This workaround removes the element by hand and moves the caret to the previous element
|
|
13770 |
if (sc && ed.dom.isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) {
|
|
13771 |
if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) {
|
|
13772 |
// Find previous block element
|
|
13773 |
n = sc;
|
|
13774 |
while ((n = n.previousSibling) && !ed.dom.isBlock(n)) ;
|
|
13775 |
|
|
13776 |
if (n) {
|
|
13777 |
if (sc != b.firstChild) {
|
|
13778 |
// Find last text node
|
69d05c
|
13779 |
w = ed.dom.doc.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, FALSE);
|
d9344f
|
13780 |
while (tn = w.nextNode())
|
S |
13781 |
n = tn;
|
|
13782 |
|
|
13783 |
// Place caret at the end of last text node
|
|
13784 |
r = ed.getDoc().createRange();
|
|
13785 |
r.setStart(n, n.nodeValue ? n.nodeValue.length : 0);
|
|
13786 |
r.setEnd(n, n.nodeValue ? n.nodeValue.length : 0);
|
|
13787 |
se.setRng(r);
|
|
13788 |
|
|
13789 |
// Remove the target container
|
|
13790 |
ed.dom.remove(sc);
|
|
13791 |
}
|
|
13792 |
|
|
13793 |
return Event.cancel(e);
|
|
13794 |
}
|
|
13795 |
}
|
|
13796 |
}
|
|
13797 |
}
|
|
13798 |
});
|
29da64
|
13799 |
})(tinymce);
|
69d05c
|
13800 |
|
29da64
|
13801 |
(function(tinymce) {
|
d9344f
|
13802 |
// Shorten names
|
S |
13803 |
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, extend = tinymce.extend;
|
|
13804 |
|
|
13805 |
tinymce.create('tinymce.ControlManager', {
|
|
13806 |
ControlManager : function(ed, s) {
|
|
13807 |
var t = this, i;
|
|
13808 |
|
|
13809 |
s = s || {};
|
|
13810 |
t.editor = ed;
|
|
13811 |
t.controls = {};
|
|
13812 |
t.onAdd = new tinymce.util.Dispatcher(t);
|
|
13813 |
t.onPostRender = new tinymce.util.Dispatcher(t);
|
|
13814 |
t.prefix = s.prefix || ed.id + '_';
|
|
13815 |
t._cls = {};
|
|
13816 |
|
|
13817 |
t.onPostRender.add(function() {
|
|
13818 |
each(t.controls, function(c) {
|
|
13819 |
c.postRender();
|
|
13820 |
});
|
|
13821 |
});
|
|
13822 |
},
|
|
13823 |
|
|
13824 |
get : function(id) {
|
|
13825 |
return this.controls[this.prefix + id] || this.controls[id];
|
|
13826 |
},
|
|
13827 |
|
|
13828 |
setActive : function(id, s) {
|
|
13829 |
var c = null;
|
|
13830 |
|
|
13831 |
if (c = this.get(id))
|
|
13832 |
c.setActive(s);
|
|
13833 |
|
|
13834 |
return c;
|
|
13835 |
},
|
|
13836 |
|
|
13837 |
setDisabled : function(id, s) {
|
|
13838 |
var c = null;
|
|
13839 |
|
|
13840 |
if (c = this.get(id))
|
|
13841 |
c.setDisabled(s);
|
|
13842 |
|
|
13843 |
return c;
|
|
13844 |
},
|
|
13845 |
|
|
13846 |
add : function(c) {
|
|
13847 |
var t = this;
|
|
13848 |
|
|
13849 |
if (c) {
|
|
13850 |
t.controls[c.id] = c;
|
|
13851 |
t.onAdd.dispatch(c, t);
|
|
13852 |
}
|
|
13853 |
|
|
13854 |
return c;
|
|
13855 |
},
|
|
13856 |
|
|
13857 |
createControl : function(n) {
|
|
13858 |
var c, t = this, ed = t.editor;
|
|
13859 |
|
|
13860 |
each(ed.plugins, function(p) {
|
|
13861 |
if (p.createControl) {
|
|
13862 |
c = p.createControl(n, t);
|
|
13863 |
|
|
13864 |
if (c)
|
|
13865 |
return false;
|
|
13866 |
}
|
|
13867 |
});
|
|
13868 |
|
|
13869 |
switch (n) {
|
|
13870 |
case "|":
|
|
13871 |
case "separator":
|
|
13872 |
return t.createSeparator();
|
|
13873 |
}
|
|
13874 |
|
|
13875 |
if (!c && ed.buttons && (c = ed.buttons[n]))
|
|
13876 |
return t.createButton(n, c);
|
|
13877 |
|
|
13878 |
return t.add(c);
|
|
13879 |
},
|
|
13880 |
|
|
13881 |
createDropMenu : function(id, s, cc) {
|
|
13882 |
var t = this, ed = t.editor, c, bm, v, cls;
|
|
13883 |
|
|
13884 |
s = extend({
|
|
13885 |
'class' : 'mceDropDown',
|
|
13886 |
constrain : ed.settings.constrain_menus
|
|
13887 |
}, s);
|
|
13888 |
|
|
13889 |
s['class'] = s['class'] + ' ' + ed.getParam('skin') + 'Skin';
|
|
13890 |
if (v = ed.getParam('skin_variant'))
|
|
13891 |
s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1);
|
|
13892 |
|
|
13893 |
id = t.prefix + id;
|
|
13894 |
cls = cc || t._cls.dropmenu || tinymce.ui.DropMenu;
|
|
13895 |
c = t.controls[id] = new cls(id, s);
|
|
13896 |
c.onAddItem.add(function(c, o) {
|
|
13897 |
var s = o.settings;
|
|
13898 |
|
|
13899 |
s.title = ed.getLang(s.title, s.title);
|
|
13900 |
|
|
13901 |
if (!s.onclick) {
|
|
13902 |
s.onclick = function(v) {
|
69d05c
|
13903 |
if (s.cmd)
|
A |
13904 |
ed.execCommand(s.cmd, s.ui || false, s.value);
|
d9344f
|
13905 |
};
|
S |
13906 |
}
|
|
13907 |
});
|
|
13908 |
|
|
13909 |
ed.onRemove.add(function() {
|
|
13910 |
c.destroy();
|
|
13911 |
});
|
|
13912 |
|
|
13913 |
// Fix for bug #1897785, #1898007
|
|
13914 |
if (tinymce.isIE) {
|
|
13915 |
c.onShowMenu.add(function() {
|
29da64
|
13916 |
// IE 8 needs focus in order to store away a range with the current collapsed caret location
|
A |
13917 |
ed.focus();
|
|
13918 |
|
18240a
|
13919 |
bm = ed.selection.getBookmark(1);
|
d9344f
|
13920 |
});
|
S |
13921 |
|
|
13922 |
c.onHideMenu.add(function() {
|
29da64
|
13923 |
if (bm) {
|
d9344f
|
13924 |
ed.selection.moveToBookmark(bm);
|
29da64
|
13925 |
bm = 0;
|
A |
13926 |
}
|
d9344f
|
13927 |
});
|
S |
13928 |
}
|
|
13929 |
|
|
13930 |
return t.add(c);
|
|
13931 |
},
|
|
13932 |
|
|
13933 |
createListBox : function(id, s, cc) {
|
|
13934 |
var t = this, ed = t.editor, cmd, c, cls;
|
|
13935 |
|
|
13936 |
if (t.get(id))
|
|
13937 |
return null;
|
|
13938 |
|
|
13939 |
s.title = ed.translate(s.title);
|
|
13940 |
s.scope = s.scope || ed;
|
|
13941 |
|
|
13942 |
if (!s.onselect) {
|
|
13943 |
s.onselect = function(v) {
|
|
13944 |
ed.execCommand(s.cmd, s.ui || false, v || s.value);
|
|
13945 |
};
|
|
13946 |
}
|
|
13947 |
|
|
13948 |
s = extend({
|
|
13949 |
title : s.title,
|
|
13950 |
'class' : 'mce_' + id,
|
|
13951 |
scope : s.scope,
|
|
13952 |
control_manager : t
|
|
13953 |
}, s);
|
|
13954 |
|
|
13955 |
id = t.prefix + id;
|
|
13956 |
|
|
13957 |
if (ed.settings.use_native_selects)
|
|
13958 |
c = new tinymce.ui.NativeListBox(id, s);
|
|
13959 |
else {
|
|
13960 |
cls = cc || t._cls.listbox || tinymce.ui.ListBox;
|
a9251b
|
13961 |
c = new cls(id, s, ed);
|
d9344f
|
13962 |
}
|
S |
13963 |
|
|
13964 |
t.controls[id] = c;
|
|
13965 |
|
|
13966 |
// Fix focus problem in Safari
|
|
13967 |
if (tinymce.isWebKit) {
|
|
13968 |
c.onPostRender.add(function(c, n) {
|
|
13969 |
// Store bookmark on mousedown
|
|
13970 |
Event.add(n, 'mousedown', function() {
|
58fb65
|
13971 |
ed.bookmark = ed.selection.getBookmark(1);
|
d9344f
|
13972 |
});
|
S |
13973 |
|
|
13974 |
// Restore on focus, since it might be lost
|
|
13975 |
Event.add(n, 'focus', function() {
|
|
13976 |
ed.selection.moveToBookmark(ed.bookmark);
|
|
13977 |
ed.bookmark = null;
|
|
13978 |
});
|
|
13979 |
});
|
|
13980 |
}
|
|
13981 |
|
|
13982 |
if (c.hideMenu)
|
|
13983 |
ed.onMouseDown.add(c.hideMenu, c);
|
|
13984 |
|
|
13985 |
return t.add(c);
|
|
13986 |
},
|
|
13987 |
|
|
13988 |
createButton : function(id, s, cc) {
|
|
13989 |
var t = this, ed = t.editor, o, c, cls;
|
|
13990 |
|
|
13991 |
if (t.get(id))
|
|
13992 |
return null;
|
|
13993 |
|
|
13994 |
s.title = ed.translate(s.title);
|
18240a
|
13995 |
s.label = ed.translate(s.label);
|
d9344f
|
13996 |
s.scope = s.scope || ed;
|
S |
13997 |
|
|
13998 |
if (!s.onclick && !s.menu_button) {
|
|
13999 |
s.onclick = function() {
|
|
14000 |
ed.execCommand(s.cmd, s.ui || false, s.value);
|
|
14001 |
};
|
|
14002 |
}
|
|
14003 |
|
|
14004 |
s = extend({
|
|
14005 |
title : s.title,
|
|
14006 |
'class' : 'mce_' + id,
|
|
14007 |
unavailable_prefix : ed.getLang('unavailable', ''),
|
|
14008 |
scope : s.scope,
|
|
14009 |
control_manager : t
|
|
14010 |
}, s);
|
|
14011 |
|
|
14012 |
id = t.prefix + id;
|
|
14013 |
|
|
14014 |
if (s.menu_button) {
|
|
14015 |
cls = cc || t._cls.menubutton || tinymce.ui.MenuButton;
|
a9251b
|
14016 |
c = new cls(id, s, ed);
|
d9344f
|
14017 |
ed.onMouseDown.add(c.hideMenu, c);
|
S |
14018 |
} else {
|
|
14019 |
cls = t._cls.button || tinymce.ui.Button;
|
|
14020 |
c = new cls(id, s);
|
|
14021 |
}
|
|
14022 |
|
|
14023 |
return t.add(c);
|
|
14024 |
},
|
|
14025 |
|
29da64
|
14026 |
createMenuButton : function(id, s, cc) {
|
d9344f
|
14027 |
s = s || {};
|
S |
14028 |
s.menu_button = 1;
|
|
14029 |
|
29da64
|
14030 |
return this.createButton(id, s, cc);
|
d9344f
|
14031 |
},
|
S |
14032 |
|
|
14033 |
createSplitButton : function(id, s, cc) {
|
|
14034 |
var t = this, ed = t.editor, cmd, c, cls;
|
|
14035 |
|
|
14036 |
if (t.get(id))
|
|
14037 |
return null;
|
|
14038 |
|
|
14039 |
s.title = ed.translate(s.title);
|
|
14040 |
s.scope = s.scope || ed;
|
|
14041 |
|
|
14042 |
if (!s.onclick) {
|
|
14043 |
s.onclick = function(v) {
|
|
14044 |
ed.execCommand(s.cmd, s.ui || false, v || s.value);
|
|
14045 |
};
|
|
14046 |
}
|
|
14047 |
|
|
14048 |
if (!s.onselect) {
|
|
14049 |
s.onselect = function(v) {
|
|
14050 |
ed.execCommand(s.cmd, s.ui || false, v || s.value);
|
|
14051 |
};
|
|
14052 |
}
|
|
14053 |
|
|
14054 |
s = extend({
|
|
14055 |
title : s.title,
|
|
14056 |
'class' : 'mce_' + id,
|
|
14057 |
scope : s.scope,
|
|
14058 |
control_manager : t
|
|
14059 |
}, s);
|
|
14060 |
|
|
14061 |
id = t.prefix + id;
|
|
14062 |
cls = cc || t._cls.splitbutton || tinymce.ui.SplitButton;
|
a9251b
|
14063 |
c = t.add(new cls(id, s, ed));
|
d9344f
|
14064 |
ed.onMouseDown.add(c.hideMenu, c);
|
S |
14065 |
|
|
14066 |
return c;
|
|
14067 |
},
|
|
14068 |
|
|
14069 |
createColorSplitButton : function(id, s, cc) {
|
18240a
|
14070 |
var t = this, ed = t.editor, cmd, c, cls, bm;
|
d9344f
|
14071 |
|
S |
14072 |
if (t.get(id))
|
|
14073 |
return null;
|
|
14074 |
|
|
14075 |
s.title = ed.translate(s.title);
|
|
14076 |
s.scope = s.scope || ed;
|
|
14077 |
|
|
14078 |
if (!s.onclick) {
|
|
14079 |
s.onclick = function(v) {
|
29da64
|
14080 |
if (tinymce.isIE)
|
A |
14081 |
bm = ed.selection.getBookmark(1);
|
58fb65
|
14082 |
|
d9344f
|
14083 |
ed.execCommand(s.cmd, s.ui || false, v || s.value);
|
S |
14084 |
};
|
|
14085 |
}
|
|
14086 |
|
|
14087 |
if (!s.onselect) {
|
|
14088 |
s.onselect = function(v) {
|
|
14089 |
ed.execCommand(s.cmd, s.ui || false, v || s.value);
|
|
14090 |
};
|
|
14091 |
}
|
|
14092 |
|
|
14093 |
s = extend({
|
|
14094 |
title : s.title,
|
|
14095 |
'class' : 'mce_' + id,
|
|
14096 |
'menu_class' : ed.getParam('skin') + 'Skin',
|
|
14097 |
scope : s.scope,
|
|
14098 |
more_colors_title : ed.getLang('more_colors')
|
|
14099 |
}, s);
|
|
14100 |
|
|
14101 |
id = t.prefix + id;
|
|
14102 |
cls = cc || t._cls.colorsplitbutton || tinymce.ui.ColorSplitButton;
|
a9251b
|
14103 |
c = new cls(id, s, ed);
|
d9344f
|
14104 |
ed.onMouseDown.add(c.hideMenu, c);
|
S |
14105 |
|
|
14106 |
// Remove the menu element when the editor is removed
|
|
14107 |
ed.onRemove.add(function() {
|
|
14108 |
c.destroy();
|
|
14109 |
});
|
18240a
|
14110 |
|
A |
14111 |
// Fix for bug #1897785, #1898007
|
|
14112 |
if (tinymce.isIE) {
|
58fb65
|
14113 |
c.onShowMenu.add(function() {
|
A |
14114 |
// IE 8 needs focus in order to store away a range with the current collapsed caret location
|
|
14115 |
ed.focus();
|
|
14116 |
bm = ed.selection.getBookmark(1);
|
|
14117 |
});
|
|
14118 |
|
18240a
|
14119 |
c.onHideMenu.add(function() {
|
A |
14120 |
if (bm) {
|
|
14121 |
ed.selection.moveToBookmark(bm);
|
|
14122 |
bm = 0;
|
|
14123 |
}
|
|
14124 |
});
|
|
14125 |
}
|
d9344f
|
14126 |
|
S |
14127 |
return t.add(c);
|
|
14128 |
},
|
|
14129 |
|
|
14130 |
createToolbar : function(id, s, cc) {
|
|
14131 |
var c, t = this, cls;
|
|
14132 |
|
|
14133 |
id = t.prefix + id;
|
|
14134 |
cls = cc || t._cls.toolbar || tinymce.ui.Toolbar;
|
a9251b
|
14135 |
c = new cls(id, s, t.editor);
|
d9344f
|
14136 |
|
S |
14137 |
if (t.get(id))
|
|
14138 |
return null;
|
|
14139 |
|
a9251b
|
14140 |
return t.add(c);
|
T |
14141 |
},
|
|
14142 |
|
|
14143 |
createToolbarGroup : function(id, s, cc) {
|
|
14144 |
var c, t = this, cls;
|
|
14145 |
id = t.prefix + id;
|
|
14146 |
cls = cc || this._cls.toolbarGroup || tinymce.ui.ToolbarGroup;
|
|
14147 |
c = new cls(id, s, t.editor);
|
|
14148 |
|
|
14149 |
if (t.get(id))
|
|
14150 |
return null;
|
|
14151 |
|
d9344f
|
14152 |
return t.add(c);
|
S |
14153 |
},
|
|
14154 |
|
|
14155 |
createSeparator : function(cc) {
|
|
14156 |
var cls = cc || this._cls.separator || tinymce.ui.Separator;
|
|
14157 |
|
|
14158 |
return new cls();
|
|
14159 |
},
|
|
14160 |
|
|
14161 |
setControlType : function(n, c) {
|
|
14162 |
return this._cls[n.toLowerCase()] = c;
|
|
14163 |
},
|
58fb65
|
14164 |
|
d9344f
|
14165 |
destroy : function() {
|
S |
14166 |
each(this.controls, function(c) {
|
|
14167 |
c.destroy();
|
|
14168 |
});
|
|
14169 |
|
|
14170 |
this.controls = null;
|
|
14171 |
}
|
58fb65
|
14172 |
});
|
29da64
|
14173 |
})(tinymce);
|
69d05c
|
14174 |
|
29da64
|
14175 |
(function(tinymce) {
|
d9344f
|
14176 |
var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isIE = tinymce.isIE, isOpera = tinymce.isOpera;
|
S |
14177 |
|
|
14178 |
tinymce.create('tinymce.WindowManager', {
|
|
14179 |
WindowManager : function(ed) {
|
|
14180 |
var t = this;
|
|
14181 |
|
|
14182 |
t.editor = ed;
|
|
14183 |
t.onOpen = new Dispatcher(t);
|
|
14184 |
t.onClose = new Dispatcher(t);
|
|
14185 |
t.params = {};
|
|
14186 |
t.features = {};
|
|
14187 |
},
|
|
14188 |
|
|
14189 |
open : function(s, p) {
|
|
14190 |
var t = this, f = '', x, y, mo = t.editor.settings.dialog_type == 'modal', w, sw, sh, vp = tinymce.DOM.getViewPort(), u;
|
|
14191 |
|
|
14192 |
// Default some options
|
|
14193 |
s = s || {};
|
|
14194 |
p = p || {};
|
|
14195 |
sw = isOpera ? vp.w : screen.width; // Opera uses windows inside the Opera window
|
|
14196 |
sh = isOpera ? vp.h : screen.height;
|
|
14197 |
s.name = s.name || 'mc_' + new Date().getTime();
|
|
14198 |
s.width = parseInt(s.width || 320);
|
|
14199 |
s.height = parseInt(s.height || 240);
|
|
14200 |
s.resizable = true;
|
|
14201 |
s.left = s.left || parseInt(sw / 2.0) - (s.width / 2.0);
|
|
14202 |
s.top = s.top || parseInt(sh / 2.0) - (s.height / 2.0);
|
|
14203 |
p.inline = false;
|
|
14204 |
p.mce_width = s.width;
|
|
14205 |
p.mce_height = s.height;
|
|
14206 |
p.mce_auto_focus = s.auto_focus;
|
|
14207 |
|
|
14208 |
if (mo) {
|
|
14209 |
if (isIE) {
|
|
14210 |
s.center = true;
|
|
14211 |
s.help = false;
|
|
14212 |
s.dialogWidth = s.width + 'px';
|
|
14213 |
s.dialogHeight = s.height + 'px';
|
|
14214 |
s.scroll = s.scrollbars || false;
|
18240a
|
14215 |
}
|
d9344f
|
14216 |
}
|
S |
14217 |
|
|
14218 |
// Build features string
|
|
14219 |
each(s, function(v, k) {
|
|
14220 |
if (tinymce.is(v, 'boolean'))
|
|
14221 |
v = v ? 'yes' : 'no';
|
|
14222 |
|
|
14223 |
if (!/^(name|url)$/.test(k)) {
|
|
14224 |
if (isIE && mo)
|
|
14225 |
f += (f ? ';' : '') + k + ':' + v;
|
|
14226 |
else
|
|
14227 |
f += (f ? ',' : '') + k + '=' + v;
|
|
14228 |
}
|
|
14229 |
});
|
|
14230 |
|
|
14231 |
t.features = s;
|
|
14232 |
t.params = p;
|
|
14233 |
t.onOpen.dispatch(t, s, p);
|
|
14234 |
|
|
14235 |
u = s.url || s.file;
|
18240a
|
14236 |
u = tinymce._addVer(u);
|
A |
14237 |
|
d9344f
|
14238 |
try {
|
S |
14239 |
if (isIE && mo) {
|
|
14240 |
w = 1;
|
18240a
|
14241 |
window.showModalDialog(u, window, f);
|
d9344f
|
14242 |
} else
|
S |
14243 |
w = window.open(u, s.name, f);
|
|
14244 |
} catch (ex) {
|
|
14245 |
// Ignore
|
|
14246 |
}
|
|
14247 |
|
|
14248 |
if (!w)
|
|
14249 |
alert(t.editor.getLang('popup_blocked'));
|
|
14250 |
},
|
|
14251 |
|
|
14252 |
close : function(w) {
|
|
14253 |
w.close();
|
|
14254 |
this.onClose.dispatch(this);
|
|
14255 |
},
|
|
14256 |
|
|
14257 |
createInstance : function(cl, a, b, c, d, e) {
|
|
14258 |
var f = tinymce.resolve(cl);
|
|
14259 |
|
|
14260 |
return new f(a, b, c, d, e);
|
|
14261 |
},
|
|
14262 |
|
29da64
|
14263 |
confirm : function(t, cb, s, w) {
|
A |
14264 |
w = w || window;
|
|
14265 |
|
|
14266 |
cb.call(s || this, w.confirm(this._decode(this.editor.getLang(t, t))));
|
d9344f
|
14267 |
},
|
S |
14268 |
|
29da64
|
14269 |
alert : function(tx, cb, s, w) {
|
d9344f
|
14270 |
var t = this;
|
29da64
|
14271 |
|
A |
14272 |
w = w || window;
|
|
14273 |
w.alert(t._decode(t.editor.getLang(tx, tx)));
|
d9344f
|
14274 |
|
S |
14275 |
if (cb)
|
|
14276 |
cb.call(s || t);
|
|
14277 |
},
|
|
14278 |
|
69d05c
|
14279 |
resizeBy : function(dw, dh, win) {
|
A |
14280 |
win.resizeBy(dw, dh);
|
|
14281 |
},
|
|
14282 |
|
d9344f
|
14283 |
// Internal functions
|
S |
14284 |
|
|
14285 |
_decode : function(s) {
|
|
14286 |
return tinymce.DOM.decode(s).replace(/\\n/g, '\n');
|
|
14287 |
}
|
58fb65
|
14288 |
});
|
69d05c
|
14289 |
}(tinymce));
|
A |
14290 |
(function(tinymce) {
|
|
14291 |
tinymce.Formatter = function(ed) {
|
|
14292 |
var formats = {},
|
|
14293 |
each = tinymce.each,
|
|
14294 |
dom = ed.dom,
|
|
14295 |
selection = ed.selection,
|
|
14296 |
TreeWalker = tinymce.dom.TreeWalker,
|
|
14297 |
rangeUtils = new tinymce.dom.RangeUtils(dom),
|
a9251b
|
14298 |
isValid = ed.schema.isValidChild,
|
69d05c
|
14299 |
isBlock = dom.isBlock,
|
A |
14300 |
forcedRootBlock = ed.settings.forced_root_block,
|
|
14301 |
nodeIndex = dom.nodeIndex,
|
|
14302 |
INVISIBLE_CHAR = '\uFEFF',
|
|
14303 |
MCE_ATTR_RE = /^(src|href|style)$/,
|
|
14304 |
FALSE = false,
|
|
14305 |
TRUE = true,
|
|
14306 |
undefined,
|
|
14307 |
pendingFormats = {apply : [], remove : []};
|
29da64
|
14308 |
|
799907
|
14309 |
function isArray(obj) {
|
A |
14310 |
return obj instanceof Array;
|
|
14311 |
};
|
|
14312 |
|
69d05c
|
14313 |
function getParents(node, selector) {
|
A |
14314 |
return dom.getParents(node, selector, dom.getRoot());
|
29da64
|
14315 |
};
|
A |
14316 |
|
69d05c
|
14317 |
function isCaretNode(node) {
|
A |
14318 |
return node.nodeType === 1 && (node.face === 'mceinline' || node.style.fontFamily === 'mceinline');
|
|
14319 |
};
|
29da64
|
14320 |
|
69d05c
|
14321 |
// Public functions
|
29da64
|
14322 |
|
69d05c
|
14323 |
function get(name) {
|
A |
14324 |
return name ? formats[name] : formats;
|
|
14325 |
};
|
29da64
|
14326 |
|
69d05c
|
14327 |
function register(name, format) {
|
A |
14328 |
if (name) {
|
|
14329 |
if (typeof(name) !== 'string') {
|
|
14330 |
each(name, function(format, name) {
|
|
14331 |
register(name, format);
|
|
14332 |
});
|
29da64
|
14333 |
} else {
|
69d05c
|
14334 |
// Force format into array and add it to internal collection
|
A |
14335 |
format = format.length ? format : [format];
|
29da64
|
14336 |
|
69d05c
|
14337 |
each(format, function(format) {
|
A |
14338 |
// Set deep to false by default on selector formats this to avoid removing
|
|
14339 |
// alignment on images inside paragraphs when alignment is changed on paragraphs
|
|
14340 |
if (format.deep === undefined)
|
|
14341 |
format.deep = !format.selector;
|
|
14342 |
|
|
14343 |
// Default to true
|
|
14344 |
if (format.split === undefined)
|
|
14345 |
format.split = !format.selector || format.inline;
|
|
14346 |
|
|
14347 |
// Default to true
|
|
14348 |
if (format.remove === undefined && format.selector && !format.inline)
|
|
14349 |
format.remove = 'none';
|
|
14350 |
|
|
14351 |
// Mark format as a mixed format inline + block level
|
|
14352 |
if (format.selector && format.inline) {
|
|
14353 |
format.mixed = true;
|
|
14354 |
format.block_expand = true;
|
|
14355 |
}
|
|
14356 |
|
|
14357 |
// Split classes if needed
|
|
14358 |
if (typeof(format.classes) === 'string')
|
|
14359 |
format.classes = format.classes.split(/\s+/);
|
|
14360 |
});
|
|
14361 |
|
|
14362 |
formats[name] = format;
|
|
14363 |
}
|
|
14364 |
}
|
|
14365 |
};
|
|
14366 |
|
a9251b
|
14367 |
var getTextDecoration = function(node) {
|
T |
14368 |
var decoration;
|
|
14369 |
|
|
14370 |
ed.dom.getParent(node, function(n) {
|
|
14371 |
decoration = ed.dom.getStyle(n, 'text-decoration');
|
|
14372 |
return decoration && decoration !== 'none';
|
|
14373 |
});
|
|
14374 |
|
|
14375 |
return decoration;
|
|
14376 |
};
|
|
14377 |
|
|
14378 |
var processUnderlineAndColor = function(node) {
|
|
14379 |
var textDecoration;
|
|
14380 |
if (node.nodeType === 1 && node.parentNode && node.parentNode.nodeType === 1) {
|
|
14381 |
textDecoration = getTextDecoration(node.parentNode);
|
|
14382 |
if (ed.dom.getStyle(node, 'color') && textDecoration) {
|
|
14383 |
ed.dom.setStyle(node, 'text-decoration', textDecoration);
|
|
14384 |
} else if (ed.dom.getStyle(node, 'textdecoration') === textDecoration) {
|
|
14385 |
ed.dom.setStyle(node, 'text-decoration', null);
|
|
14386 |
}
|
|
14387 |
}
|
|
14388 |
};
|
|
14389 |
|
69d05c
|
14390 |
function apply(name, vars, node) {
|
a9251b
|
14391 |
var formatList = get(name), format = formatList[0], bookmark, rng, i, isCollapsed = selection.isCollapsed();
|
69d05c
|
14392 |
|
A |
14393 |
function moveStart(rng) {
|
|
14394 |
var container = rng.startContainer,
|
|
14395 |
offset = rng.startOffset,
|
|
14396 |
walker, node;
|
|
14397 |
|
|
14398 |
// Move startContainer/startOffset in to a suitable node
|
|
14399 |
if (container.nodeType == 1 || container.nodeValue === "") {
|
2011be
|
14400 |
container = container.nodeType == 1 ? container.childNodes[offset] : container;
|
A |
14401 |
|
|
14402 |
// Might fail if the offset is behind the last element in it's container
|
|
14403 |
if (container) {
|
|
14404 |
walker = new TreeWalker(container, container.parentNode);
|
|
14405 |
for (node = walker.current(); node; node = walker.next()) {
|
|
14406 |
if (node.nodeType == 3 && !isWhiteSpaceNode(node)) {
|
|
14407 |
rng.setStart(node, 0);
|
|
14408 |
break;
|
|
14409 |
}
|
69d05c
|
14410 |
}
|
29da64
|
14411 |
}
|
A |
14412 |
}
|
|
14413 |
|
69d05c
|
14414 |
return rng;
|
A |
14415 |
};
|
29da64
|
14416 |
|
69d05c
|
14417 |
function setElementFormat(elm, fmt) {
|
A |
14418 |
fmt = fmt || format;
|
29da64
|
14419 |
|
69d05c
|
14420 |
if (elm) {
|
A |
14421 |
each(fmt.styles, function(value, name) {
|
|
14422 |
dom.setStyle(elm, name, replaceVars(value, vars));
|
|
14423 |
});
|
29da64
|
14424 |
|
69d05c
|
14425 |
each(fmt.attributes, function(value, name) {
|
A |
14426 |
dom.setAttrib(elm, name, replaceVars(value, vars));
|
|
14427 |
});
|
29da64
|
14428 |
|
69d05c
|
14429 |
each(fmt.classes, function(value) {
|
A |
14430 |
value = replaceVars(value, vars);
|
|
14431 |
|
|
14432 |
if (!dom.hasClass(elm, value))
|
|
14433 |
dom.addClass(elm, value);
|
|
14434 |
});
|
|
14435 |
}
|
|
14436 |
};
|
|
14437 |
|
|
14438 |
function applyRngStyle(rng) {
|
|
14439 |
var newWrappers = [], wrapName, wrapElm;
|
|
14440 |
|
|
14441 |
// Setup wrapper element
|
|
14442 |
wrapName = format.inline || format.block;
|
|
14443 |
wrapElm = dom.create(wrapName);
|
|
14444 |
setElementFormat(wrapElm);
|
|
14445 |
|
|
14446 |
rangeUtils.walk(rng, function(nodes) {
|
|
14447 |
var currentWrapElm;
|
|
14448 |
|
|
14449 |
function process(node) {
|
|
14450 |
var nodeName = node.nodeName.toLowerCase(), parentName = node.parentNode.nodeName.toLowerCase(), found;
|
|
14451 |
|
|
14452 |
// Stop wrapping on br elements
|
|
14453 |
if (isEq(nodeName, 'br')) {
|
|
14454 |
currentWrapElm = 0;
|
|
14455 |
|
|
14456 |
// Remove any br elements when we wrap things
|
|
14457 |
if (format.block)
|
|
14458 |
dom.remove(node);
|
|
14459 |
|
|
14460 |
return;
|
|
14461 |
}
|
|
14462 |
|
|
14463 |
// If node is wrapper type
|
|
14464 |
if (format.wrapper && matchNode(node, name, vars)) {
|
|
14465 |
currentWrapElm = 0;
|
|
14466 |
return;
|
|
14467 |
}
|
|
14468 |
|
|
14469 |
// Can we rename the block
|
|
14470 |
if (format.block && !format.wrapper && isTextBlock(nodeName)) {
|
|
14471 |
node = dom.rename(node, wrapName);
|
|
14472 |
setElementFormat(node);
|
|
14473 |
newWrappers.push(node);
|
|
14474 |
currentWrapElm = 0;
|
|
14475 |
return;
|
|
14476 |
}
|
|
14477 |
|
|
14478 |
// Handle selector patterns
|
|
14479 |
if (format.selector) {
|
|
14480 |
// Look for matching formats
|
|
14481 |
each(formatList, function(format) {
|
a9251b
|
14482 |
// Check collapsed state if it exists
|
T |
14483 |
if ('collapsed' in format && format.collapsed !== isCollapsed) {
|
|
14484 |
return;
|
|
14485 |
}
|
|
14486 |
|
69d05c
|
14487 |
if (dom.is(node, format.selector) && !isCaretNode(node)) {
|
A |
14488 |
setElementFormat(node, format);
|
|
14489 |
found = true;
|
|
14490 |
}
|
|
14491 |
});
|
|
14492 |
|
2011be
|
14493 |
// Continue processing if a selector match wasn't found and a inline element is defined
|
69d05c
|
14494 |
if (!format.inline || found) {
|
A |
14495 |
currentWrapElm = 0;
|
|
14496 |
return;
|
|
14497 |
}
|
|
14498 |
}
|
|
14499 |
|
|
14500 |
// Is it valid to wrap this item
|
a9251b
|
14501 |
if (isValid(wrapName, nodeName) && isValid(parentName, wrapName) &&
|
T |
14502 |
!(node.nodeType === 3 && node.nodeValue.length === 1 && node.nodeValue.charCodeAt(0) === 65279)) {
|
69d05c
|
14503 |
// Start wrapping
|
A |
14504 |
if (!currentWrapElm) {
|
|
14505 |
// Wrap the node
|
|
14506 |
currentWrapElm = wrapElm.cloneNode(FALSE);
|
|
14507 |
node.parentNode.insertBefore(currentWrapElm, node);
|
|
14508 |
newWrappers.push(currentWrapElm);
|
|
14509 |
}
|
|
14510 |
|
|
14511 |
currentWrapElm.appendChild(node);
|
|
14512 |
} else {
|
|
14513 |
// Start a new wrapper for possible children
|
|
14514 |
currentWrapElm = 0;
|
|
14515 |
|
|
14516 |
each(tinymce.grep(node.childNodes), process);
|
|
14517 |
|
|
14518 |
// End the last wrapper
|
|
14519 |
currentWrapElm = 0;
|
|
14520 |
}
|
|
14521 |
};
|
|
14522 |
|
|
14523 |
// Process siblings from range
|
|
14524 |
each(nodes, process);
|
|
14525 |
});
|
a9251b
|
14526 |
|
T |
14527 |
// Wrap links inside as well, for example color inside a link when the wrapper is around the link
|
|
14528 |
if (format.wrap_links === false) {
|
|
14529 |
each(newWrappers, function(node) {
|
|
14530 |
function process(node) {
|
|
14531 |
var i, currentWrapElm, children;
|
|
14532 |
|
|
14533 |
if (node.nodeName === 'A') {
|
|
14534 |
currentWrapElm = wrapElm.cloneNode(FALSE);
|
|
14535 |
newWrappers.push(currentWrapElm);
|
|
14536 |
|
|
14537 |
children = tinymce.grep(node.childNodes);
|
|
14538 |
for (i = 0; i < children.length; i++)
|
|
14539 |
currentWrapElm.appendChild(children[i]);
|
|
14540 |
|
|
14541 |
node.appendChild(currentWrapElm);
|
|
14542 |
}
|
|
14543 |
|
|
14544 |
each(tinymce.grep(node.childNodes), process);
|
|
14545 |
};
|
|
14546 |
|
|
14547 |
process(node);
|
|
14548 |
});
|
|
14549 |
}
|
69d05c
|
14550 |
|
A |
14551 |
// Cleanup
|
|
14552 |
each(newWrappers, function(node) {
|
|
14553 |
var childCount;
|
|
14554 |
|
|
14555 |
function getChildCount(node) {
|
|
14556 |
var count = 0;
|
|
14557 |
|
|
14558 |
each(node.childNodes, function(node) {
|
|
14559 |
if (!isWhiteSpaceNode(node) && !isBookmarkNode(node))
|
|
14560 |
count++;
|
|
14561 |
});
|
|
14562 |
|
|
14563 |
return count;
|
|
14564 |
};
|
|
14565 |
|
|
14566 |
function mergeStyles(node) {
|
|
14567 |
var child, clone;
|
|
14568 |
|
|
14569 |
each(node.childNodes, function(node) {
|
|
14570 |
if (node.nodeType == 1 && !isBookmarkNode(node) && !isCaretNode(node)) {
|
|
14571 |
child = node;
|
|
14572 |
return FALSE; // break loop
|
|
14573 |
}
|
|
14574 |
});
|
|
14575 |
|
|
14576 |
// If child was found and of the same type as the current node
|
|
14577 |
if (child && matchName(child, format)) {
|
|
14578 |
clone = child.cloneNode(FALSE);
|
|
14579 |
setElementFormat(clone);
|
|
14580 |
|
|
14581 |
dom.replace(clone, node, TRUE);
|
|
14582 |
dom.remove(child, 1);
|
|
14583 |
}
|
|
14584 |
|
|
14585 |
return clone || node;
|
|
14586 |
};
|
|
14587 |
|
|
14588 |
childCount = getChildCount(node);
|
|
14589 |
|
a9251b
|
14590 |
// Remove empty nodes but only if there is multiple wrappers and they are not block
|
T |
14591 |
// elements so never remove single <h1></h1> since that would remove the currrent empty block element where the caret is at
|
|
14592 |
if ((newWrappers.length > 1 || !isBlock(node)) && childCount === 0) {
|
69d05c
|
14593 |
dom.remove(node, 1);
|
A |
14594 |
return;
|
|
14595 |
}
|
|
14596 |
|
|
14597 |
if (format.inline || format.wrapper) {
|
|
14598 |
// Merges the current node with it's children of similar type to reduce the number of elements
|
|
14599 |
if (!format.exact && childCount === 1)
|
|
14600 |
node = mergeStyles(node);
|
|
14601 |
|
|
14602 |
// Remove/merge children
|
|
14603 |
each(formatList, function(format) {
|
|
14604 |
// Merge all children of similar type will move styles from child to parent
|
|
14605 |
// this: <span style="color:red"><b><span style="color:red; font-size:10px">text</span></b></span>
|
|
14606 |
// will become: <span style="color:red"><b><span style="font-size:10px">text</span></b></span>
|
|
14607 |
each(dom.select(format.inline, node), function(child) {
|
a9251b
|
14608 |
var parent;
|
T |
14609 |
|
|
14610 |
// When wrap_links is set to false we don't want
|
|
14611 |
// to remove the format on children within links
|
|
14612 |
if (format.wrap_links === false) {
|
|
14613 |
parent = child.parentNode;
|
|
14614 |
|
|
14615 |
do {
|
|
14616 |
if (parent.nodeName === 'A')
|
|
14617 |
return;
|
|
14618 |
} while (parent = parent.parentNode);
|
|
14619 |
}
|
|
14620 |
|
69d05c
|
14621 |
removeFormat(format, vars, child, format.exact ? child : null);
|
A |
14622 |
});
|
|
14623 |
});
|
|
14624 |
|
2011be
|
14625 |
// Remove child if direct parent is of same type
|
A |
14626 |
if (matchNode(node.parentNode, name, vars)) {
|
|
14627 |
dom.remove(node, 1);
|
|
14628 |
node = 0;
|
|
14629 |
return TRUE;
|
|
14630 |
}
|
|
14631 |
|
69d05c
|
14632 |
// Look for parent with similar style format
|
2011be
|
14633 |
if (format.merge_with_parents) {
|
A |
14634 |
dom.getParent(node.parentNode, function(parent) {
|
|
14635 |
if (matchNode(parent, name, vars)) {
|
|
14636 |
dom.remove(node, 1);
|
|
14637 |
node = 0;
|
|
14638 |
return TRUE;
|
|
14639 |
}
|
|
14640 |
});
|
|
14641 |
}
|
69d05c
|
14642 |
|
A |
14643 |
// Merge next and previous siblings if they are similar <b>text</b><b>text</b> becomes <b>texttext</b>
|
|
14644 |
if (node) {
|
|
14645 |
node = mergeSiblings(getNonWhiteSpaceSibling(node), node);
|
|
14646 |
node = mergeSiblings(node, getNonWhiteSpaceSibling(node, TRUE));
|
|
14647 |
}
|
|
14648 |
}
|
|
14649 |
});
|
|
14650 |
};
|
|
14651 |
|
|
14652 |
if (format) {
|
|
14653 |
if (node) {
|
|
14654 |
rng = dom.createRng();
|
|
14655 |
|
|
14656 |
rng.setStartBefore(node);
|
|
14657 |
rng.setEndAfter(node);
|
|
14658 |
|
2011be
|
14659 |
applyRngStyle(expandRng(rng, formatList));
|
69d05c
|
14660 |
} else {
|
a9251b
|
14661 |
if (!isCollapsed || !format.inline || dom.select('td.mceSelected,th.mceSelected').length) {
|
T |
14662 |
// Obtain selection node before selection is unselected by applyRngStyle()
|
|
14663 |
var curSelNode = ed.selection.getNode();
|
|
14664 |
|
69d05c
|
14665 |
// Apply formatting to selection
|
A |
14666 |
bookmark = selection.getBookmark();
|
|
14667 |
applyRngStyle(expandRng(selection.getRng(TRUE), formatList));
|
a9251b
|
14668 |
|
T |
14669 |
// Colored nodes should be underlined so that the color of the underline matches the text color.
|
|
14670 |
if (format.styles && (format.styles.color || format.styles.textDecoration)) {
|
|
14671 |
tinymce.walk(curSelNode, processUnderlineAndColor, 'childNodes');
|
|
14672 |
processUnderlineAndColor(curSelNode);
|
|
14673 |
}
|
69d05c
|
14674 |
|
A |
14675 |
selection.moveToBookmark(bookmark);
|
|
14676 |
selection.setRng(moveStart(selection.getRng(TRUE)));
|
|
14677 |
ed.nodeChanged();
|
|
14678 |
} else
|
|
14679 |
performCaretAction('apply', name, vars);
|
|
14680 |
}
|
29da64
|
14681 |
}
|
69d05c
|
14682 |
};
|
29da64
|
14683 |
|
69d05c
|
14684 |
function remove(name, vars, node) {
|
A |
14685 |
var formatList = get(name), format = formatList[0], bookmark, i, rng;
|
a9251b
|
14686 |
|
T |
14687 |
function moveStart(rng) {
|
|
14688 |
var container = rng.startContainer,
|
|
14689 |
offset = rng.startOffset,
|
|
14690 |
walker, node, nodes, tmpNode;
|
|
14691 |
|
|
14692 |
// Convert text node into index if possible
|
|
14693 |
if (container.nodeType == 3 && offset >= container.nodeValue.length - 1) {
|
|
14694 |
container = container.parentNode;
|
|
14695 |
offset = nodeIndex(container) + 1;
|
|
14696 |
}
|
|
14697 |
|
|
14698 |
// Move startContainer/startOffset in to a suitable node
|
|
14699 |
if (container.nodeType == 1) {
|
|
14700 |
nodes = container.childNodes;
|
|
14701 |
container = nodes[Math.min(offset, nodes.length - 1)];
|
|
14702 |
walker = new TreeWalker(container);
|
|
14703 |
|
|
14704 |
// If offset is at end of the parent node walk to the next one
|
|
14705 |
if (offset > nodes.length - 1)
|
|
14706 |
walker.next();
|
|
14707 |
|
|
14708 |
for (node = walker.current(); node; node = walker.next()) {
|
|
14709 |
if (node.nodeType == 3 && !isWhiteSpaceNode(node)) {
|
|
14710 |
// IE has a "neat" feature where it moves the start node into the closest element
|
|
14711 |
// we can avoid this by inserting an element before it and then remove it after we set the selection
|
|
14712 |
tmpNode = dom.create('a', null, INVISIBLE_CHAR);
|
|
14713 |
node.parentNode.insertBefore(tmpNode, node);
|
|
14714 |
|
|
14715 |
// Set selection and remove tmpNode
|
|
14716 |
rng.setStart(node, 0);
|
|
14717 |
selection.setRng(rng);
|
|
14718 |
dom.remove(tmpNode);
|
|
14719 |
|
|
14720 |
return;
|
|
14721 |
}
|
|
14722 |
}
|
|
14723 |
}
|
|
14724 |
};
|
29da64
|
14725 |
|
69d05c
|
14726 |
// Merges the styles for each node
|
A |
14727 |
function process(node) {
|
|
14728 |
var children, i, l;
|
29da64
|
14729 |
|
69d05c
|
14730 |
// Grab the children first since the nodelist might be changed
|
A |
14731 |
children = tinymce.grep(node.childNodes);
|
|
14732 |
|
|
14733 |
// Process current node
|
|
14734 |
for (i = 0, l = formatList.length; i < l; i++) {
|
|
14735 |
if (removeFormat(formatList[i], vars, node, node))
|
|
14736 |
break;
|
29da64
|
14737 |
}
|
A |
14738 |
|
69d05c
|
14739 |
// Process the children
|
A |
14740 |
if (format.deep) {
|
|
14741 |
for (i = 0, l = children.length; i < l; i++)
|
|
14742 |
process(children[i]);
|
|
14743 |
}
|
|
14744 |
};
|
|
14745 |
|
|
14746 |
function findFormatRoot(container) {
|
|
14747 |
var formatRoot;
|
|
14748 |
|
|
14749 |
// Find format root
|
|
14750 |
each(getParents(container.parentNode).reverse(), function(parent) {
|
|
14751 |
var format;
|
|
14752 |
|
|
14753 |
// Find format root element
|
|
14754 |
if (!formatRoot && parent.id != '_start' && parent.id != '_end') {
|
|
14755 |
// Is the node matching the format we are looking for
|
|
14756 |
format = matchNode(parent, name, vars);
|
|
14757 |
if (format && format.split !== false)
|
|
14758 |
formatRoot = parent;
|
|
14759 |
}
|
|
14760 |
});
|
|
14761 |
|
|
14762 |
return formatRoot;
|
|
14763 |
};
|
|
14764 |
|
|
14765 |
function wrapAndSplit(format_root, container, target, split) {
|
|
14766 |
var parent, clone, lastClone, firstClone, i, formatRootParent;
|
|
14767 |
|
|
14768 |
// Format root found then clone formats and split it
|
|
14769 |
if (format_root) {
|
|
14770 |
formatRootParent = format_root.parentNode;
|
|
14771 |
|
|
14772 |
for (parent = container.parentNode; parent && parent != formatRootParent; parent = parent.parentNode) {
|
|
14773 |
clone = parent.cloneNode(FALSE);
|
|
14774 |
|
|
14775 |
for (i = 0; i < formatList.length; i++) {
|
|
14776 |
if (removeFormat(formatList[i], vars, clone, clone)) {
|
|
14777 |
clone = 0;
|
|
14778 |
break;
|
|
14779 |
}
|
|
14780 |
}
|
|
14781 |
|
|
14782 |
// Build wrapper node
|
|
14783 |
if (clone) {
|
|
14784 |
if (lastClone)
|
|
14785 |
clone.appendChild(lastClone);
|
|
14786 |
|
|
14787 |
if (!firstClone)
|
|
14788 |
firstClone = clone;
|
|
14789 |
|
|
14790 |
lastClone = clone;
|
|
14791 |
}
|
|
14792 |
}
|
|
14793 |
|
|
14794 |
// Never split block elements if the format is mixed
|
|
14795 |
if (split && (!format.mixed || !isBlock(format_root)))
|
|
14796 |
container = dom.split(format_root, container);
|
|
14797 |
|
|
14798 |
// Wrap container in cloned formats
|
|
14799 |
if (lastClone) {
|
|
14800 |
target.parentNode.insertBefore(lastClone, target);
|
|
14801 |
firstClone.appendChild(target);
|
|
14802 |
}
|
|
14803 |
}
|
|
14804 |
|
|
14805 |
return container;
|
|
14806 |
};
|
|
14807 |
|
|
14808 |
function splitToFormatRoot(container) {
|
|
14809 |
return wrapAndSplit(findFormatRoot(container), container, container, true);
|
|
14810 |
};
|
|
14811 |
|
|
14812 |
function unwrap(start) {
|
|
14813 |
var node = dom.get(start ? '_start' : '_end'),
|
|
14814 |
out = node[start ? 'firstChild' : 'lastChild'];
|
|
14815 |
|
2011be
|
14816 |
// If the end is placed within the start the result will be removed
|
A |
14817 |
// So this checks if the out node is a bookmark node if it is it
|
|
14818 |
// checks for another more suitable node
|
|
14819 |
if (isBookmarkNode(out))
|
|
14820 |
out = out[start ? 'firstChild' : 'lastChild'];
|
|
14821 |
|
|
14822 |
dom.remove(node, true);
|
69d05c
|
14823 |
|
A |
14824 |
return out;
|
|
14825 |
};
|
|
14826 |
|
|
14827 |
function removeRngStyle(rng) {
|
|
14828 |
var startContainer, endContainer;
|
|
14829 |
|
|
14830 |
rng = expandRng(rng, formatList, TRUE);
|
|
14831 |
|
|
14832 |
if (format.split) {
|
|
14833 |
startContainer = getContainer(rng, TRUE);
|
|
14834 |
endContainer = getContainer(rng);
|
|
14835 |
|
|
14836 |
if (startContainer != endContainer) {
|
|
14837 |
// Wrap start/end nodes in span element since these might be cloned/moved
|
a9251b
|
14838 |
startContainer = wrap(startContainer, 'span', {id : '_start', 'data-mce-type' : 'bookmark'});
|
T |
14839 |
endContainer = wrap(endContainer, 'span', {id : '_end', 'data-mce-type' : 'bookmark'});
|
69d05c
|
14840 |
|
A |
14841 |
// Split start/end
|
|
14842 |
splitToFormatRoot(startContainer);
|
|
14843 |
splitToFormatRoot(endContainer);
|
|
14844 |
|
|
14845 |
// Unwrap start/end to get real elements again
|
|
14846 |
startContainer = unwrap(TRUE);
|
|
14847 |
endContainer = unwrap();
|
|
14848 |
} else
|
|
14849 |
startContainer = endContainer = splitToFormatRoot(startContainer);
|
|
14850 |
|
|
14851 |
// Update range positions since they might have changed after the split operations
|
|
14852 |
rng.startContainer = startContainer.parentNode;
|
|
14853 |
rng.startOffset = nodeIndex(startContainer);
|
|
14854 |
rng.endContainer = endContainer.parentNode;
|
|
14855 |
rng.endOffset = nodeIndex(endContainer) + 1;
|
|
14856 |
}
|
|
14857 |
|
|
14858 |
// Remove items between start/end
|
|
14859 |
rangeUtils.walk(rng, function(nodes) {
|
|
14860 |
each(nodes, function(node) {
|
|
14861 |
process(node);
|
a9251b
|
14862 |
|
T |
14863 |
// Remove parent span if it only contains text-decoration: underline, yet a parent node is also underlined.
|
|
14864 |
if (node.nodeType === 1 && ed.dom.getStyle(node, 'text-decoration') === 'underline' && node.parentNode && getTextDecoration(node.parentNode) === 'underline') {
|
|
14865 |
removeFormat({'deep': false, 'exact': true, 'inline': 'span', 'styles': {'textDecoration' : 'underline'}}, null, node);
|
|
14866 |
}
|
69d05c
|
14867 |
});
|
A |
14868 |
});
|
|
14869 |
};
|
|
14870 |
|
|
14871 |
// Handle node
|
|
14872 |
if (node) {
|
|
14873 |
rng = dom.createRng();
|
|
14874 |
rng.setStartBefore(node);
|
|
14875 |
rng.setEndAfter(node);
|
|
14876 |
removeRngStyle(rng);
|
29da64
|
14877 |
return;
|
A |
14878 |
}
|
|
14879 |
|
a9251b
|
14880 |
if (!selection.isCollapsed() || !format.inline || dom.select('td.mceSelected,th.mceSelected').length) {
|
69d05c
|
14881 |
bookmark = selection.getBookmark();
|
A |
14882 |
removeRngStyle(selection.getRng(TRUE));
|
|
14883 |
selection.moveToBookmark(bookmark);
|
a9251b
|
14884 |
|
T |
14885 |
// Check if start element still has formatting then we are at: "<b>text|</b>text" and need to move the start into the next text node
|
|
14886 |
if (match(name, vars, selection.getStart())) {
|
|
14887 |
moveStart(selection.getRng(true));
|
|
14888 |
}
|
|
14889 |
|
69d05c
|
14890 |
ed.nodeChanged();
|
A |
14891 |
} else
|
|
14892 |
performCaretAction('remove', name, vars);
|
|
14893 |
};
|
|
14894 |
|
|
14895 |
function toggle(name, vars, node) {
|
a9251b
|
14896 |
var fmt = get(name);
|
T |
14897 |
|
|
14898 |
if (match(name, vars, node) && (!('toggle' in fmt[0]) || fmt[0]['toggle']))
|
69d05c
|
14899 |
remove(name, vars, node);
|
A |
14900 |
else
|
|
14901 |
apply(name, vars, node);
|
|
14902 |
};
|
|
14903 |
|
2011be
|
14904 |
function matchNode(node, name, vars, similar) {
|
69d05c
|
14905 |
var formatList = get(name), format, i, classes;
|
A |
14906 |
|
|
14907 |
function matchItems(node, format, item_name) {
|
|
14908 |
var key, value, items = format[item_name], i;
|
|
14909 |
|
|
14910 |
// Check all items
|
|
14911 |
if (items) {
|
|
14912 |
// Non indexed object
|
|
14913 |
if (items.length === undefined) {
|
|
14914 |
for (key in items) {
|
|
14915 |
if (items.hasOwnProperty(key)) {
|
|
14916 |
if (item_name === 'attributes')
|
|
14917 |
value = dom.getAttrib(node, key);
|
|
14918 |
else
|
|
14919 |
value = getStyle(node, key);
|
|
14920 |
|
2011be
|
14921 |
if (similar && !value && !format.exact)
|
A |
14922 |
return;
|
|
14923 |
|
|
14924 |
if ((!similar || format.exact) && !isEq(value, replaceVars(items[key], vars)))
|
69d05c
|
14925 |
return;
|
A |
14926 |
}
|
|
14927 |
}
|
|
14928 |
} else {
|
|
14929 |
// Only one match needed for indexed arrays
|
|
14930 |
for (i = 0; i < items.length; i++) {
|
|
14931 |
if (item_name === 'attributes' ? dom.getAttrib(node, items[i]) : getStyle(node, items[i]))
|
|
14932 |
return format;
|
|
14933 |
}
|
|
14934 |
}
|
|
14935 |
}
|
|
14936 |
|
|
14937 |
return format;
|
|
14938 |
};
|
|
14939 |
|
|
14940 |
if (formatList && node) {
|
|
14941 |
// Check each format in list
|
|
14942 |
for (i = 0; i < formatList.length; i++) {
|
|
14943 |
format = formatList[i];
|
|
14944 |
|
|
14945 |
// Name name, attributes, styles and classes
|
|
14946 |
if (matchName(node, format) && matchItems(node, format, 'attributes') && matchItems(node, format, 'styles')) {
|
|
14947 |
// Match classes
|
|
14948 |
if (classes = format.classes) {
|
|
14949 |
for (i = 0; i < classes.length; i++) {
|
|
14950 |
if (!dom.hasClass(node, classes[i]))
|
|
14951 |
return;
|
|
14952 |
}
|
|
14953 |
}
|
|
14954 |
|
|
14955 |
return format;
|
|
14956 |
}
|
|
14957 |
}
|
|
14958 |
}
|
|
14959 |
};
|
|
14960 |
|
|
14961 |
function match(name, vars, node) {
|
|
14962 |
var startNode, i;
|
|
14963 |
|
|
14964 |
function matchParents(node) {
|
|
14965 |
// Find first node with similar format settings
|
|
14966 |
node = dom.getParent(node, function(node) {
|
2011be
|
14967 |
return !!matchNode(node, name, vars, true);
|
69d05c
|
14968 |
});
|
A |
14969 |
|
|
14970 |
// Do an exact check on the similar format element
|
|
14971 |
return matchNode(node, name, vars);
|
|
14972 |
};
|
|
14973 |
|
|
14974 |
// Check specified node
|
|
14975 |
if (node)
|
|
14976 |
return matchParents(node);
|
|
14977 |
|
|
14978 |
// Check pending formats
|
|
14979 |
if (selection.isCollapsed()) {
|
|
14980 |
for (i = pendingFormats.apply.length - 1; i >= 0; i--) {
|
|
14981 |
if (pendingFormats.apply[i].name == name)
|
|
14982 |
return true;
|
|
14983 |
}
|
|
14984 |
|
|
14985 |
for (i = pendingFormats.remove.length - 1; i >= 0; i--) {
|
|
14986 |
if (pendingFormats.remove[i].name == name)
|
|
14987 |
return false;
|
|
14988 |
}
|
|
14989 |
|
|
14990 |
return matchParents(selection.getNode());
|
|
14991 |
}
|
|
14992 |
|
|
14993 |
// Check selected node
|
|
14994 |
node = selection.getNode();
|
|
14995 |
if (matchParents(node))
|
|
14996 |
return TRUE;
|
|
14997 |
|
|
14998 |
// Check start node if it's different
|
|
14999 |
startNode = selection.getStart();
|
|
15000 |
if (startNode != node) {
|
|
15001 |
if (matchParents(startNode))
|
|
15002 |
return TRUE;
|
|
15003 |
}
|
|
15004 |
|
|
15005 |
return FALSE;
|
|
15006 |
};
|
|
15007 |
|
799907
|
15008 |
function matchAll(names, vars) {
|
A |
15009 |
var startElement, matchedFormatNames = [], checkedMap = {}, i, ni, name;
|
|
15010 |
|
|
15011 |
// If the selection is collapsed then check pending formats
|
|
15012 |
if (selection.isCollapsed()) {
|
|
15013 |
for (ni = 0; ni < names.length; ni++) {
|
|
15014 |
// If the name is to be removed, then stop it from being added
|
|
15015 |
for (i = pendingFormats.remove.length - 1; i >= 0; i--) {
|
|
15016 |
name = names[ni];
|
|
15017 |
|
|
15018 |
if (pendingFormats.remove[i].name == name) {
|
|
15019 |
checkedMap[name] = true;
|
|
15020 |
break;
|
|
15021 |
}
|
|
15022 |
}
|
|
15023 |
}
|
|
15024 |
|
|
15025 |
// If the format is to be applied
|
|
15026 |
for (i = pendingFormats.apply.length - 1; i >= 0; i--) {
|
|
15027 |
for (ni = 0; ni < names.length; ni++) {
|
|
15028 |
name = names[ni];
|
|
15029 |
|
|
15030 |
if (!checkedMap[name] && pendingFormats.apply[i].name == name) {
|
|
15031 |
checkedMap[name] = true;
|
|
15032 |
matchedFormatNames.push(name);
|
|
15033 |
}
|
|
15034 |
}
|
|
15035 |
}
|
|
15036 |
}
|
|
15037 |
|
|
15038 |
// Check start of selection for formats
|
|
15039 |
startElement = selection.getStart();
|
|
15040 |
dom.getParent(startElement, function(node) {
|
|
15041 |
var i, name;
|
|
15042 |
|
|
15043 |
for (i = 0; i < names.length; i++) {
|
|
15044 |
name = names[i];
|
|
15045 |
|
|
15046 |
if (!checkedMap[name] && matchNode(node, name, vars)) {
|
|
15047 |
checkedMap[name] = true;
|
|
15048 |
matchedFormatNames.push(name);
|
|
15049 |
}
|
|
15050 |
}
|
|
15051 |
});
|
|
15052 |
|
|
15053 |
return matchedFormatNames;
|
|
15054 |
};
|
|
15055 |
|
69d05c
|
15056 |
function canApply(name) {
|
A |
15057 |
var formatList = get(name), startNode, parents, i, x, selector;
|
|
15058 |
|
|
15059 |
if (formatList) {
|
|
15060 |
startNode = selection.getStart();
|
|
15061 |
parents = getParents(startNode);
|
|
15062 |
|
|
15063 |
for (x = formatList.length - 1; x >= 0; x--) {
|
|
15064 |
selector = formatList[x].selector;
|
|
15065 |
|
|
15066 |
// Format is not selector based, then always return TRUE
|
|
15067 |
if (!selector)
|
|
15068 |
return TRUE;
|
|
15069 |
|
|
15070 |
for (i = parents.length - 1; i >= 0; i--) {
|
|
15071 |
if (dom.is(parents[i], selector))
|
|
15072 |
return TRUE;
|
|
15073 |
}
|
|
15074 |
}
|
|
15075 |
}
|
|
15076 |
|
|
15077 |
return FALSE;
|
|
15078 |
};
|
|
15079 |
|
|
15080 |
// Expose to public
|
|
15081 |
tinymce.extend(this, {
|
|
15082 |
get : get,
|
|
15083 |
register : register,
|
|
15084 |
apply : apply,
|
|
15085 |
remove : remove,
|
|
15086 |
toggle : toggle,
|
|
15087 |
match : match,
|
799907
|
15088 |
matchAll : matchAll,
|
69d05c
|
15089 |
matchNode : matchNode,
|
A |
15090 |
canApply : canApply
|
29da64
|
15091 |
});
|
A |
15092 |
|
69d05c
|
15093 |
// Private functions
|
A |
15094 |
|
|
15095 |
function matchName(node, format) {
|
|
15096 |
// Check for inline match
|
|
15097 |
if (isEq(node, format.inline))
|
|
15098 |
return TRUE;
|
|
15099 |
|
|
15100 |
// Check for block match
|
|
15101 |
if (isEq(node, format.block))
|
|
15102 |
return TRUE;
|
|
15103 |
|
|
15104 |
// Check for selector match
|
|
15105 |
if (format.selector)
|
|
15106 |
return dom.is(node, format.selector);
|
|
15107 |
};
|
|
15108 |
|
|
15109 |
function isEq(str1, str2) {
|
|
15110 |
str1 = str1 || '';
|
|
15111 |
str2 = str2 || '';
|
|
15112 |
|
799907
|
15113 |
str1 = '' + (str1.nodeName || str1);
|
A |
15114 |
str2 = '' + (str2.nodeName || str2);
|
69d05c
|
15115 |
|
A |
15116 |
return str1.toLowerCase() == str2.toLowerCase();
|
|
15117 |
};
|
|
15118 |
|
|
15119 |
function getStyle(node, name) {
|
|
15120 |
var styleVal = dom.getStyle(node, name);
|
|
15121 |
|
|
15122 |
// Force the format to hex
|
|
15123 |
if (name == 'color' || name == 'backgroundColor')
|
|
15124 |
styleVal = dom.toHex(styleVal);
|
|
15125 |
|
|
15126 |
// Opera will return bold as 700
|
|
15127 |
if (name == 'fontWeight' && styleVal == 700)
|
|
15128 |
styleVal = 'bold';
|
|
15129 |
|
|
15130 |
return '' + styleVal;
|
|
15131 |
};
|
|
15132 |
|
|
15133 |
function replaceVars(value, vars) {
|
|
15134 |
if (typeof(value) != "string")
|
|
15135 |
value = value(vars);
|
|
15136 |
else if (vars) {
|
|
15137 |
value = value.replace(/%(\w+)/g, function(str, name) {
|
|
15138 |
return vars[name] || str;
|
|
15139 |
});
|
29da64
|
15140 |
}
|
A |
15141 |
|
69d05c
|
15142 |
return value;
|
A |
15143 |
};
|
29da64
|
15144 |
|
69d05c
|
15145 |
function isWhiteSpaceNode(node) {
|
2011be
|
15146 |
return node && node.nodeType === 3 && /^([\s\r\n]+|)$/.test(node.nodeValue);
|
69d05c
|
15147 |
};
|
A |
15148 |
|
|
15149 |
function wrap(node, name, attrs) {
|
|
15150 |
var wrapper = dom.create(name, attrs);
|
|
15151 |
|
|
15152 |
node.parentNode.insertBefore(wrapper, node);
|
|
15153 |
wrapper.appendChild(node);
|
|
15154 |
|
|
15155 |
return wrapper;
|
|
15156 |
};
|
|
15157 |
|
|
15158 |
function expandRng(rng, format, remove) {
|
|
15159 |
var startContainer = rng.startContainer,
|
|
15160 |
startOffset = rng.startOffset,
|
|
15161 |
endContainer = rng.endContainer,
|
a9251b
|
15162 |
endOffset = rng.endOffset, sibling, lastIdx, leaf;
|
69d05c
|
15163 |
|
A |
15164 |
// This function walks up the tree if there is no siblings before/after the node
|
|
15165 |
function findParentContainer(container, child_name, sibling_name, root) {
|
|
15166 |
var parent, child;
|
|
15167 |
|
|
15168 |
root = root || dom.getRoot();
|
|
15169 |
|
|
15170 |
for (;;) {
|
|
15171 |
// Check if we can move up are we at root level or body level
|
|
15172 |
parent = container.parentNode;
|
|
15173 |
|
|
15174 |
// Stop expanding on block elements or root depending on format
|
|
15175 |
if (parent == root || (!format[0].block_expand && isBlock(parent)))
|
|
15176 |
return container;
|
|
15177 |
|
|
15178 |
for (sibling = parent[child_name]; sibling && sibling != container; sibling = sibling[sibling_name]) {
|
|
15179 |
if (sibling.nodeType == 1 && !isBookmarkNode(sibling))
|
|
15180 |
return container;
|
|
15181 |
|
|
15182 |
if (sibling.nodeType == 3 && !isWhiteSpaceNode(sibling))
|
|
15183 |
return container;
|
|
15184 |
}
|
|
15185 |
|
|
15186 |
container = container.parentNode;
|
|
15187 |
}
|
|
15188 |
|
|
15189 |
return container;
|
|
15190 |
};
|
|
15191 |
|
a9251b
|
15192 |
// This function walks down the tree to find the leaf at the selection.
|
T |
15193 |
// The offset is also returned as if node initially a leaf, the offset may be in the middle of the text node.
|
|
15194 |
function findLeaf(node, offset) {
|
|
15195 |
if (offset === undefined)
|
|
15196 |
offset = node.nodeType === 3 ? node.length : node.childNodes.length;
|
|
15197 |
while (node && node.hasChildNodes()) {
|
|
15198 |
node = node.childNodes[offset];
|
|
15199 |
if (node)
|
|
15200 |
offset = node.nodeType === 3 ? node.length : node.childNodes.length;
|
|
15201 |
}
|
|
15202 |
return { node: node, offset: offset };
|
|
15203 |
}
|
|
15204 |
|
69d05c
|
15205 |
// If index based start position then resolve it
|
A |
15206 |
if (startContainer.nodeType == 1 && startContainer.hasChildNodes()) {
|
|
15207 |
lastIdx = startContainer.childNodes.length - 1;
|
|
15208 |
startContainer = startContainer.childNodes[startOffset > lastIdx ? lastIdx : startOffset];
|
|
15209 |
|
|
15210 |
if (startContainer.nodeType == 3)
|
|
15211 |
startOffset = 0;
|
|
15212 |
}
|
|
15213 |
|
|
15214 |
// If index based end position then resolve it
|
|
15215 |
if (endContainer.nodeType == 1 && endContainer.hasChildNodes()) {
|
|
15216 |
lastIdx = endContainer.childNodes.length - 1;
|
|
15217 |
endContainer = endContainer.childNodes[endOffset > lastIdx ? lastIdx : endOffset - 1];
|
|
15218 |
|
|
15219 |
if (endContainer.nodeType == 3)
|
|
15220 |
endOffset = endContainer.nodeValue.length;
|
|
15221 |
}
|
|
15222 |
|
|
15223 |
// Exclude bookmark nodes if possible
|
|
15224 |
if (isBookmarkNode(startContainer.parentNode))
|
|
15225 |
startContainer = startContainer.parentNode;
|
|
15226 |
|
|
15227 |
if (isBookmarkNode(startContainer))
|
|
15228 |
startContainer = startContainer.nextSibling || startContainer;
|
|
15229 |
|
a9251b
|
15230 |
if (isBookmarkNode(endContainer.parentNode)) {
|
T |
15231 |
endOffset = dom.nodeIndex(endContainer);
|
69d05c
|
15232 |
endContainer = endContainer.parentNode;
|
a9251b
|
15233 |
}
|
69d05c
|
15234 |
|
a9251b
|
15235 |
if (isBookmarkNode(endContainer) && endContainer.previousSibling) {
|
T |
15236 |
endContainer = endContainer.previousSibling;
|
|
15237 |
endOffset = endContainer.length;
|
|
15238 |
}
|
69d05c
|
15239 |
|
a9251b
|
15240 |
if (format[0].inline) {
|
T |
15241 |
// Avoid applying formatting to a trailing space.
|
|
15242 |
leaf = findLeaf(endContainer, endOffset);
|
|
15243 |
if (leaf.node) {
|
|
15244 |
while (leaf.node && leaf.offset === 0 && leaf.node.previousSibling)
|
|
15245 |
leaf = findLeaf(leaf.node.previousSibling);
|
|
15246 |
|
|
15247 |
if (leaf.node && leaf.offset > 0 && leaf.node.nodeType === 3 &&
|
|
15248 |
leaf.node.nodeValue.charAt(leaf.offset - 1) === ' ') {
|
|
15249 |
|
|
15250 |
if (leaf.offset > 1) {
|
|
15251 |
endContainer = leaf.node;
|
|
15252 |
endContainer.splitText(leaf.offset - 1);
|
|
15253 |
} else if (leaf.node.previousSibling) {
|
|
15254 |
endContainer = leaf.node.previousSibling;
|
|
15255 |
}
|
|
15256 |
}
|
|
15257 |
}
|
|
15258 |
}
|
|
15259 |
|
69d05c
|
15260 |
// Move start/end point up the tree if the leaves are sharp and if we are in different containers
|
A |
15261 |
// Example * becomes !: !<p><b><i>*text</i><i>text*</i></b></p>!
|
|
15262 |
// This will reduce the number of wrapper elements that needs to be created
|
|
15263 |
// Move start point up the tree
|
|
15264 |
if (format[0].inline || format[0].block_expand) {
|
|
15265 |
startContainer = findParentContainer(startContainer, 'firstChild', 'nextSibling');
|
|
15266 |
endContainer = findParentContainer(endContainer, 'lastChild', 'previousSibling');
|
|
15267 |
}
|
|
15268 |
|
|
15269 |
// Expand start/end container to matching selector
|
|
15270 |
if (format[0].selector && format[0].expand !== FALSE && !format[0].inline) {
|
|
15271 |
function findSelectorEndPoint(container, sibling_name) {
|
a9251b
|
15272 |
var parents, i, y, curFormat;
|
69d05c
|
15273 |
|
A |
15274 |
if (container.nodeType == 3 && container.nodeValue.length == 0 && container[sibling_name])
|
|
15275 |
container = container[sibling_name];
|
|
15276 |
|
|
15277 |
parents = getParents(container);
|
|
15278 |
for (i = 0; i < parents.length; i++) {
|
|
15279 |
for (y = 0; y < format.length; y++) {
|
a9251b
|
15280 |
curFormat = format[y];
|
T |
15281 |
|
|
15282 |
// If collapsed state is set then skip formats that doesn't match that
|
|
15283 |
if ("collapsed" in curFormat && curFormat.collapsed !== rng.collapsed)
|
|
15284 |
continue;
|
|
15285 |
|
|
15286 |
if (dom.is(parents[i], curFormat.selector))
|
69d05c
|
15287 |
return parents[i];
|
A |
15288 |
}
|
|
15289 |
}
|
|
15290 |
|
|
15291 |
return container;
|
|
15292 |
};
|
|
15293 |
|
|
15294 |
// Find new startContainer/endContainer if there is better one
|
|
15295 |
startContainer = findSelectorEndPoint(startContainer, 'previousSibling');
|
|
15296 |
endContainer = findSelectorEndPoint(endContainer, 'nextSibling');
|
|
15297 |
}
|
|
15298 |
|
|
15299 |
// Expand start/end container to matching block element or text node
|
|
15300 |
if (format[0].block || format[0].selector) {
|
|
15301 |
function findBlockEndPoint(container, sibling_name, sibling_name2) {
|
|
15302 |
var node;
|
|
15303 |
|
|
15304 |
// Expand to block of similar type
|
|
15305 |
if (!format[0].wrapper)
|
|
15306 |
node = dom.getParent(container, format[0].block);
|
|
15307 |
|
|
15308 |
// Expand to first wrappable block element or any block element
|
|
15309 |
if (!node)
|
|
15310 |
node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, isBlock);
|
|
15311 |
|
|
15312 |
// Exclude inner lists from wrapping
|
|
15313 |
if (node && format[0].wrapper)
|
|
15314 |
node = getParents(node, 'ul,ol').reverse()[0] || node;
|
|
15315 |
|
|
15316 |
// Didn't find a block element look for first/last wrappable element
|
|
15317 |
if (!node) {
|
|
15318 |
node = container;
|
|
15319 |
|
|
15320 |
while (node[sibling_name] && !isBlock(node[sibling_name])) {
|
|
15321 |
node = node[sibling_name];
|
|
15322 |
|
|
15323 |
// Break on BR but include it will be removed later on
|
|
15324 |
// we can't remove it now since we need to check if it can be wrapped
|
|
15325 |
if (isEq(node, 'br'))
|
|
15326 |
break;
|
|
15327 |
}
|
|
15328 |
}
|
|
15329 |
|
|
15330 |
return node || container;
|
|
15331 |
};
|
|
15332 |
|
|
15333 |
// Find new startContainer/endContainer if there is better one
|
|
15334 |
startContainer = findBlockEndPoint(startContainer, 'previousSibling');
|
|
15335 |
endContainer = findBlockEndPoint(endContainer, 'nextSibling');
|
|
15336 |
|
|
15337 |
// Non block element then try to expand up the leaf
|
|
15338 |
if (format[0].block) {
|
|
15339 |
if (!isBlock(startContainer))
|
|
15340 |
startContainer = findParentContainer(startContainer, 'firstChild', 'nextSibling');
|
|
15341 |
|
|
15342 |
if (!isBlock(endContainer))
|
|
15343 |
endContainer = findParentContainer(endContainer, 'lastChild', 'previousSibling');
|
|
15344 |
}
|
|
15345 |
}
|
|
15346 |
|
|
15347 |
// Setup index for startContainer
|
|
15348 |
if (startContainer.nodeType == 1) {
|
|
15349 |
startOffset = nodeIndex(startContainer);
|
|
15350 |
startContainer = startContainer.parentNode;
|
|
15351 |
}
|
|
15352 |
|
|
15353 |
// Setup index for endContainer
|
|
15354 |
if (endContainer.nodeType == 1) {
|
|
15355 |
endOffset = nodeIndex(endContainer) + 1;
|
|
15356 |
endContainer = endContainer.parentNode;
|
|
15357 |
}
|
|
15358 |
|
|
15359 |
// Return new range like object
|
|
15360 |
return {
|
|
15361 |
startContainer : startContainer,
|
|
15362 |
startOffset : startOffset,
|
|
15363 |
endContainer : endContainer,
|
|
15364 |
endOffset : endOffset
|
|
15365 |
};
|
|
15366 |
}
|
|
15367 |
|
|
15368 |
function removeFormat(format, vars, node, compare_node) {
|
|
15369 |
var i, attrs, stylesModified;
|
|
15370 |
|
|
15371 |
// Check if node matches format
|
|
15372 |
if (!matchName(node, format))
|
|
15373 |
return FALSE;
|
|
15374 |
|
|
15375 |
// Should we compare with format attribs and styles
|
|
15376 |
if (format.remove != 'all') {
|
|
15377 |
// Remove styles
|
|
15378 |
each(format.styles, function(value, name) {
|
|
15379 |
value = replaceVars(value, vars);
|
|
15380 |
|
|
15381 |
// Indexed array
|
|
15382 |
if (typeof(name) === 'number') {
|
|
15383 |
name = value;
|
|
15384 |
compare_node = 0;
|
|
15385 |
}
|
|
15386 |
|
|
15387 |
if (!compare_node || isEq(getStyle(compare_node, name), value))
|
|
15388 |
dom.setStyle(node, name, '');
|
|
15389 |
|
|
15390 |
stylesModified = 1;
|
|
15391 |
});
|
|
15392 |
|
|
15393 |
// Remove style attribute if it's empty
|
|
15394 |
if (stylesModified && dom.getAttrib(node, 'style') == '') {
|
|
15395 |
node.removeAttribute('style');
|
a9251b
|
15396 |
node.removeAttribute('data-mce-style');
|
69d05c
|
15397 |
}
|
A |
15398 |
|
|
15399 |
// Remove attributes
|
|
15400 |
each(format.attributes, function(value, name) {
|
|
15401 |
var valueOut;
|
|
15402 |
|
|
15403 |
value = replaceVars(value, vars);
|
|
15404 |
|
|
15405 |
// Indexed array
|
|
15406 |
if (typeof(name) === 'number') {
|
|
15407 |
name = value;
|
|
15408 |
compare_node = 0;
|
|
15409 |
}
|
|
15410 |
|
|
15411 |
if (!compare_node || isEq(dom.getAttrib(compare_node, name), value)) {
|
|
15412 |
// Keep internal classes
|
|
15413 |
if (name == 'class') {
|
|
15414 |
value = dom.getAttrib(node, name);
|
|
15415 |
if (value) {
|
|
15416 |
// Build new class value where everything is removed except the internal prefixed classes
|
|
15417 |
valueOut = '';
|
|
15418 |
each(value.split(/\s+/), function(cls) {
|
|
15419 |
if (/mce\w+/.test(cls))
|
|
15420 |
valueOut += (valueOut ? ' ' : '') + cls;
|
|
15421 |
});
|
|
15422 |
|
|
15423 |
// We got some internal classes left
|
|
15424 |
if (valueOut) {
|
|
15425 |
dom.setAttrib(node, name, valueOut);
|
|
15426 |
return;
|
|
15427 |
}
|
|
15428 |
}
|
|
15429 |
}
|
|
15430 |
|
|
15431 |
// IE6 has a bug where the attribute doesn't get removed correctly
|
|
15432 |
if (name == "class")
|
|
15433 |
node.removeAttribute('className');
|
|
15434 |
|
|
15435 |
// Remove mce prefixed attributes
|
|
15436 |
if (MCE_ATTR_RE.test(name))
|
a9251b
|
15437 |
node.removeAttribute('data-mce-' + name);
|
69d05c
|
15438 |
|
A |
15439 |
node.removeAttribute(name);
|
|
15440 |
}
|
|
15441 |
});
|
|
15442 |
|
|
15443 |
// Remove classes
|
|
15444 |
each(format.classes, function(value) {
|
|
15445 |
value = replaceVars(value, vars);
|
|
15446 |
|
|
15447 |
if (!compare_node || dom.hasClass(compare_node, value))
|
|
15448 |
dom.removeClass(node, value);
|
|
15449 |
});
|
|
15450 |
|
|
15451 |
// Check for non internal attributes
|
|
15452 |
attrs = dom.getAttribs(node);
|
|
15453 |
for (i = 0; i < attrs.length; i++) {
|
|
15454 |
if (attrs[i].nodeName.indexOf('_') !== 0)
|
|
15455 |
return FALSE;
|
|
15456 |
}
|
|
15457 |
}
|
|
15458 |
|
|
15459 |
// Remove the inline child if it's empty for example <b> or <span>
|
|
15460 |
if (format.remove != 'none') {
|
|
15461 |
removeNode(node, format);
|
|
15462 |
return TRUE;
|
|
15463 |
}
|
|
15464 |
};
|
|
15465 |
|
|
15466 |
function removeNode(node, format) {
|
|
15467 |
var parentNode = node.parentNode, rootBlockElm;
|
|
15468 |
|
|
15469 |
if (format.block) {
|
|
15470 |
if (!forcedRootBlock) {
|
|
15471 |
function find(node, next, inc) {
|
|
15472 |
node = getNonWhiteSpaceSibling(node, next, inc);
|
|
15473 |
|
|
15474 |
return !node || (node.nodeName == 'BR' || isBlock(node));
|
|
15475 |
};
|
|
15476 |
|
|
15477 |
// Append BR elements if needed before we remove the block
|
|
15478 |
if (isBlock(node) && !isBlock(parentNode)) {
|
|
15479 |
if (!find(node, FALSE) && !find(node.firstChild, TRUE, 1))
|
|
15480 |
node.insertBefore(dom.create('br'), node.firstChild);
|
|
15481 |
|
|
15482 |
if (!find(node, TRUE) && !find(node.lastChild, FALSE, 1))
|
|
15483 |
node.appendChild(dom.create('br'));
|
|
15484 |
}
|
|
15485 |
} else {
|
|
15486 |
// Wrap the block in a forcedRootBlock if we are at the root of document
|
|
15487 |
if (parentNode == dom.getRoot()) {
|
|
15488 |
if (!format.list_block || !isEq(node, format.list_block)) {
|
|
15489 |
each(tinymce.grep(node.childNodes), function(node) {
|
|
15490 |
if (isValid(forcedRootBlock, node.nodeName.toLowerCase())) {
|
|
15491 |
if (!rootBlockElm)
|
|
15492 |
rootBlockElm = wrap(node, forcedRootBlock);
|
|
15493 |
else
|
|
15494 |
rootBlockElm.appendChild(node);
|
|
15495 |
} else
|
|
15496 |
rootBlockElm = 0;
|
|
15497 |
});
|
|
15498 |
}
|
|
15499 |
}
|
|
15500 |
}
|
|
15501 |
}
|
|
15502 |
|
|
15503 |
// Never remove nodes that isn't the specified inline element if a selector is specified too
|
|
15504 |
if (format.selector && format.inline && !isEq(format.inline, node))
|
|
15505 |
return;
|
|
15506 |
|
|
15507 |
dom.remove(node, 1);
|
|
15508 |
};
|
|
15509 |
|
|
15510 |
function getNonWhiteSpaceSibling(node, next, inc) {
|
|
15511 |
if (node) {
|
|
15512 |
next = next ? 'nextSibling' : 'previousSibling';
|
|
15513 |
|
|
15514 |
for (node = inc ? node : node[next]; node; node = node[next]) {
|
|
15515 |
if (node.nodeType == 1 || !isWhiteSpaceNode(node))
|
|
15516 |
return node;
|
|
15517 |
}
|
|
15518 |
}
|
|
15519 |
};
|
|
15520 |
|
|
15521 |
function isBookmarkNode(node) {
|
a9251b
|
15522 |
return node && node.nodeType == 1 && node.getAttribute('data-mce-type') == 'bookmark';
|
69d05c
|
15523 |
};
|
A |
15524 |
|
|
15525 |
function mergeSiblings(prev, next) {
|
|
15526 |
var marker, sibling, tmpSibling;
|
|
15527 |
|
|
15528 |
function compareElements(node1, node2) {
|
|
15529 |
// Not the same name
|
|
15530 |
if (node1.nodeName != node2.nodeName)
|
|
15531 |
return FALSE;
|
|
15532 |
|
|
15533 |
function getAttribs(node) {
|
|
15534 |
var attribs = {};
|
|
15535 |
|
|
15536 |
each(dom.getAttribs(node), function(attr) {
|
|
15537 |
var name = attr.nodeName.toLowerCase();
|
|
15538 |
|
|
15539 |
// Don't compare internal attributes or style
|
|
15540 |
if (name.indexOf('_') !== 0 && name !== 'style')
|
|
15541 |
attribs[name] = dom.getAttrib(node, name);
|
58fb65
|
15542 |
});
|
69d05c
|
15543 |
|
A |
15544 |
return attribs;
|
|
15545 |
};
|
|
15546 |
|
|
15547 |
function compareObjects(obj1, obj2) {
|
|
15548 |
var value, name;
|
|
15549 |
|
|
15550 |
for (name in obj1) {
|
|
15551 |
// Obj1 has item obj2 doesn't have
|
|
15552 |
if (obj1.hasOwnProperty(name)) {
|
|
15553 |
value = obj2[name];
|
|
15554 |
|
|
15555 |
// Obj2 doesn't have obj1 item
|
|
15556 |
if (value === undefined)
|
|
15557 |
return FALSE;
|
|
15558 |
|
|
15559 |
// Obj2 item has a different value
|
|
15560 |
if (obj1[name] != value)
|
|
15561 |
return FALSE;
|
|
15562 |
|
|
15563 |
// Delete similar value
|
|
15564 |
delete obj2[name];
|
|
15565 |
}
|
|
15566 |
}
|
|
15567 |
|
|
15568 |
// Check if obj 2 has something obj 1 doesn't have
|
|
15569 |
for (name in obj2) {
|
|
15570 |
// Obj2 has item obj1 doesn't have
|
|
15571 |
if (obj2.hasOwnProperty(name))
|
|
15572 |
return FALSE;
|
|
15573 |
}
|
|
15574 |
|
|
15575 |
return TRUE;
|
|
15576 |
};
|
|
15577 |
|
|
15578 |
// Attribs are not the same
|
|
15579 |
if (!compareObjects(getAttribs(node1), getAttribs(node2)))
|
|
15580 |
return FALSE;
|
|
15581 |
|
|
15582 |
// Styles are not the same
|
|
15583 |
if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style'))))
|
|
15584 |
return FALSE;
|
|
15585 |
|
|
15586 |
return TRUE;
|
|
15587 |
};
|
|
15588 |
|
|
15589 |
// Check if next/prev exists and that they are elements
|
|
15590 |
if (prev && next) {
|
|
15591 |
function findElementSibling(node, sibling_name) {
|
|
15592 |
for (sibling = node; sibling; sibling = sibling[sibling_name]) {
|
a9251b
|
15593 |
if (sibling.nodeType == 3 && sibling.nodeValue.length !== 0)
|
69d05c
|
15594 |
return node;
|
A |
15595 |
|
|
15596 |
if (sibling.nodeType == 1 && !isBookmarkNode(sibling))
|
|
15597 |
return sibling;
|
|
15598 |
}
|
|
15599 |
|
|
15600 |
return node;
|
|
15601 |
};
|
|
15602 |
|
|
15603 |
// If previous sibling is empty then jump over it
|
|
15604 |
prev = findElementSibling(prev, 'previousSibling');
|
|
15605 |
next = findElementSibling(next, 'nextSibling');
|
|
15606 |
|
|
15607 |
// Compare next and previous nodes
|
|
15608 |
if (compareElements(prev, next)) {
|
|
15609 |
// Append nodes between
|
|
15610 |
for (sibling = prev.nextSibling; sibling && sibling != next;) {
|
|
15611 |
tmpSibling = sibling;
|
|
15612 |
sibling = sibling.nextSibling;
|
|
15613 |
prev.appendChild(tmpSibling);
|
|
15614 |
}
|
|
15615 |
|
|
15616 |
// Remove next node
|
|
15617 |
dom.remove(next);
|
|
15618 |
|
|
15619 |
// Move children into prev node
|
|
15620 |
each(tinymce.grep(next.childNodes), function(node) {
|
|
15621 |
prev.appendChild(node);
|
|
15622 |
});
|
|
15623 |
|
|
15624 |
return prev;
|
|
15625 |
}
|
29da64
|
15626 |
}
|
69d05c
|
15627 |
|
A |
15628 |
return next;
|
|
15629 |
};
|
|
15630 |
|
|
15631 |
function isTextBlock(name) {
|
2011be
|
15632 |
return /^(h[1-6]|p|div|pre|address|dl|dt|dd)$/.test(name);
|
69d05c
|
15633 |
};
|
A |
15634 |
|
|
15635 |
function getContainer(rng, start) {
|
|
15636 |
var container, offset, lastIdx;
|
|
15637 |
|
|
15638 |
container = rng[start ? 'startContainer' : 'endContainer'];
|
|
15639 |
offset = rng[start ? 'startOffset' : 'endOffset'];
|
|
15640 |
|
|
15641 |
if (container.nodeType == 1) {
|
|
15642 |
lastIdx = container.childNodes.length - 1;
|
|
15643 |
|
|
15644 |
if (!start && offset)
|
|
15645 |
offset--;
|
|
15646 |
|
|
15647 |
container = container.childNodes[offset > lastIdx ? lastIdx : offset];
|
|
15648 |
}
|
|
15649 |
|
|
15650 |
return container;
|
|
15651 |
};
|
|
15652 |
|
|
15653 |
function performCaretAction(type, name, vars) {
|
|
15654 |
var i, currentPendingFormats = pendingFormats[type],
|
|
15655 |
otherPendingFormats = pendingFormats[type == 'apply' ? 'remove' : 'apply'];
|
|
15656 |
|
|
15657 |
function hasPending() {
|
|
15658 |
return pendingFormats.apply.length || pendingFormats.remove.length;
|
|
15659 |
};
|
|
15660 |
|
|
15661 |
function resetPending() {
|
|
15662 |
pendingFormats.apply = [];
|
|
15663 |
pendingFormats.remove = [];
|
|
15664 |
};
|
|
15665 |
|
|
15666 |
function perform(caret_node) {
|
|
15667 |
// Apply pending formats
|
|
15668 |
each(pendingFormats.apply.reverse(), function(item) {
|
|
15669 |
apply(item.name, item.vars, caret_node);
|
a9251b
|
15670 |
|
T |
15671 |
// Colored nodes should be underlined so that the color of the underline matches the text color.
|
|
15672 |
if (item.name === 'forecolor' && item.vars.value)
|
|
15673 |
processUnderlineAndColor(caret_node.parentNode);
|
69d05c
|
15674 |
});
|
A |
15675 |
|
|
15676 |
// Remove pending formats
|
|
15677 |
each(pendingFormats.remove.reverse(), function(item) {
|
|
15678 |
remove(item.name, item.vars, caret_node);
|
|
15679 |
});
|
|
15680 |
|
|
15681 |
dom.remove(caret_node, 1);
|
|
15682 |
resetPending();
|
|
15683 |
};
|
|
15684 |
|
|
15685 |
// Check if it already exists then ignore it
|
|
15686 |
for (i = currentPendingFormats.length - 1; i >= 0; i--) {
|
|
15687 |
if (currentPendingFormats[i].name == name)
|
|
15688 |
return;
|
|
15689 |
}
|
|
15690 |
|
|
15691 |
currentPendingFormats.push({name : name, vars : vars});
|
|
15692 |
|
|
15693 |
// Check if it's in the other type, then remove it
|
|
15694 |
for (i = otherPendingFormats.length - 1; i >= 0; i--) {
|
|
15695 |
if (otherPendingFormats[i].name == name)
|
|
15696 |
otherPendingFormats.splice(i, 1);
|
|
15697 |
}
|
|
15698 |
|
|
15699 |
// Pending apply or remove formats
|
|
15700 |
if (hasPending()) {
|
|
15701 |
ed.getDoc().execCommand('FontName', false, 'mceinline');
|
2011be
|
15702 |
pendingFormats.lastRng = selection.getRng();
|
69d05c
|
15703 |
|
A |
15704 |
// IE will convert the current word
|
|
15705 |
each(dom.select('font,span'), function(node) {
|
|
15706 |
var bookmark;
|
|
15707 |
|
|
15708 |
if (isCaretNode(node)) {
|
|
15709 |
bookmark = selection.getBookmark();
|
|
15710 |
perform(node);
|
|
15711 |
selection.moveToBookmark(bookmark);
|
|
15712 |
ed.nodeChanged();
|
|
15713 |
}
|
|
15714 |
});
|
|
15715 |
|
|
15716 |
// Only register listeners once if we need to
|
|
15717 |
if (!pendingFormats.isListening && hasPending()) {
|
|
15718 |
pendingFormats.isListening = true;
|
|
15719 |
|
|
15720 |
each('onKeyDown,onKeyUp,onKeyPress,onMouseUp'.split(','), function(event) {
|
|
15721 |
ed[event].addToTop(function(ed, e) {
|
2011be
|
15722 |
// Do we have pending formats and is the selection moved has moved
|
A |
15723 |
if (hasPending() && !tinymce.dom.RangeUtils.compareRanges(pendingFormats.lastRng, selection.getRng())) {
|
69d05c
|
15724 |
each(dom.select('font,span'), function(node) {
|
2011be
|
15725 |
var textNode, rng;
|
69d05c
|
15726 |
|
A |
15727 |
// Look for marker
|
|
15728 |
if (isCaretNode(node)) {
|
|
15729 |
textNode = node.firstChild;
|
|
15730 |
|
2011be
|
15731 |
if (textNode) {
|
A |
15732 |
perform(node);
|
69d05c
|
15733 |
|
2011be
|
15734 |
rng = dom.createRng();
|
A |
15735 |
rng.setStart(textNode, textNode.nodeValue.length);
|
|
15736 |
rng.setEnd(textNode, textNode.nodeValue.length);
|
|
15737 |
selection.setRng(rng);
|
|
15738 |
ed.nodeChanged();
|
|
15739 |
} else
|
|
15740 |
dom.remove(node);
|
69d05c
|
15741 |
}
|
A |
15742 |
});
|
|
15743 |
|
|
15744 |
// Always unbind and clear pending styles on keyup
|
|
15745 |
if (e.type == 'keyup' || e.type == 'mouseup')
|
|
15746 |
resetPending();
|
|
15747 |
}
|
|
15748 |
});
|
|
15749 |
});
|
|
15750 |
}
|
|
15751 |
}
|
|
15752 |
};
|
|
15753 |
};
|
|
15754 |
})(tinymce);
|
|
15755 |
|
|
15756 |
tinymce.onAddEditor.add(function(tinymce, ed) {
|
|
15757 |
var filters, fontSizes, dom, settings = ed.settings;
|
|
15758 |
|
|
15759 |
if (settings.inline_styles) {
|
|
15760 |
fontSizes = tinymce.explode(settings.font_size_style_values);
|
|
15761 |
|
|
15762 |
function replaceWithSpan(node, styles) {
|
a9251b
|
15763 |
tinymce.each(styles, function(value, name) {
|
T |
15764 |
if (value)
|
|
15765 |
dom.setStyle(node, name, value);
|
|
15766 |
});
|
|
15767 |
|
|
15768 |
dom.rename(node, 'span');
|
69d05c
|
15769 |
};
|
A |
15770 |
|
|
15771 |
filters = {
|
|
15772 |
font : function(dom, node) {
|
|
15773 |
replaceWithSpan(node, {
|
|
15774 |
backgroundColor : node.style.backgroundColor,
|
|
15775 |
color : node.color,
|
|
15776 |
fontFamily : node.face,
|
|
15777 |
fontSize : fontSizes[parseInt(node.size) - 1]
|
|
15778 |
});
|
|
15779 |
},
|
|
15780 |
|
|
15781 |
u : function(dom, node) {
|
|
15782 |
replaceWithSpan(node, {
|
|
15783 |
textDecoration : 'underline'
|
|
15784 |
});
|
|
15785 |
},
|
|
15786 |
|
|
15787 |
strike : function(dom, node) {
|
|
15788 |
replaceWithSpan(node, {
|
|
15789 |
textDecoration : 'line-through'
|
|
15790 |
});
|
|
15791 |
}
|
|
15792 |
};
|
|
15793 |
|
|
15794 |
function convert(editor, params) {
|
|
15795 |
dom = editor.dom;
|
|
15796 |
|
|
15797 |
if (settings.convert_fonts_to_spans) {
|
|
15798 |
tinymce.each(dom.select('font,u,strike', params.node), function(node) {
|
|
15799 |
filters[node.nodeName.toLowerCase()](ed.dom, node);
|
|
15800 |
});
|
|
15801 |
}
|
|
15802 |
};
|
|
15803 |
|
|
15804 |
ed.onPreProcess.add(convert);
|
a9251b
|
15805 |
ed.onSetContent.add(convert);
|
69d05c
|
15806 |
|
A |
15807 |
ed.onInit.add(function() {
|
|
15808 |
ed.selection.onSetContent.add(convert);
|
29da64
|
15809 |
});
|
69d05c
|
15810 |
}
|
A |
15811 |
});
|
29da64
|
15812 |
|