Lib_Js_TinyMCE - Version 3.3.7.0

Version Notes

3.3.7.0

Download this release

Release Info

Developer Magento Core Team
Extension Lib_Js_TinyMCE
Version 3.3.7.0
Comparing to
See all releases


Code changes from version 3.3.2.0 to 3.3.7.0

Files changed (50) hide show
  1. js/tiny_mce/classes/Editor.js +76 -7
  2. js/tiny_mce/classes/EditorCommands.js +15 -5
  3. js/tiny_mce/classes/ForceBlocks.js +93 -38
  4. js/tiny_mce/classes/Formatter.js +62 -33
  5. js/tiny_mce/classes/adapter/jquery/jquery.tinymce.js +17 -8
  6. js/tiny_mce/classes/dom/DOMUtils.js +9 -6
  7. js/tiny_mce/classes/dom/RangeUtils.js +28 -0
  8. js/tiny_mce/classes/dom/Selection.js +85 -39
  9. js/tiny_mce/classes/dom/Sizzle.js +234 -137
  10. js/tiny_mce/classes/dom/TridentSelection.js +99 -92
  11. js/tiny_mce/classes/tinymce.js +9 -0
  12. js/tiny_mce/classes/ui/ListBox.js +1 -1
  13. js/tiny_mce/jquery.tinymce.js +1 -1
  14. js/tiny_mce/langs/en.js +17 -16
  15. js/tiny_mce/plugins/autoresize/editor_plugin.js +1 -1
  16. js/tiny_mce/plugins/autoresize/editor_plugin_src.js +23 -21
  17. js/tiny_mce/plugins/contextmenu/editor_plugin.js +1 -1
  18. js/tiny_mce/plugins/contextmenu/editor_plugin_src.js +23 -3
  19. js/tiny_mce/plugins/fullpage/editor_plugin.js +1 -1
  20. js/tiny_mce/plugins/fullpage/editor_plugin_src.js +4 -0
  21. js/tiny_mce/plugins/fullscreen/editor_plugin.js +1 -1
  22. js/tiny_mce/plugins/fullscreen/editor_plugin_src.js +6 -3
  23. js/tiny_mce/plugins/legacyoutput/editor_plugin.js +1 -1
  24. js/tiny_mce/plugins/legacyoutput/editor_plugin_src.js +1 -1
  25. js/tiny_mce/plugins/paste/editor_plugin.js +1 -1
  26. js/tiny_mce/plugins/paste/editor_plugin_src.js +18 -7
  27. js/tiny_mce/plugins/spellchecker/editor_plugin.js +1 -1
  28. js/tiny_mce/plugins/spellchecker/editor_plugin_src.js +100 -24
  29. js/tiny_mce/plugins/style/props.htm +2 -5
  30. js/tiny_mce/plugins/table/editor_plugin.js +1 -1
  31. js/tiny_mce/plugins/table/editor_plugin_src.js +12 -5
  32. js/tiny_mce/plugins/table/js/cell.js +1 -1
  33. js/tiny_mce/plugins/table/js/row.js +1 -1
  34. js/tiny_mce/plugins/table/js/table.js +2 -2
  35. js/tiny_mce/plugins/template/template.htm +0 -1
  36. js/tiny_mce/plugins/wordcount/editor_plugin.js +1 -1
  37. js/tiny_mce/plugins/wordcount/editor_plugin_src.js +1 -1
  38. js/tiny_mce/themes/advanced/charmap.htm +0 -1
  39. js/tiny_mce/themes/advanced/editor_template.js +1 -1
  40. js/tiny_mce/themes/advanced/editor_template_src.js +38 -11
  41. js/tiny_mce/themes/advanced/skins/default/ui.css +1 -1
  42. js/tiny_mce/themes/advanced/skins/o2k7/ui.css +1 -1
  43. js/tiny_mce/themes/advanced/source_editor.htm +0 -1
  44. js/tiny_mce/tiny_mce.js +1 -1
  45. js/tiny_mce/tiny_mce_jquery.js +1 -1
  46. js/tiny_mce/tiny_mce_jquery_src.js +455 -215
  47. js/tiny_mce/tiny_mce_prototype.js +1 -1
  48. js/tiny_mce/tiny_mce_prototype_src.js +688 -351
  49. js/tiny_mce/tiny_mce_src.js +688 -351
  50. package.xml +5 -5
js/tiny_mce/classes/Editor.js CHANGED
@@ -480,6 +480,12 @@
480
if (!t.getElement())
481
return;
482
483
// Add hidden input for non input elements inside form elements
484
if (!/TEXTAREA|INPUT/i.test(t.getElement().nodeName) && s.hidden_input && DOM.getParent(id, 'form'))
485
DOM.insertAfter(DOM.create('input', {type : 'hidden', name : id}), id);
@@ -916,6 +922,7 @@
916
hilitecolor : {inline : 'span', styles : {backgroundColor : '%value'}},
917
fontname : {inline : 'span', styles : {fontFamily : '%value'}},
918
fontsize : {inline : 'span', styles : {fontSize : '%value'}},
919
blockquote : {block : 'blockquote', wrapper : 1, remove : 'all'},
920
921
removeformat : [
@@ -1321,13 +1328,28 @@
1321
* @param {Boolean} sf Skip DOM focus. Just set is as the active editor.
1322
*/
1323
focus : function(sf) {
1324
- var oed, t = this, ce = t.settings.content_editable;
1325
1326
if (!sf) {
1327
// Is not content editable
1328
if (!ce)
1329
t.getWin().focus();
1330
1331
// #ifdef contentEditable
1332
1333
// Content editable mode ends here
@@ -2368,7 +2390,7 @@
2368
2369
// Add node change handlers
2370
t.onMouseUp.add(t.nodeChanged);
2371
- t.onClick.add(t.nodeChanged);
2372
t.onKeyUp.add(function(ed, e) {
2373
var c = e.keyCode;
2374
@@ -2389,11 +2411,9 @@
2389
}
2390
2391
// Add default shortcuts for gecko
2392
- if (isGecko) {
2393
- t.addShortcut('ctrl+b', t.getLang('bold_desc'), 'Bold');
2394
- t.addShortcut('ctrl+i', t.getLang('italic_desc'), 'Italic');
2395
- t.addShortcut('ctrl+u', t.getLang('underline_desc'), 'Underline');
2396
- }
2397
2398
// BlockFormat shortcuts keys
2399
for (i=1; i<=6; i++)
@@ -2544,6 +2564,55 @@
2544
});
2545
2546
t.onKeyDown.add(function(ed, e) {
2547
// Is caracter positon keys
2548
if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45) {
2549
if (t.undoManager.typing)
480
if (!t.getElement())
481
return;
482
483
+ // Is a iPad/iPhone, then skip initialization. We need to sniff here since the
484
+ // browser says it has contentEditable support but there is no visible caret
485
+ // We will remove this check ones Apple implements full contentEditable support
486
+ if (tinymce.isIDevice)
487
+ return;
488
+
489
// Add hidden input for non input elements inside form elements
490
if (!/TEXTAREA|INPUT/i.test(t.getElement().nodeName) && s.hidden_input && DOM.getParent(id, 'form'))
491
DOM.insertAfter(DOM.create('input', {type : 'hidden', name : id}), id);
922
hilitecolor : {inline : 'span', styles : {backgroundColor : '%value'}},
923
fontname : {inline : 'span', styles : {fontFamily : '%value'}},
924
fontsize : {inline : 'span', styles : {fontSize : '%value'}},
925
+ fontsize_class : {inline : 'span', attributes : {'class' : '%value'}},
926
blockquote : {block : 'blockquote', wrapper : 1, remove : 'all'},
927
928
removeformat : [
1328
* @param {Boolean} sf Skip DOM focus. Just set is as the active editor.
1329
*/
1330
focus : function(sf) {
1331
+ var oed, t = this, ce = t.settings.content_editable, ieRng, controlElm, doc = t.getDoc();
1332
1333
if (!sf) {
1334
+ // Get selected control element
1335
+ ieRng = t.selection.getRng();
1336
+ if (ieRng.item) {
1337
+ controlElm = ieRng.item(0);
1338
+ }
1339
+
1340
// Is not content editable
1341
if (!ce)
1342
t.getWin().focus();
1343
1344
+ // Restore selected control element
1345
+ // This is needed when for example an image is selected within a
1346
+ // layer a call to focus will then remove the control selection
1347
+ if (controlElm && controlElm.ownerDocument == doc) {
1348
+ ieRng = doc.body.createControlRange();
1349
+ ieRng.addElement(controlElm);
1350
+ ieRng.select();
1351
+ }
1352
+
1353
// #ifdef contentEditable
1354
1355
// Content editable mode ends here
2390
2391
// Add node change handlers
2392
t.onMouseUp.add(t.nodeChanged);
2393
+ //t.onClick.add(t.nodeChanged);
2394
t.onKeyUp.add(function(ed, e) {
2395
var c = e.keyCode;
2396
2411
}
2412
2413
// Add default shortcuts for gecko
2414
+ t.addShortcut('ctrl+b', t.getLang('bold_desc'), 'Bold');
2415
+ t.addShortcut('ctrl+i', t.getLang('italic_desc'), 'Italic');
2416
+ t.addShortcut('ctrl+u', t.getLang('underline_desc'), 'Underline');
2417
2418
// BlockFormat shortcuts keys
2419
for (i=1; i<=6; i++)
2564
});
2565
2566
t.onKeyDown.add(function(ed, e) {
2567
+ var rng, tmpRng, parent, offset;
2568
+
2569
+ // IE has a really odd bug where the DOM might include an node that doesn't have
2570
+ // a proper structure. If you try to access nodeValue it would throw an illegal value exception.
2571
+ // This seems to only happen when you delete contents and it seems to be avoidable if you refresh the element
2572
+ // after you delete contents from it. See: #3008923
2573
+ if (isIE && e.keyCode == 46) {
2574
+ rng = t.selection.getRng();
2575
+
2576
+ if (rng.parentElement) {
2577
+ parent = rng.parentElement();
2578
+
2579
+ // Get the current caret position within the element
2580
+ tmpRng = rng.duplicate();
2581
+ tmpRng.moveToElementText(parent);
2582
+ tmpRng.setEndPoint('EndToEnd', rng);
2583
+ offset = tmpRng.text.length;
2584
+
2585
+ // Select next word when ctrl key is used in combo with delete
2586
+ if (e.ctrlKey) {
2587
+ rng.moveEnd('word', 1);
2588
+ rng.select();
2589
+ }
2590
+
2591
+ // Delete contents
2592
+ t.selection.getSel().clear();
2593
+
2594
+ // Check if we are within the same parent
2595
+ if (rng.parentElement() == parent) {
2596
+ try {
2597
+ // Update the HTML and hopefully it will remove the artifacts
2598
+ parent.innerHTML = parent.innerHTML;
2599
+ } catch (ex) {
2600
+ // And since it's IE it can sometimes produce an unknown runtime error
2601
+ }
2602
+
2603
+ // Restore the caret position
2604
+ tmpRng.moveToElementText(parent);
2605
+ tmpRng.collapse();
2606
+ tmpRng.move('character', offset);
2607
+ tmpRng.select();
2608
+ }
2609
+
2610
+ // Block the default delete behavior since it might be broken
2611
+ e.preventDefault();
2612
+ return;
2613
+ }
2614
+ }
2615
+
2616
// Is caracter positon keys
2617
if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45) {
2618
if (t.undoManager.typing)
js/tiny_mce/classes/EditorCommands.js CHANGED
@@ -155,7 +155,7 @@
155
}
156
157
// Present alert message about clipboard access not being available
158
- if (failed || !doc.queryCommandEnabled(command)) {
159
if (tinymce.isGecko) {
160
editor.windowManager.confirm(editor.getLang('clipboard_msg'), function(state) {
161
if (state)
@@ -250,16 +250,18 @@
250
},
251
252
mceCleanup : function() {
253
- storeSelection();
254
editor.setContent(editor.getContent({cleanup : TRUE}), {cleanup : TRUE});
255
- restoreSelection();
256
},
257
258
mceRemoveNode : function(command, ui, value) {
259
var node = value || selection.getNode();
260
261
// Make sure that the body node isn't removed
262
- if (node != ed.getBody()) {
263
storeSelection();
264
editor.dom.remove(node, TRUE);
265
restoreSelection();
@@ -364,8 +366,16 @@
364
if (value.href)
365
dom.setAttribs(link, value);
366
else
367
- ed.dom.remove(link, TRUE);
368
}
369
}
370
});
371
155
}
156
157
// Present alert message about clipboard access not being available
158
+ if (failed || !doc.queryCommandSupported(command)) {
159
if (tinymce.isGecko) {
160
editor.windowManager.confirm(editor.getLang('clipboard_msg'), function(state) {
161
if (state)
250
},
251
252
mceCleanup : function() {
253
+ var bookmark = selection.getBookmark();
254
+
255
editor.setContent(editor.getContent({cleanup : TRUE}), {cleanup : TRUE});
256
+
257
+ selection.moveToBookmark(bookmark);
258
},
259
260
mceRemoveNode : function(command, ui, value) {
261
var node = value || selection.getNode();
262
263
// Make sure that the body node isn't removed
264
+ if (node != editor.getBody()) {
265
storeSelection();
266
editor.dom.remove(node, TRUE);
267
restoreSelection();
366
if (value.href)
367
dom.setAttribs(link, value);
368
else
369
+ editor.dom.remove(link, TRUE);
370
}
371
+ },
372
+
373
+ selectAll : function() {
374
+ var root = dom.getRoot();
375
+ var rng = dom.createRng();
376
+ rng.setStart(root, 0);
377
+ rng.setEnd(root, root.childNodes.length);
378
+ editor.selection.setRng(rng);
379
}
380
});
381
js/tiny_mce/classes/ForceBlocks.js CHANGED
@@ -19,6 +19,27 @@
19
TRUE = true,
20
FALSE = false;
21
22
// Checks if the selection/caret is at the end of the specified block element
23
function isAtEnd(rng, par) {
24
var rng2 = par.ownerDocument.createRange();
@@ -130,11 +151,54 @@
130
}
131
}
132
133
- if (!isIE && s.force_p_newlines) {
134
- ed.onKeyPress.add(function(ed, e) {
135
- if (e.keyCode == 13 && !e.shiftKey && !t.insertPara(e))
136
- Event.cancel(e);
137
- });
138
139
if (isGecko) {
140
ed.onKeyDown.add(function(ed, e) {
@@ -175,7 +239,7 @@
175
};
176
177
ed.onKeyPress.add(function(ed, e) {
178
- if (e.keyCode == 13 && (e.shiftKey || s.force_br_newlines)) {
179
insertBr(ed);
180
Event.cancel(e);
181
}
@@ -285,6 +349,13 @@
285
}
286
}
287
} else {
288
tr = d.body.createTextRange();
289
tr.moveToElementText(b);
290
tr.collapse(1);
@@ -629,7 +700,22 @@
629
},
630
631
backspaceDelete : function(e, bs) {
632
- 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;
633
634
// The caret sometimes gets stuck in Gecko if you delete empty paragraphs
635
// This workaround removes the element by hand and moves the caret to the previous element
@@ -660,37 +746,6 @@
660
}
661
}
662
}
663
-
664
- // Gecko generates BR elements here and there, we don't like those so lets remove them
665
- function handler(e) {
666
- var pr;
667
-
668
- e = e.target;
669
-
670
- // A new BR was created in a block element, remove it
671
- if (e && e.parentNode && e.nodeName == 'BR' && (n = t.getParentBlock(e))) {
672
- pr = e.previousSibling;
673
-
674
- Event.remove(b, 'DOMNodeInserted', handler);
675
-
676
- // Is there whitespace at the end of the node before then we might need the pesky BR
677
- // to place the caret at a correct location see bug: #2013943
678
- if (pr && pr.nodeType == 3 && /\s+#x2F;.test(pr.nodeValue))
679
- return;
680
-
681
- // Only remove BR elements that got inserted in the middle of the text
682
- if (e.previousSibling || e.nextSibling)
683
- ed.dom.remove(e);
684
- }
685
- };
686
-
687
- // Listen for new nodes
688
- Event._add(b, 'DOMNodeInserted', handler);
689
-
690
- // Remove listener
691
- window.setTimeout(function() {
692
- Event._remove(b, 'DOMNodeInserted', handler);
693
- }, 1);
694
}
695
});
696
})(tinymce);
19
TRUE = true,
20
FALSE = false;
21
22
+ function cloneFormats(node) {
23
+ var clone, temp, inner;
24
+
25
+ do {
26
+ if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)#x2F;.test(node.nodeName)) {
27
+ if (clone) {
28
+ temp = node.cloneNode(false);
29
+ temp.appendChild(clone);
30
+ clone = temp;
31
+ } else {
32
+ clone = inner = node.cloneNode(false);
33
+ }
34
+
35
+ clone.removeAttribute('id');
36
+ }
37
+ } while (node = node.parentNode);
38
+
39
+ if (clone)
40
+ return {wrapper : clone, inner : inner};
41
+ };
42
+
43
// Checks if the selection/caret is at the end of the specified block element
44
function isAtEnd(rng, par) {
45
var rng2 = par.ownerDocument.createRange();
151
}
152
}
153
154
+ if (s.force_p_newlines) {
155
+ if (!isIE) {
156
+ ed.onKeyPress.add(function(ed, e) {
157
+ if (e.keyCode == 13 && !e.shiftKey && !t.insertPara(e))
158
+ Event.cancel(e);
159
+ });
160
+ } else {
161
+ // Ungly hack to for IE to preserve the formatting when you press
162
+ // enter at the end of a block element with formatted contents
163
+ // This logic overrides the browsers default logic with
164
+ // custom logic that enables us to control the output
165
+ tinymce.addUnload(function() {
166
+ t._previousFormats = 0; // Fix IE leak
167
+ });
168
+
169
+ ed.onKeyPress.add(function(ed, e) {
170
+ t._previousFormats = 0;
171
+
172
+ // Clone the current formats, this will later be applied to the new block contents
173
+ if (e.keyCode == 13 && !e.shiftKey && ed.selection.isCollapsed() && s.keep_styles)
174
+ t._previousFormats = cloneFormats(ed.selection.getStart());
175
+ });
176
+
177
+ ed.onKeyUp.add(function(ed, e) {
178
+ // Let IE break the element and the wrap the new caret location in the previous formats
179
+ if (e.keyCode == 13 && !e.shiftKey) {
180
+ var parent = ed.selection.getStart(), fmt = t._previousFormats;
181
+
182
+ // Parent is an empty block
183
+ if (!parent.hasChildNodes()) {
184
+ parent = dom.getParent(parent, dom.isBlock);
185
+
186
+ if (parent) {
187
+ parent.innerHTML = '';
188
+
189
+ if (t._previousFormats) {
190
+ parent.appendChild(fmt.wrapper);
191
+ fmt.inner.innerHTML = '\uFEFF';
192
+ } else
193
+ parent.innerHTML = '\uFEFF';
194
+
195
+ selection.select(parent, 1);
196
+ ed.getDoc().execCommand('Delete', false, null);
197
+ }
198
+ }
199
+ }
200
+ });
201
+ }
202
203
if (isGecko) {
204
ed.onKeyDown.add(function(ed, e) {
239
};
240
241
ed.onKeyPress.add(function(ed, e) {
242
+ if (e.keyCode == 13 && (e.shiftKey || (s.force_br_newlines && !dom.getParent(selection.getNode(), 'h1,h2,h3,h4,h5,h6,ol,ul')))) {
243
insertBr(ed);
244
Event.cancel(e);
245
}
349
}
350
}
351
} else {
352
+ // Force control range into text range
353
+ if (r.item) {
354
+ tr = d.body.createTextRange();
355
+ tr.moveToElementText(r.item(0));
356
+ r = tr;
357
+ }
358
+
359
tr = d.body.createTextRange();
360
tr.moveToElementText(b);
361
tr.collapse(1);
700
},
701
702
backspaceDelete : function(e, bs) {
703
+ 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;
704
+
705
+ // Delete when caret is behind a element doesn't work correctly on Gecko see #3011651
706
+ if (!bs && r.collapsed && sc.nodeType == 1 && r.startOffset == sc.childNodes.length) {
707
+ walker = new tinymce.dom.TreeWalker(sc.lastChild, sc);
708
+
709
+ // Walk the dom backwards until we find a text node
710
+ for (n = sc.lastChild; n; n = walker.prev()) {
711
+ if (n.nodeType == 3) {
712
+ r.setStart(n, n.nodeValue.length);
713
+ r.collapse(true);
714
+ se.setRng(r);
715
+ return;
716
+ }
717
+ }
718
+ }
719
720
// The caret sometimes gets stuck in Gecko if you delete empty paragraphs
721
// This workaround removes the element by hand and moves the caret to the previous element
746
}
747
}
748
}
749
}
750
});
751
})(tinymce);
js/tiny_mce/classes/Formatter.js CHANGED
@@ -141,11 +141,16 @@
141
142
// Move startContainer/startOffset in to a suitable node
143
if (container.nodeType == 1 || container.nodeValue === "") {
144
- walker = new TreeWalker(container.childNodes[offset]);
145
- for (node = walker.current(); node; node = walker.next()) {
146
- if (node.nodeType == 3 && !isBlock(node.parentNode) && !isWhiteSpaceNode(node)) {
147
- rng.setStart(node, 0);
148
- break;
149
}
150
}
151
}
@@ -227,7 +232,7 @@
227
}
228
});
229
230
- // Contine processing if a selector match wasn't found and a inline element is defined
231
if (!format.inline || found) {
232
currentWrapElm = 0;
233
return;
@@ -320,14 +325,23 @@
320
});
321
});
322
323
// Look for parent with similar style format
324
- dom.getParent(node.parentNode, function(parent) {
325
- if (matchNode(parent, name, vars)) {
326
- dom.remove(node, 1);
327
- node = 0;
328
- return TRUE;
329
- }
330
- });
331
332
// Merge next and previous siblings if they are similar <b>text</b><b>text</b> becomes <b>texttext</b>
333
if (node) {
@@ -345,7 +359,7 @@
345
rng.setStartBefore(node);
346
rng.setEndAfter(node);
347
348
- applyRngStyle(rng);
349
} else {
350
if (!selection.isCollapsed() || !format.inline) {
351
// Apply formatting to selection
@@ -462,7 +476,13 @@
462
var node = dom.get(start ? '_start' : '_end'),
463
out = node[start ? 'firstChild' : 'lastChild'];
464
465
- dom.remove(node, 1);
466
467
return out;
468
};
@@ -525,7 +545,7 @@
525
};
526
527
/**
528
- * Toggles the specifed format on/off.
529
*
530
* @method toggle
531
* @param {String} name Name of format to apply/remove.
@@ -546,9 +566,10 @@
546
* @param {Node} node Node to check the format on.
547
* @param {String} name Format name to check.
548
* @param {Object} vars Optional list of variables to replace before checking it.
549
* @return {Object} Returns the format object it matches or undefined if it doesn't match.
550
*/
551
- function matchNode(node, name, vars) {
552
var formatList = get(name), format, i, classes;
553
554
function matchItems(node, format, item_name) {
@@ -565,7 +586,10 @@
565
else
566
value = getStyle(node, key);
567
568
- if (!isEq(value, replaceVars(items[key], vars)))
569
return;
570
}
571
}
@@ -603,7 +627,7 @@
603
};
604
605
/**
606
- * Matches the current selection or specifed node against the specified format name.
607
*
608
* @method match
609
* @param {String} name Name of format to match.
@@ -617,7 +641,7 @@
617
function matchParents(node) {
618
// Find first node with similar format settings
619
node = dom.getParent(node, function(node) {
620
- return !!matchNode(node, name, vars);
621
});
622
623
// Do an exact check on the similar format element
@@ -764,7 +788,7 @@
764
* Checks if the specified nodes name matches the format inline/block or selector.
765
*
766
* @private
767
- * @param {Node} node Node to match agains the specified format.
768
* @param {Object} format Format object o match with.
769
* @return {boolean} true/false if the format matches.
770
*/
@@ -844,7 +868,7 @@
844
};
845
846
function isWhiteSpaceNode(node) {
847
- return node && node.nodeType === 3 && /^\s*#x2F;.test(node.nodeValue);
848
};
849
850
function wrap(node, name, attrs) {
@@ -1042,7 +1066,7 @@
1042
* @param {Object} format Format object with items to remove from node.
1043
* @param {Object} vars Name/value object with variables to apply to format.
1044
* @param {Node} node Node to remove the format styles on.
1045
- * @param {Node} compare_node Optional compare node, if specidied the styles will be compared to that node.
1046
* @return {Boolean} True/false if the node was removed or not.
1047
*/
1048
function removeFormat(format, vars, node, compare_node) {
@@ -1252,7 +1276,7 @@
1252
*
1253
* @private
1254
* @param {Node} node1 First node to compare with.
1255
- * @param {Node} node2 Secont node to compare with.
1256
* @return {boolean} True/false if the nodes are the same or not.
1257
*/
1258
function compareElements(node1, node2) {
@@ -1381,7 +1405,7 @@
1381
* @return {boolean} True/false if the node is a text block.
1382
*/
1383
function isTextBlock(name) {
1384
- return /^(h[1-6]|p|div|pre|address)#x2F;.test(name);
1385
};
1386
1387
function getContainer(rng, start) {
@@ -1447,6 +1471,7 @@
1447
// Pending apply or remove formats
1448
if (hasPending()) {
1449
ed.getDoc().execCommand('FontName', false, 'mceinline');
1450
1451
// IE will convert the current word
1452
each(dom.select('font,span'), function(node) {
@@ -1466,21 +1491,25 @@
1466
1467
each('onKeyDown,onKeyUp,onKeyPress,onMouseUp'.split(','), function(event) {
1468
ed[event].addToTop(function(ed, e) {
1469
- if (hasPending()) {
1470
each(dom.select('font,span'), function(node) {
1471
- var bookmark, textNode, rng;
1472
1473
// Look for marker
1474
if (isCaretNode(node)) {
1475
textNode = node.firstChild;
1476
1477
- perform(node);
1478
1479
- rng = dom.createRng();
1480
- rng.setStart(textNode, textNode.nodeValue.length);
1481
- rng.setEnd(textNode, textNode.nodeValue.length);
1482
- selection.setRng(rng);
1483
- ed.nodeChanged();
1484
}
1485
});
1486
141
142
// Move startContainer/startOffset in to a suitable node
143
if (container.nodeType == 1 || container.nodeValue === "") {
144
+ container = container.nodeType == 1 ? container.childNodes[offset] : container;
145
+
146
+ // Might fail if the offset is behind the last element in it's container
147
+ if (container) {
148
+ walker = new TreeWalker(container, container.parentNode);
149
+ for (node = walker.current(); node; node = walker.next()) {
150
+ if (node.nodeType == 3 && !isWhiteSpaceNode(node)) {
151
+ rng.setStart(node, 0);
152
+ break;
153
+ }
154
}
155
}
156
}
232
}
233
});
234
235
+ // Continue processing if a selector match wasn't found and a inline element is defined
236
if (!format.inline || found) {
237
currentWrapElm = 0;
238
return;
325
});
326
});
327
328
+ // Remove child if direct parent is of same type
329
+ if (matchNode(node.parentNode, name, vars)) {
330
+ dom.remove(node, 1);
331
+ node = 0;
332
+ return TRUE;
333
+ }
334
+
335
// Look for parent with similar style format
336
+ if (format.merge_with_parents) {
337
+ dom.getParent(node.parentNode, function(parent) {
338
+ if (matchNode(parent, name, vars)) {
339
+ dom.remove(node, 1);
340
+ node = 0;
341
+ return TRUE;
342
+ }
343
+ });
344
+ }
345
346
// Merge next and previous siblings if they are similar <b>text</b><b>text</b> becomes <b>texttext</b>
347
if (node) {
359
rng.setStartBefore(node);
360
rng.setEndAfter(node);
361
362
+ applyRngStyle(expandRng(rng, formatList));
363
} else {
364
if (!selection.isCollapsed() || !format.inline) {
365
// Apply formatting to selection
476
var node = dom.get(start ? '_start' : '_end'),
477
out = node[start ? 'firstChild' : 'lastChild'];
478
479
+ // If the end is placed within the start the result will be removed
480
+ // So this checks if the out node is a bookmark node if it is it
481
+ // checks for another more suitable node
482
+ if (isBookmarkNode(out))
483
+ out = out[start ? 'firstChild' : 'lastChild'];
484
+
485
+ dom.remove(node, true);
486
487
return out;
488
};
545
};
546
547
/**
548
+ * Toggles the specified format on/off.
549
*
550
* @method toggle
551
* @param {String} name Name of format to apply/remove.
566
* @param {Node} node Node to check the format on.
567
* @param {String} name Format name to check.
568
* @param {Object} vars Optional list of variables to replace before checking it.
569
+ * @param {Boolean} similar Match format that has similar properties.
570
* @return {Object} Returns the format object it matches or undefined if it doesn't match.
571
*/
572
+ function matchNode(node, name, vars, similar) {
573
var formatList = get(name), format, i, classes;
574
575
function matchItems(node, format, item_name) {
586
else
587
value = getStyle(node, key);
588
589
+ if (similar && !value && !format.exact)
590
+ return;
591
+
592
+ if ((!similar || format.exact) && !isEq(value, replaceVars(items[key], vars)))
593
return;
594
}
595
}
627
};
628
629
/**
630
+ * Matches the current selection or specified node against the specified format name.
631
*
632
* @method match
633
* @param {String} name Name of format to match.
641
function matchParents(node) {
642
// Find first node with similar format settings
643
node = dom.getParent(node, function(node) {
644
+ return !!matchNode(node, name, vars, true);
645
});
646
647
// Do an exact check on the similar format element
788
* Checks if the specified nodes name matches the format inline/block or selector.
789
*
790
* @private
791
+ * @param {Node} node Node to match against the specified format.
792
* @param {Object} format Format object o match with.
793
* @return {boolean} true/false if the format matches.
794
*/
868
};
869
870
function isWhiteSpaceNode(node) {
871
+ return node && node.nodeType === 3 && /^([\s\r\n]+|)#x2F;.test(node.nodeValue);
872
};
873
874
function wrap(node, name, attrs) {
1066
* @param {Object} format Format object with items to remove from node.
1067
* @param {Object} vars Name/value object with variables to apply to format.
1068
* @param {Node} node Node to remove the format styles on.
1069
+ * @param {Node} compare_node Optional compare node, if specified the styles will be compared to that node.
1070
* @return {Boolean} True/false if the node was removed or not.
1071
*/
1072
function removeFormat(format, vars, node, compare_node) {
1276
*
1277
* @private
1278
* @param {Node} node1 First node to compare with.
1279
+ * @param {Node} node2 Second node to compare with.
1280
* @return {boolean} True/false if the nodes are the same or not.
1281
*/
1282
function compareElements(node1, node2) {
1405
* @return {boolean} True/false if the node is a text block.
1406
*/
1407
function isTextBlock(name) {
1408
+ return /^(h[1-6]|p|div|pre|address|dl|dt|dd)#x2F;.test(name);
1409
};
1410
1411
function getContainer(rng, start) {
1471
// Pending apply or remove formats
1472
if (hasPending()) {
1473
ed.getDoc().execCommand('FontName', false, 'mceinline');
1474
+ pendingFormats.lastRng = selection.getRng();
1475
1476
// IE will convert the current word
1477
each(dom.select('font,span'), function(node) {
1491
1492
each('onKeyDown,onKeyUp,onKeyPress,onMouseUp'.split(','), function(event) {
1493
ed[event].addToTop(function(ed, e) {
1494
+ // Do we have pending formats and is the selection moved has moved
1495
+ if (hasPending() && !tinymce.dom.RangeUtils.compareRanges(pendingFormats.lastRng, selection.getRng())) {
1496
each(dom.select('font,span'), function(node) {
1497
+ var textNode, rng;
1498
1499
// Look for marker
1500
if (isCaretNode(node)) {
1501
textNode = node.firstChild;
1502
1503
+ if (textNode) {
1504
+ perform(node);
1505
1506
+ rng = dom.createRng();
1507
+ rng.setStart(textNode, textNode.nodeValue.length);
1508
+ rng.setEnd(textNode, textNode.nodeValue.length);
1509
+ selection.setRng(rng);
1510
+ ed.nodeChanged();
1511
+ } else
1512
+ dom.remove(node);
1513
}
1514
});
1515
js/tiny_mce/classes/adapter/jquery/jquery.tinymce.js CHANGED
@@ -19,7 +19,7 @@
19
20
// No match then just ignore the call
21
if (!self.length)
22
- return;
23
24
// Get editor instance
25
if (!settings)
@@ -91,7 +91,8 @@
91
92
// Setup tinyMCEPreInit object this will later be used by the TinyMCE
93
// core script to locate other resources like CSS files, dialogs etc
94
- win.tinyMCEPreInit = {
95
base : base,
96
suffix : suffix,
97
query : query
@@ -143,6 +144,11 @@
143
success : function() {
144
tinymce.dom.Event.domLoaded = 1;
145
lazyLoading = 2;
146
init();
147
148
$.each(delayedInits, function(i, init) {
@@ -157,6 +163,8 @@
157
else
158
init();
159
}
160
};
161
162
// Add :tinymce psuedo selector this will select elements that has been converted into editor instances
@@ -242,20 +250,21 @@
242
var self = this;
243
244
if (!containsTinyMCE(self))
245
- return origFn.call(self, value);
246
247
if (value !== undefined) {
248
loadOrSave.call(self.filter(":tinymce"), value);
249
- origFn.call(self.not(":tinymce"), value);
250
251
return self; // return original set for chaining
252
} else {
253
var ret = "";
254
-
255
(textProc ? self : self.eq(0)).each(function(i, node) {
256
var ed = tinyMCEInstance(node);
257
258
- ret += ed ? (textProc ? ed.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g, "") : ed.getContent()) : origFn.call($(node), value);
259
});
260
261
return ret;
@@ -272,7 +281,7 @@
272
var self = this;
273
274
if (!containsTinyMCE(self))
275
- return origFn.call(self, value);
276
277
if (value !== undefined) {
278
self.filter(":tinymce").each(function(i, node) {
@@ -281,7 +290,7 @@
281
ed && ed.setContent(prepend ? value + ed.getContent() : ed.getContent() + value);
282
});
283
284
- origFn.call(self.not(":tinymce"), value);
285
286
return self; // return original set for chaining
287
}
19
20
// No match then just ignore the call
21
if (!self.length)
22
+ return self;
23
24
// Get editor instance
25
if (!settings)
91
92
// Setup tinyMCEPreInit object this will later be used by the TinyMCE
93
// core script to locate other resources like CSS files, dialogs etc
94
+ // You can also predefined a tinyMCEPreInit object and then it will use that instead
95
+ win.tinyMCEPreInit = win.tinyMCEPreInit || {
96
base : base,
97
suffix : suffix,
98
query : query
144
success : function() {
145
tinymce.dom.Event.domLoaded = 1;
146
lazyLoading = 2;
147
+
148
+ // Execute callback after mainscript has been loaded and before the initialization occurs
149
+ if (settings.script_loaded)
150
+ settings.script_loaded();
151
+
152
init();
153
154
$.each(delayedInits, function(i, init) {
163
else
164
init();
165
}
166
+
167
+ return self;
168
};
169
170
// Add :tinymce psuedo selector this will select elements that has been converted into editor instances
250
var self = this;
251
252
if (!containsTinyMCE(self))
253
+ return origFn.apply(self, arguments);
254
255
if (value !== undefined) {
256
loadOrSave.call(self.filter(":tinymce"), value);
257
+ origFn.apply(self.not(":tinymce"), arguments);
258
259
return self; // return original set for chaining
260
} else {
261
var ret = "";
262
+ var args = arguments;
263
+
264
(textProc ? self : self.eq(0)).each(function(i, node) {
265
var ed = tinyMCEInstance(node);
266
267
+ ret += ed ? (textProc ? ed.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g, "") : ed.getContent()) : origFn.apply($(node), args);
268
});
269
270
return ret;
281
var self = this;
282
283
if (!containsTinyMCE(self))
284
+ return origFn.apply(self, arguments);
285
286
if (value !== undefined) {
287
self.filter(":tinymce").each(function(i, node) {
290
ed && ed.setContent(prepend ? value + ed.getContent() : ed.getContent() + value);
291
});
292
293
+ origFn.apply(self.not(":tinymce"), arguments);
294
295
return self; // return original set for chaining
296
}
js/tiny_mce/classes/dom/DOMUtils.js CHANGED
@@ -441,7 +441,7 @@
441
if (keep_children) {
442
while (child = node.firstChild) {
443
// IE 8 will crash if you don't remove completely empty text nodes
444
- if (child.nodeType !== 3 || child.nodeValue)
445
parent.insertBefore(child, node);
446
else
447
node.removeChild(child);
@@ -512,7 +512,7 @@
512
* @method getStyle
513
* @param {String/Element} n HTML element or element id string to get style from.
514
* @param {String} na Style name to return.
515
- * @param {String} c Computed style.
516
* @return {String} Current style or computed style value of a element.
517
*/
518
getStyle : function(n, na, c) {
@@ -1226,7 +1226,7 @@
1226
// So if we replace the p elements with divs and mark them and then replace them back to paragraphs
1227
// after we use innerHTML we can fix the DOM tree
1228
h = h.replace(/<p ([^>]+)>|<p>/ig, '<div $1 _mce_tmp="1">');
1229
- h = h.replace(/<\/p>/g, '</div>');
1230
1231
// Set the new HTML with DIVs
1232
set();
@@ -1857,10 +1857,13 @@
1857
for (lastNodeType = node.nodeType, node = node.previousSibling, lastNode = node; node; node = node.previousSibling) {
1858
nodeType = node.nodeType;
1859
1860
- // Handle normalization of text nodes
1861
- if (!normalized || nodeType != 3 || (lastNodeType != nodeType && node.nodeValue.length))
1862
- idx++;
1863
1864
lastNodeType = nodeType;
1865
}
1866
}
441
if (keep_children) {
442
while (child = node.firstChild) {
443
// IE 8 will crash if you don't remove completely empty text nodes
444
+ if (!tinymce.isIE || child.nodeType !== 3 || child.nodeValue)
445
parent.insertBefore(child, node);
446
else
447
node.removeChild(child);
512
* @method getStyle
513
* @param {String/Element} n HTML element or element id string to get style from.
514
* @param {String} na Style name to return.
515
+ * @param {Boolean} c Computed style.
516
* @return {String} Current style or computed style value of a element.
517
*/
518
getStyle : function(n, na, c) {
1226
// So if we replace the p elements with divs and mark them and then replace them back to paragraphs
1227
// after we use innerHTML we can fix the DOM tree
1228
h = h.replace(/<p ([^>]+)>|<p>/ig, '<div $1 _mce_tmp="1">');
1229
+ h = h.replace(/<\/p>/gi, '</div>');
1230
1231
// Set the new HTML with DIVs
1232
set();
1857
for (lastNodeType = node.nodeType, node = node.previousSibling, lastNode = node; node; node = node.previousSibling) {
1858
nodeType = node.nodeType;
1859
1860
+ // Normalize text nodes
1861
+ if (normalized && nodeType == 3) {
1862
+ if (nodeType == lastNodeType || !node.nodeValue.length)
1863
+ continue;
1864
+ }
1865
1866
+ idx++;
1867
lastNodeType = nodeType;
1868
}
1869
}
js/tiny_mce/classes/dom/RangeUtils.js CHANGED
@@ -197,4 +197,32 @@
197
};
198
*/
199
};
200
})(tinymce);
197
};
198
*/
199
};
200
+
201
+ /**
202
+ * Compares two ranges and checks if they are equal.
203
+ *
204
+ * @static
205
+ * @param {DOMRange} rng1 First range to compare.
206
+ * @param {DOMRange} rng2 First range to compare.
207
+ * @return {Boolean} true/false if the ranges are equal.
208
+ */
209
+ tinymce.dom.RangeUtils.compareRanges = function(rng1, rng2) {
210
+ if (rng1 && rng2) {
211
+ // Compare native IE ranges
212
+ if (rng1.item || rng1.duplicate) {
213
+ // Both are control ranges and the selected element matches
214
+ if (rng1.item && rng2.item && rng1.item(0) === rng2.item(0))
215
+ return true;
216
+
217
+ // Both are text ranges and the range matches
218
+ if (rng1.isEqual && rng2.isEqual && rng2.isEqual(rng1))
219
+ return true;
220
+ } else {
221
+ // Compare w3c ranges
222
+ return rng1.startContainer == rng2.startContainer && rng1.startOffset == rng2.startOffset;
223
+ }
224
+ }
225
+
226
+ return false;
227
+ };
228
})(tinymce);
js/tiny_mce/classes/dom/Selection.js CHANGED
@@ -125,17 +125,21 @@
125
h += '<span id="__caret">_</span>';
126
127
// Delete and insert new node
128
- if (r.startContainer == d && r.endContainer == d) {
129
// WebKit will fail if the body is empty since the range is then invalid and it can't insert contents
130
d.body.innerHTML = h;
131
} else {
132
r.deleteContents();
133
- r.insertNode(t.getRng().createContextualFragment(h));
134
}
135
136
// Move to caret marker
137
c = t.dom.get('__caret');
138
-
139
// Make sure we wrap it compleatly, Opera fails with a simple select call
140
r = d.createRange();
141
r.setStartBefore(c);
@@ -166,30 +170,43 @@
166
* @return {Element} Start element of selection range.
167
*/
168
getStart : function() {
169
- var t = this, r = t.getRng(), e;
170
-
171
- if (r.duplicate || r.item) {
172
- if (r.item)
173
- return r.item(0);
174
175
- r = r.duplicate();
176
- r.collapse(1);
177
- e = r.parentElement();
178
179
- if (e && e.nodeName == 'BODY')
180
- return e.firstChild || e;
181
182
- return e;
183
} else {
184
- e = r.startContainer;
185
186
- if (e.nodeType == 1 && e.hasChildNodes())
187
- e = e.childNodes[Math.min(e.childNodes.length - 1, r.startOffset)];
188
189
- if (e && e.nodeType == 3)
190
- return e.parentNode;
191
192
- return e;
193
}
194
},
195
@@ -269,10 +286,10 @@
269
point.push(offset);
270
} else {
271
childNodes = container.childNodes;
272
-
273
- if (offset >= childNodes.length) {
274
after = 1;
275
- offset = childNodes.length - 1;
276
}
277
278
point.push(t.dom.nodeIndex(childNodes[offset], normalized) + after);
@@ -358,7 +375,7 @@
358
* @return {Boolean} true/false if it was successful or not.
359
*/
360
moveToBookmark : function(bookmark) {
361
- var t = this, dom = t.dom, marker1, marker2, rng, root;
362
363
// Clear selection cache
364
if (t.tridentSel)
@@ -370,12 +387,16 @@
370
root = dom.getRoot();
371
372
function setEndPoint(start) {
373
- var point = bookmark[start ? 'start' : 'end'], i, node, offset;
374
375
if (point) {
376
// Find container node
377
- for (node = root, i = point.length - 1; i >= 1; i--)
378
- node = node.childNodes[point[i]];
379
380
// Set offset within container node
381
if (start)
@@ -390,8 +411,6 @@
390
391
t.setRng(rng);
392
} else if (bookmark.id) {
393
- rng = dom.createRng();
394
-
395
function restoreEndPoint(suffix) {
396
var marker = dom.get(bookmark.id + '_' + suffix), node, idx, next, prev, keep = bookmark.keep;
397
@@ -402,21 +421,22 @@
402
if (!keep) {
403
idx = dom.nodeIndex(marker);
404
} else {
405
- node = marker;
406
idx = 1;
407
}
408
409
- rng.setStart(node, idx);
410
- rng.setEnd(node, idx);
411
} else {
412
if (!keep) {
413
idx = dom.nodeIndex(marker);
414
} else {
415
- node = marker;
416
idx = 1;
417
}
418
419
- rng.setEnd(node, idx);
420
}
421
422
if (!keep) {
@@ -441,19 +461,33 @@
441
dom.remove(next);
442
443
if (suffix == 'start') {
444
- rng.setStart(prev, idx);
445
- rng.setEnd(prev, idx);
446
- } else
447
- rng.setEnd(prev, idx);
448
}
449
}
450
}
451
};
452
453
// Restore start/end points
454
restoreEndPoint('start');
455
restoreEndPoint('end');
456
457
t.setRng(rng);
458
} else if (bookmark.name) {
459
t.select(dom.select(bookmark.name)[bookmark.index]);
@@ -591,6 +625,16 @@
591
if (!r)
592
r = t.win.document.createRange ? t.win.document.createRange() : t.win.document.body.createTextRange();
593
594
return r;
595
},
596
@@ -602,13 +646,15 @@
602
*/
603
setRng : function(r) {
604
var s, t = this;
605
-
606
if (!t.tridentSel) {
607
s = t.getSel();
608
609
if (s) {
610
s.removeAllRanges();
611
s.addRange(r);
612
}
613
} else {
614
// Is W3C Range
125
h += '<span id="__caret">_</span>';
126
127
// Delete and insert new node
128
+
129
+ if (r.startContainer == d && r.endContainer == d) {
130
// WebKit will fail if the body is empty since the range is then invalid and it can't insert contents
131
d.body.innerHTML = h;
132
} else {
133
r.deleteContents();
134
+ if (d.body.childNodes.length == 0) {
135
+ d.body.innerHTML = h;
136
+ } else {
137
+ r.insertNode(r.createContextualFragment(h));
138
+ }
139
}
140
141
// Move to caret marker
142
c = t.dom.get('__caret');
143
// Make sure we wrap it compleatly, Opera fails with a simple select call
144
r = d.createRange();
145
r.setStartBefore(c);
170
* @return {Element} Start element of selection range.
171
*/
172
getStart : function() {
173
+ var rng = this.getRng(), startElement, parentElement, checkRng, node;
174
175
+ if (rng.duplicate || rng.item) {
176
+ // Control selection, return first item
177
+ if (rng.item)
178
+ return rng.item(0);
179
+
180
+ // Get start element
181
+ checkRng = rng.duplicate();
182
+ checkRng.collapse(1);
183
+ startElement = checkRng.parentElement();
184
+
185
+ // Check if range parent is inside the start element, then return the inner parent element
186
+ // This will fix issues when a single element is selected, IE would otherwise return the wrong start element
187
+ parentElement = node = rng.parentElement();
188
+ while (node = node.parentNode) {
189
+ if (node == startElement) {
190
+ startElement = parentElement;
191
+ break;
192
+ }
193
+ }
194
195
+ // If start element is body element try to move to the first child if it exists
196
+ if (startElement && startElement.nodeName == 'BODY')
197
+ return startElement.firstChild || startElement;
198
199
+ return startElement;
200
} else {
201
+ startElement = rng.startContainer;
202
203
+ if (startElement.nodeType == 1 && startElement.hasChildNodes())
204
+ startElement = startElement.childNodes[Math.min(startElement.childNodes.length - 1, rng.startOffset)];
205
206
+ if (startElement && startElement.nodeType == 3)
207
+ return startElement.parentNode;
208
209
+ return startElement;
210
}
211
},
212
286
point.push(offset);
287
} else {
288
childNodes = container.childNodes;
289
+
290
+ if (offset >= childNodes.length && childNodes.length) {
291
after = 1;
292
+ offset = Math.max(0, childNodes.length - 1);
293
}
294
295
point.push(t.dom.nodeIndex(childNodes[offset], normalized) + after);
375
* @return {Boolean} true/false if it was successful or not.
376
*/
377
moveToBookmark : function(bookmark) {
378
+ var t = this, dom = t.dom, marker1, marker2, rng, root, startContainer, endContainer, startOffset, endOffset;
379
380
// Clear selection cache
381
if (t.tridentSel)
387
root = dom.getRoot();
388
389
function setEndPoint(start) {
390
+ var point = bookmark[start ? 'start' : 'end'], i, node, offset, children;
391
392
if (point) {
393
// Find container node
394
+ for (node = root, i = point.length - 1; i >= 1; i--) {
395
+ children = node.childNodes;
396
+
397
+ if (children.length)
398
+ node = children[point[i]];
399
+ }
400
401
// Set offset within container node
402
if (start)
411
412
t.setRng(rng);
413
} else if (bookmark.id) {
414
function restoreEndPoint(suffix) {
415
var marker = dom.get(bookmark.id + '_' + suffix), node, idx, next, prev, keep = bookmark.keep;
416
421
if (!keep) {
422
idx = dom.nodeIndex(marker);
423
} else {
424
+ node = marker.firstChild;
425
idx = 1;
426
}
427
428
+ startContainer = endContainer = node;
429
+ startOffset = endOffset = idx;
430
} else {
431
if (!keep) {
432
idx = dom.nodeIndex(marker);
433
} else {
434
+ node = marker.firstChild;
435
idx = 1;
436
}
437
438
+ endContainer = node;
439
+ endOffset = idx;
440
}
441
442
if (!keep) {
461
dom.remove(next);
462
463
if (suffix == 'start') {
464
+ startContainer = endContainer = prev;
465
+ startOffset = endOffset = idx;
466
+ } else {
467
+ endContainer = prev;
468
+ endOffset = idx;
469
+ }
470
}
471
}
472
}
473
};
474
475
+ function addBogus(node) {
476
+ // Adds a bogus BR element for empty block elements
477
+ // on non IE browsers just to have a place to put the caret
478
+ if (!isIE && dom.isBlock(node) && !node.innerHTML)
479
+ node.innerHTML = '<br _mce_bogus="1" />';
480
+
481
+ return node;
482
+ };
483
+
484
// Restore start/end points
485
restoreEndPoint('start');
486
restoreEndPoint('end');
487
488
+ rng = dom.createRng();
489
+ rng.setStart(addBogus(startContainer), startOffset);
490
+ rng.setEnd(addBogus(endContainer), endOffset);
491
t.setRng(rng);
492
} else if (bookmark.name) {
493
t.select(dom.select(bookmark.name)[bookmark.index]);
625
if (!r)
626
r = t.win.document.createRange ? t.win.document.createRange() : t.win.document.body.createTextRange();
627
628
+ if (t.selectedRange && t.explicitRange) {
629
+ if (r.compareBoundaryPoints(r.START_TO_START, t.selectedRange) === 0 && r.compareBoundaryPoints(r.END_TO_END, t.selectedRange) === 0) {
630
+ // Safari, Opera and Chrome only ever select text which causes the range to change.
631
+ // This lets us use the originally set range if the selection hasn't been changed by the user.
632
+ r = t.explicitRange;
633
+ } else {
634
+ t.selectedRange = null;
635
+ t.explicitRange = null;
636
+ }
637
+ }
638
return r;
639
},
640
646
*/
647
setRng : function(r) {
648
var s, t = this;
649
+
650
if (!t.tridentSel) {
651
s = t.getSel();
652
653
if (s) {
654
+ t.explicitRange = r;
655
s.removeAllRanges();
656
s.addRange(r);
657
+ t.selectedRange = s.getRangeAt(0);
658
}
659
} else {
660
// Is W3C Range
js/tiny_mce/classes/dom/Sizzle.js CHANGED
@@ -8,14 +8,26 @@
8
*/
9
(function(){
10
11
- var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
12
done = 0,
13
toString = Object.prototype.toString,
14
- hasDuplicate = false;
15
16
var Sizzle = function(selector, context, results, seed) {
17
results = results || [];
18
- var origContext = context = context || document;
19
20
if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
21
return [];
@@ -25,19 +37,25 @@ var Sizzle = function(selector, context, results, seed) {
25
return results;
26
}
27
28
- var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context);
29
30
// Reset the position of the chunker regexp (start from head)
31
- chunker.lastIndex = 0;
32
-
33
- while ( (m = chunker.exec(selector)) !== null ) {
34
- parts.push( m[1] );
35
36
- if ( m[2] ) {
37
- extra = RegExp.rightContext;
38
- break;
39
}
40
- }
41
42
if ( parts.length > 1 && origPOS.exec( selector ) ) {
43
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
@@ -50,9 +68,10 @@ var Sizzle = function(selector, context, results, seed) {
50
while ( parts.length ) {
51
selector = parts.shift();
52
53
- if ( Expr.relative[ selector ] )
54
selector += parts.shift();
55
-
56
set = posProcess( selector, set );
57
}
58
}
@@ -61,12 +80,12 @@ var Sizzle = function(selector, context, results, seed) {
61
// (but not if it'll be faster if the inner selector is an ID)
62
if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
63
Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
64
- var ret = Sizzle.find( parts.shift(), context, contextXML );
65
context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
66
}
67
68
if ( context ) {
69
- var ret = seed ?
70
{ expr: parts.pop(), set: makeArray(seed) } :
71
Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
72
set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
@@ -78,7 +97,8 @@ var Sizzle = function(selector, context, results, seed) {
78
}
79
80
while ( parts.length ) {
81
- var cur = parts.pop(), pop = cur;
82
83
if ( !Expr.relative[ cur ] ) {
84
cur = "";
@@ -102,20 +122,20 @@ var Sizzle = function(selector, context, results, seed) {
102
}
103
104
if ( !checkSet ) {
105
- throw "Syntax error, unrecognized expression: " + (cur || selector);
106
}
107
108
if ( toString.call(checkSet) === "[object Array]" ) {
109
if ( !prune ) {
110
results.push.apply( results, checkSet );
111
} else if ( context && context.nodeType === 1 ) {
112
- for ( var i = 0; checkSet[i] != null; i++ ) {
113
- if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
114
results.push( set[i] );
115
}
116
}
117
} else {
118
- for ( var i = 0; checkSet[i] != null; i++ ) {
119
if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
120
results.push( set[i] );
121
}
@@ -135,7 +155,7 @@ var Sizzle = function(selector, context, results, seed) {
135
136
Sizzle.uniqueSort = function(results){
137
if ( sortOrder ) {
138
- hasDuplicate = false;
139
results.sort(sortOrder);
140
141
if ( hasDuplicate ) {
@@ -146,6 +166,8 @@ Sizzle.uniqueSort = function(results){
146
}
147
}
148
}
149
};
150
151
Sizzle.matches = function(expr, set){
@@ -153,7 +175,7 @@ Sizzle.matches = function(expr, set){
153
};
154
155
Sizzle.find = function(expr, context, isXML){
156
- var set, match;
157
158
if ( !expr ) {
159
return [];
@@ -162,8 +184,9 @@ Sizzle.find = function(expr, context, isXML){
162
for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
163
var type = Expr.order[i], match;
164
165
- if ( (match = Expr.match[ type ].exec( expr )) ) {
166
- var left = RegExp.leftContext;
167
168
if ( left.substr( left.length - 1 ) !== "\\" ) {
169
match[1] = (match[1] || "").replace(/\\/g, "");
@@ -185,15 +208,21 @@ Sizzle.find = function(expr, context, isXML){
185
186
Sizzle.filter = function(expr, set, inplace, not){
187
var old = expr, result = [], curLoop = set, match, anyFound,
188
- isXMLFilter = set && set[0] && isXML(set[0]);
189
190
while ( expr && set.length ) {
191
for ( var type in Expr.filter ) {
192
- if ( (match = Expr.match[ type ].exec( expr )) != null ) {
193
- var filter = Expr.filter[ type ], found, item;
194
anyFound = false;
195
196
- if ( curLoop == result ) {
197
result = [];
198
}
199
@@ -244,9 +273,9 @@ Sizzle.filter = function(expr, set, inplace, not){
244
}
245
246
// Improper expression
247
- if ( expr == old ) {
248
if ( anyFound == null ) {
249
- throw "Syntax error, unrecognized expression: " + expr;
250
} else {
251
break;
252
}
@@ -258,18 +287,23 @@ Sizzle.filter = function(expr, set, inplace, not){
258
return curLoop;
259
};
260
261
var Expr = Sizzle.selectors = {
262
order: [ "ID", "NAME", "TAG" ],
263
match: {
264
- ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
265
- CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
266
- NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
267
- ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
268
- TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
269
- CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
270
- POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
271
- PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
272
},
273
attrMap: {
274
"class": "className",
275
"for": "htmlFor"
@@ -280,20 +314,20 @@ var Expr = Sizzle.selectors = {
280
}
281
},
282
relative: {
283
- "+": function(checkSet, part, isXML){
284
var isPartStr = typeof part === "string",
285
isTag = isPartStr && !/\W/.test(part),
286
isPartStrNotTag = isPartStr && !isTag;
287
288
- if ( isTag && !isXML ) {
289
- part = part.toUpperCase();
290
}
291
292
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
293
if ( (elem = checkSet[i]) ) {
294
while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
295
296
- checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
297
elem || false :
298
elem === part;
299
}
@@ -303,22 +337,23 @@ var Expr = Sizzle.selectors = {
303
Sizzle.filter( part, checkSet, true );
304
}
305
},
306
- ">": function(checkSet, part, isXML){
307
- var isPartStr = typeof part === "string";
308
309
if ( isPartStr && !/\W/.test(part) ) {
310
- part = isXML ? part : part.toUpperCase();
311
312
- for ( var i = 0, l = checkSet.length; i < l; i++ ) {
313
- var elem = checkSet[i];
314
if ( elem ) {
315
var parent = elem.parentNode;
316
- checkSet[i] = parent.nodeName === part ? parent : false;
317
}
318
}
319
} else {
320
- for ( var i = 0, l = checkSet.length; i < l; i++ ) {
321
- var elem = checkSet[i];
322
if ( elem ) {
323
checkSet[i] = isPartStr ?
324
elem.parentNode :
@@ -332,20 +367,22 @@ var Expr = Sizzle.selectors = {
332
}
333
},
334
"": function(checkSet, part, isXML){
335
- var doneName = done++, checkFn = dirCheck;
336
337
- if ( !part.match(/\W/) ) {
338
- var nodeCheck = part = isXML ? part : part.toUpperCase();
339
checkFn = dirNodeCheck;
340
}
341
342
checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
343
},
344
"~": function(checkSet, part, isXML){
345
- var doneName = done++, checkFn = dirCheck;
346
347
- if ( typeof part === "string" && !part.match(/\W/) ) {
348
- var nodeCheck = part = isXML ? part : part.toUpperCase();
349
checkFn = dirNodeCheck;
350
}
351
@@ -359,7 +396,7 @@ var Expr = Sizzle.selectors = {
359
return m ? [m] : [];
360
}
361
},
362
- NAME: function(match, context, isXML){
363
if ( typeof context.getElementsByName !== "undefined" ) {
364
var ret = [], results = context.getElementsByName(match[1]);
365
@@ -386,9 +423,10 @@ var Expr = Sizzle.selectors = {
386
387
for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
388
if ( elem ) {
389
- if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
390
- if ( !inplace )
391
result.push( elem );
392
} else if ( inplace ) {
393
curLoop[i] = false;
394
}
@@ -401,14 +439,13 @@ var Expr = Sizzle.selectors = {
401
return match[1].replace(/\\/g, "");
402
},
403
TAG: function(match, curLoop){
404
- for ( var i = 0; curLoop[i] === false; i++ ){}
405
- return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
406
},
407
CHILD: function(match){
408
- if ( match[1] == "nth" ) {
409
// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
410
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
411
- match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
412
!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
413
414
// calculate the numbers (first)n+(last) including if they are negative
@@ -437,7 +474,7 @@ var Expr = Sizzle.selectors = {
437
PSEUDO: function(match, curLoop, inplace, result, not){
438
if ( match[1] === "not" ) {
439
// If we're dealing with a complex expression, or a simple one
440
- if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) {
441
match[3] = Sizzle(match[3], null, null, curLoop);
442
} else {
443
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
@@ -483,7 +520,7 @@ var Expr = Sizzle.selectors = {
483
return !!Sizzle( match[3], elem ).length;
484
},
485
header: function(elem){
486
- return /h\d/i.test( elem.nodeName );
487
},
488
text: function(elem){
489
return "text" === elem.type;
@@ -510,10 +547,10 @@ var Expr = Sizzle.selectors = {
510
return "reset" === elem.type;
511
},
512
button: function(elem){
513
- return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
514
},
515
input: function(elem){
516
- return /input|select|textarea|button/i.test(elem.nodeName);
517
}
518
},
519
setFilters: {
@@ -536,10 +573,10 @@ var Expr = Sizzle.selectors = {
536
return i > match[3] - 0;
537
},
538
nth: function(elem, i, match){
539
- return match[3] - 0 == i;
540
},
541
eq: function(elem, i, match){
542
- return match[3] - 0 == i;
543
}
544
},
545
filter: {
@@ -549,17 +586,19 @@ var Expr = Sizzle.selectors = {
549
if ( filter ) {
550
return filter( elem, i, match, array );
551
} else if ( name === "contains" ) {
552
- return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
553
} else if ( name === "not" ) {
554
var not = match[3];
555
556
- for ( var i = 0, l = not.length; i < l; i++ ) {
557
- if ( not[i] === elem ) {
558
return false;
559
}
560
}
561
562
return true;
563
}
564
},
565
CHILD: function(elem, match){
@@ -567,20 +606,26 @@ var Expr = Sizzle.selectors = {
567
switch (type) {
568
case 'only':
569
case 'first':
570
- while (node = node.previousSibling) {
571
- if ( node.nodeType === 1 ) return false;
572
}
573
- if ( type == 'first') return true;
574
node = elem;
575
case 'last':
576
- while (node = node.nextSibling) {
577
- if ( node.nodeType === 1 ) return false;
578
}
579
return true;
580
case 'nth':
581
var first = match[2], last = match[3];
582
583
- if ( first == 1 && last == 0 ) {
584
return true;
585
}
586
@@ -598,10 +643,10 @@ var Expr = Sizzle.selectors = {
598
}
599
600
var diff = elem.nodeIndex - last;
601
- if ( first == 0 ) {
602
- return diff == 0;
603
} else {
604
- return ( diff % first == 0 && diff / first >= 0 );
605
}
606
}
607
},
@@ -609,7 +654,7 @@ var Expr = Sizzle.selectors = {
609
return elem.nodeType === 1 && elem.getAttribute("id") === match;
610
},
611
TAG: function(elem, match){
612
- return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
613
},
614
CLASS: function(elem, match){
615
return (" " + (elem.className || elem.getAttribute("class")) + " ")
@@ -637,7 +682,7 @@ var Expr = Sizzle.selectors = {
637
!check ?
638
value && result !== false :
639
type === "!=" ?
640
- value != check :
641
type === "^=" ?
642
value.indexOf(check) === 0 :
643
type === "$=" ?
@@ -656,14 +701,18 @@ var Expr = Sizzle.selectors = {
656
}
657
};
658
659
- var origPOS = Expr.match.POS;
660
661
for ( var type in Expr.match ) {
662
- Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
663
}
664
665
var makeArray = function(array, results) {
666
- array = Array.prototype.slice.call( array );
667
668
if ( results ) {
669
results.push.apply( results, array );
@@ -675,23 +724,25 @@ var makeArray = function(array, results) {
675
676
// Perform a simple check to determine if the browser is capable of
677
// converting a NodeList to an array using builtin methods.
678
try {
679
- Array.prototype.slice.call( document.documentElement.childNodes );
680
681
// Provide a fallback method if it does not work
682
} catch(e){
683
makeArray = function(array, results) {
684
- var ret = results || [];
685
686
if ( toString.call(array) === "[object Array]" ) {
687
Array.prototype.push.apply( ret, array );
688
} else {
689
if ( typeof array.length === "number" ) {
690
- for ( var i = 0, l = array.length; i < l; i++ ) {
691
ret.push( array[i] );
692
}
693
} else {
694
- for ( var i = 0; array[i]; i++ ) {
695
ret.push( array[i] );
696
}
697
}
@@ -705,6 +756,13 @@ var sortOrder;
705
706
if ( document.documentElement.compareDocumentPosition ) {
707
sortOrder = function( a, b ) {
708
var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
709
if ( ret === 0 ) {
710
hasDuplicate = true;
@@ -713,6 +771,13 @@ if ( document.documentElement.compareDocumentPosition ) {
713
};
714
} else if ( "sourceIndex" in document.documentElement ) {
715
sortOrder = function( a, b ) {
716
var ret = a.sourceIndex - b.sourceIndex;
717
if ( ret === 0 ) {
718
hasDuplicate = true;
@@ -721,6 +786,13 @@ if ( document.documentElement.compareDocumentPosition ) {
721
};
722
} else if ( document.createRange ) {
723
sortOrder = function( a, b ) {
724
var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
725
aRange.setStart(a, 0);
726
aRange.setEnd(a, 0);
@@ -734,12 +806,32 @@ if ( document.documentElement.compareDocumentPosition ) {
734
};
735
}
736
737
// Check to see if the browser returns elements by name when
738
// querying by getElementById (and provide a workaround)
739
(function(){
740
// We're going to inject a fake input element with a specified name
741
var form = document.createElement("div"),
742
- id = "script" + (new Date).getTime();
743
form.innerHTML = "<a name='" + id + "'/>";
744
745
// Inject it into the root element, check its status, and remove it quickly
@@ -748,7 +840,7 @@ if ( document.documentElement.compareDocumentPosition ) {
748
749
// The workaround has to do additional checks after a getElementById
750
// Which slows things down for other browsers (hence the branching)
751
- if ( !!document.getElementById( id ) ) {
752
Expr.find.ID = function(match, context, isXML){
753
if ( typeof context.getElementById !== "undefined" && !isXML ) {
754
var m = context.getElementById(match[1]);
@@ -763,6 +855,7 @@ if ( document.documentElement.compareDocumentPosition ) {
763
}
764
765
root.removeChild( form );
766
})();
767
768
(function(){
@@ -803,68 +896,75 @@ if ( document.documentElement.compareDocumentPosition ) {
803
return elem.getAttribute("href", 2);
804
};
805
}
806
})();
807
808
- if ( document.querySelectorAll ) (function(){
809
- var oldSizzle = Sizzle, div = document.createElement("div");
810
- div.innerHTML = "<p class='TEST'></p>";
811
812
- // Safari can't handle uppercase or unicode characters when
813
- // in quirks mode.
814
- if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
815
- return;
816
- }
817
-
818
- Sizzle = function(query, context, extra, seed){
819
- context = context || document;
820
-
821
- // Only use querySelectorAll on non-XML documents
822
- // (ID selectors don't work in non-HTML documents)
823
- if ( !seed && context.nodeType === 9 && !isXML(context) ) {
824
- try {
825
- return makeArray( context.querySelectorAll(query), extra );
826
- } catch(e){}
827
}
828
829
- return oldSizzle(query, context, extra, seed);
830
- };
831
832
- for ( var prop in oldSizzle ) {
833
- Sizzle[ prop ] = oldSizzle[ prop ];
834
- }
835
- })();
836
837
- if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
838
var div = document.createElement("div");
839
div.innerHTML = "<div class='test e'></div><div class='test'></div>";
840
841
// Opera can't find a second classname (in 9.6)
842
- if ( div.getElementsByClassName("e").length === 0 )
843
return;
844
845
// Safari caches class attributes, doesn't catch changes (in 3.2)
846
div.lastChild.className = "e";
847
848
- if ( div.getElementsByClassName("e").length === 1 )
849
return;
850
-
851
Expr.order.splice(1, 0, "CLASS");
852
Expr.find.CLASS = function(match, context, isXML) {
853
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
854
return context.getElementsByClassName(match[1]);
855
}
856
};
857
})();
858
859
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
860
- var sibDir = dir == "previousSibling" && !isXML;
861
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
862
var elem = checkSet[i];
863
if ( elem ) {
864
- if ( sibDir && elem.nodeType === 1 ){
865
- elem.sizcache = doneName;
866
- elem.sizset = i;
867
- }
868
elem = elem[dir];
869
var match = false;
870
@@ -879,7 +979,7 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
879
elem.sizset = i;
880
}
881
882
- if ( elem.nodeName === cur ) {
883
match = elem;
884
break;
885
}
@@ -893,14 +993,9 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
893
}
894
895
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
896
- var sibDir = dir == "previousSibling" && !isXML;
897
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
898
var elem = checkSet[i];
899
if ( elem ) {
900
- if ( sibDir && elem.nodeType === 1 ) {
901
- elem.sizcache = doneName;
902
- elem.sizset = i;
903
- }
904
elem = elem[dir];
905
var match = false;
906
@@ -935,15 +1030,17 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
935
}
936
}
937
938
- var contains = document.compareDocumentPosition ? function(a, b){
939
- return a.compareDocumentPosition(b) & 16;
940
} : function(a, b){
941
return a !== b && (a.contains ? a.contains(b) : true);
942
};
943
944
- var isXML = function(elem){
945
- return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
946
- !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
947
};
948
949
var posProcess = function(selector, context){
8
*/
9
(function(){
10
11
+ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
12
done = 0,
13
toString = Object.prototype.toString,
14
+ hasDuplicate = false,
15
+ baseHasDuplicate = true;
16
+
17
+ // Here we check if the JavaScript engine is using some sort of
18
+ // optimization where it does not always call our comparision
19
+ // function. If that is the case, discard the hasDuplicate value.
20
+ // Thus far that includes Google Chrome.
21
+ [0, 0].sort(function(){
22
+ baseHasDuplicate = false;
23
+ return 0;
24
+ });
25
26
var Sizzle = function(selector, context, results, seed) {
27
results = results || [];
28
+ context = context || document;
29
+
30
+ var origContext = context;
31
32
if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
33
return [];
37
return results;
38
}
39
40
+ var parts = [], m, set, checkSet, extra, prune = true, contextXML = Sizzle.isXML(context),
41
+ soFar = selector, ret, cur, pop, i;
42
43
// Reset the position of the chunker regexp (start from head)
44
+ do {
45
+ chunker.exec("");
46
+ m = chunker.exec(soFar);
47
+
48
+ if ( m ) {
49
+ soFar = m[3];
50
+
51
+ parts.push( m[1] );
52
53
+ if ( m[2] ) {
54
+ extra = m[3];
55
+ break;
56
+ }
57
}
58
+ } while ( m );
59
60
if ( parts.length > 1 && origPOS.exec( selector ) ) {
61
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
68
while ( parts.length ) {
69
selector = parts.shift();
70
71
+ if ( Expr.relative[ selector ] ) {
72
selector += parts.shift();
73
+ }
74
+
75
set = posProcess( selector, set );
76
}
77
}
80
// (but not if it'll be faster if the inner selector is an ID)
81
if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
82
Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
83
+ ret = Sizzle.find( parts.shift(), context, contextXML );
84
context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
85
}
86
87
if ( context ) {
88
+ ret = seed ?
89
{ expr: parts.pop(), set: makeArray(seed) } :
90
Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
91
set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
97
}
98
99
while ( parts.length ) {
100
+ cur = parts.pop();
101
+ pop = cur;
102
103
if ( !Expr.relative[ cur ] ) {
104
cur = "";
122
}
123
124
if ( !checkSet ) {
125
+ Sizzle.error( cur || selector );
126
}
127
128
if ( toString.call(checkSet) === "[object Array]" ) {
129
if ( !prune ) {
130
results.push.apply( results, checkSet );
131
} else if ( context && context.nodeType === 1 ) {
132
+ for ( i = 0; checkSet[i] != null; i++ ) {
133
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
134
results.push( set[i] );
135
}
136
}
137
} else {
138
+ for ( i = 0; checkSet[i] != null; i++ ) {
139
if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
140
results.push( set[i] );
141
}
155
156
Sizzle.uniqueSort = function(results){
157
if ( sortOrder ) {
158
+ hasDuplicate = baseHasDuplicate;
159
results.sort(sortOrder);
160
161
if ( hasDuplicate ) {
166
}
167
}
168
}
169
+
170
+ return results;
171
};
172
173
Sizzle.matches = function(expr, set){
175
};
176
177
Sizzle.find = function(expr, context, isXML){
178
+ var set;
179
180
if ( !expr ) {
181
return [];
184
for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
185
var type = Expr.order[i], match;
186
187
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
188
+ var left = match[1];
189
+ match.splice(1,1);
190
191
if ( left.substr( left.length - 1 ) !== "\\" ) {
192
match[1] = (match[1] || "").replace(/\\/g, "");
208
209
Sizzle.filter = function(expr, set, inplace, not){
210
var old = expr, result = [], curLoop = set, match, anyFound,
211
+ isXMLFilter = set && set[0] && Sizzle.isXML(set[0]);
212
213
while ( expr && set.length ) {
214
for ( var type in Expr.filter ) {
215
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
216
+ var filter = Expr.filter[ type ], found, item, left = match[1];
217
anyFound = false;
218
219
+ match.splice(1,1);
220
+
221
+ if ( left.substr( left.length - 1 ) === "\\" ) {
222
+ continue;
223
+ }
224
+
225
+ if ( curLoop === result ) {
226
result = [];
227
}
228
273
}
274
275
// Improper expression
276
+ if ( expr === old ) {
277
if ( anyFound == null ) {
278
+ Sizzle.error( expr );
279
} else {
280
break;
281
}
287
return curLoop;
288
};
289
290
+ Sizzle.error = function( msg ) {
291
+ throw "Syntax error, unrecognized expression: " + msg;
292
+ };
293
+
294
var Expr = Sizzle.selectors = {
295
order: [ "ID", "NAME", "TAG" ],
296
match: {
297
+ ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
298
+ CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
299
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
300
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
301
+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
302
+ CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
303
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
304
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
305
},
306
+ leftMatch: {},
307
attrMap: {
308
"class": "className",
309
"for": "htmlFor"
314
}
315
},
316
relative: {
317
+ "+": function(checkSet, part){
318
var isPartStr = typeof part === "string",
319
isTag = isPartStr && !/\W/.test(part),
320
isPartStrNotTag = isPartStr && !isTag;
321
322
+ if ( isTag ) {
323
+ part = part.toLowerCase();
324
}
325
326
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
327
if ( (elem = checkSet[i]) ) {
328
while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
329
330
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
331
elem || false :
332
elem === part;
333
}
337
Sizzle.filter( part, checkSet, true );
338
}
339
},
340
+ ">": function(checkSet, part){
341
+ var isPartStr = typeof part === "string",
342
+ elem, i = 0, l = checkSet.length;
343
344
if ( isPartStr && !/\W/.test(part) ) {
345
+ part = part.toLowerCase();
346
347
+ for ( ; i < l; i++ ) {
348
+ elem = checkSet[i];
349
if ( elem ) {
350
var parent = elem.parentNode;
351
+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
352
}
353
}
354
} else {
355
+ for ( ; i < l; i++ ) {
356
+ elem = checkSet[i];
357
if ( elem ) {
358
checkSet[i] = isPartStr ?
359
elem.parentNode :
367
}
368
},
369
"": function(checkSet, part, isXML){
370
+ var doneName = done++, checkFn = dirCheck, nodeCheck;
371
372
+ if ( typeof part === "string" && !/\W/.test(part) ) {
373
+ part = part.toLowerCase();
374
+ nodeCheck = part;
375
checkFn = dirNodeCheck;
376
}
377
378
checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
379
},
380
"~": function(checkSet, part, isXML){
381
+ var doneName = done++, checkFn = dirCheck, nodeCheck;
382
383
+ if ( typeof part === "string" && !/\W/.test(part) ) {
384
+ part = part.toLowerCase();
385
+ nodeCheck = part;
386
checkFn = dirNodeCheck;
387
}
388
396
return m ? [m] : [];
397
}
398
},
399
+ NAME: function(match, context){
400
if ( typeof context.getElementsByName !== "undefined" ) {
401
var ret = [], results = context.getElementsByName(match[1]);
402
423
424
for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
425
if ( elem ) {
426
+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
427
+ if ( !inplace ) {
428
result.push( elem );
429
+ }
430
} else if ( inplace ) {
431
curLoop[i] = false;
432
}
439
return match[1].replace(/\\/g, "");
440
},
441
TAG: function(match, curLoop){
442
+ return match[1].toLowerCase();
443
},
444
CHILD: function(match){
445
+ if ( match[1] === "nth" ) {
446
// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
447
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
448
+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
449
!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
450
451
// calculate the numbers (first)n+(last) including if they are negative
474
PSEUDO: function(match, curLoop, inplace, result, not){
475
if ( match[1] === "not" ) {
476
// If we're dealing with a complex expression, or a simple one
477
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
478
match[3] = Sizzle(match[3], null, null, curLoop);
479
} else {
480
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
520
return !!Sizzle( match[3], elem ).length;
521
},
522
header: function(elem){
523
+ return (/h\d/i).test( elem.nodeName );
524
},
525
text: function(elem){
526
return "text" === elem.type;
547
return "reset" === elem.type;
548
},
549
button: function(elem){
550
+ return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
551
},
552
input: function(elem){
553
+ return (/input|select|textarea|button/i).test(elem.nodeName);
554
}
555
},
556
setFilters: {
573
return i > match[3] - 0;
574
},
575
nth: function(elem, i, match){
576
+ return match[3] - 0 === i;
577
},
578
eq: function(elem, i, match){
579
+ return match[3] - 0 === i;
580
}
581
},
582
filter: {
586
if ( filter ) {
587
return filter( elem, i, match, array );
588
} else if ( name === "contains" ) {
589
+ return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
590
} else if ( name === "not" ) {
591
var not = match[3];
592
593
+ for ( var j = 0, l = not.length; j < l; j++ ) {
594
+ if ( not[j] === elem ) {
595
return false;
596
}
597
}
598
599
return true;
600
+ } else {
601
+ Sizzle.error( "Syntax error, unrecognized expression: " + name );
602
}
603
},
604
CHILD: function(elem, match){
606
switch (type) {
607
case 'only':
608
case 'first':
609
+ while ( (node = node.previousSibling) ) {
610
+ if ( node.nodeType === 1 ) {
611
+ return false;
612
+ }
613
+ }
614
+ if ( type === "first" ) {
615
+ return true;
616
}
617
node = elem;
618
case 'last':
619
+ while ( (node = node.nextSibling) ) {
620
+ if ( node.nodeType === 1 ) {
621
+ return false;
622
+ }
623
}
624
return true;
625
case 'nth':
626
var first = match[2], last = match[3];
627
628
+ if ( first === 1 && last === 0 ) {
629
return true;
630
}
631
643
}
644
645
var diff = elem.nodeIndex - last;
646
+ if ( first === 0 ) {
647
+ return diff === 0;
648
} else {
649
+ return ( diff % first === 0 && diff / first >= 0 );
650
}
651
}
652
},
654
return elem.nodeType === 1 && elem.getAttribute("id") === match;
655
},
656
TAG: function(elem, match){
657
+ return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
658
},
659
CLASS: function(elem, match){
660
return (" " + (elem.className || elem.getAttribute("class")) + " ")
682
!check ?
683
value && result !== false :
684
type === "!=" ?
685
+ value !== check :
686
type === "^=" ?
687
value.indexOf(check) === 0 :
688
type === "$=" ?
701
}
702
};
703
704
+ var origPOS = Expr.match.POS,
705
+ fescape = function(all, num){
706
+ return "\\" + (num - 0 + 1);
707
+ };
708
709
for ( var type in Expr.match ) {
710
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
711
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
712
}
713
714
var makeArray = function(array, results) {
715
+ array = Array.prototype.slice.call( array, 0 );
716
717
if ( results ) {
718
results.push.apply( results, array );
724
725
// Perform a simple check to determine if the browser is capable of
726
// converting a NodeList to an array using builtin methods.
727
+ // Also verifies that the returned array holds DOM nodes
728
+ // (which is not the case in the Blackberry browser)
729
try {
730
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
731
732
// Provide a fallback method if it does not work
733
} catch(e){
734
makeArray = function(array, results) {
735
+ var ret = results || [], i = 0;
736
737
if ( toString.call(array) === "[object Array]" ) {
738
Array.prototype.push.apply( ret, array );
739
} else {
740
if ( typeof array.length === "number" ) {
741
+ for ( var l = array.length; i < l; i++ ) {
742
ret.push( array[i] );
743
}
744
} else {
745
+ for ( ; array[i]; i++ ) {
746
ret.push( array[i] );
747
}
748
}
756
757
if ( document.documentElement.compareDocumentPosition ) {
758
sortOrder = function( a, b ) {
759
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
760
+ if ( a == b ) {
761
+ hasDuplicate = true;
762
+ }
763
+ return a.compareDocumentPosition ? -1 : 1;
764
+ }
765
+
766
var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
767
if ( ret === 0 ) {
768
hasDuplicate = true;
771
};
772
} else if ( "sourceIndex" in document.documentElement ) {
773
sortOrder = function( a, b ) {
774
+ if ( !a.sourceIndex || !b.sourceIndex ) {
775
+ if ( a == b ) {
776
+ hasDuplicate = true;
777
+ }
778
+ return a.sourceIndex ? -1 : 1;
779
+ }
780
+
781
var ret = a.sourceIndex - b.sourceIndex;
782
if ( ret === 0 ) {
783
hasDuplicate = true;
786
};
787
} else if ( document.createRange ) {
788
sortOrder = function( a, b ) {
789
+ if ( !a.ownerDocument || !b.ownerDocument ) {
790
+ if ( a == b ) {
791
+ hasDuplicate = true;
792
+ }
793
+ return a.ownerDocument ? -1 : 1;
794
+ }
795
+
796
var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
797
aRange.setStart(a, 0);
798
aRange.setEnd(a, 0);
806
};
807
}
808
809
+ // Utility function for retreiving the text value of an array of DOM nodes
810
+ Sizzle.getText = function( elems ) {
811
+ var ret = "", elem;
812
+
813
+ for ( var i = 0; elems[i]; i++ ) {
814
+ elem = elems[i];
815
+
816
+ // Get the text from text nodes and CDATA nodes
817
+ if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
818
+ ret += elem.nodeValue;
819
+
820
+ // Traverse everything else, except comment nodes
821
+ } else if ( elem.nodeType !== 8 ) {
822
+ ret += Sizzle.getText( elem.childNodes );
823
+ }
824
+ }
825
+
826
+ return ret;
827
+ };
828
+
829
// Check to see if the browser returns elements by name when
830
// querying by getElementById (and provide a workaround)
831
(function(){
832
// We're going to inject a fake input element with a specified name
833
var form = document.createElement("div"),
834
+ id = "script" + (new Date()).getTime();
835
form.innerHTML = "<a name='" + id + "'/>";
836
837
// Inject it into the root element, check its status, and remove it quickly
840
841
// The workaround has to do additional checks after a getElementById
842
// Which slows things down for other browsers (hence the branching)
843
+ if ( document.getElementById( id ) ) {
844
Expr.find.ID = function(match, context, isXML){
845
if ( typeof context.getElementById !== "undefined" && !isXML ) {
846
var m = context.getElementById(match[1]);
855
}
856
857
root.removeChild( form );
858
+ root = form = null; // release memory in IE
859
})();
860
861
(function(){
896
return elem.getAttribute("href", 2);
897
};
898
}
899
+
900
+ div = null; // release memory in IE
901
})();
902
903
+ if ( document.querySelectorAll ) {
904
+ (function(){
905
+ var oldSizzle = Sizzle, div = document.createElement("div");
906
+ div.innerHTML = "<p class='TEST'></p>";
907
908
+ // Safari can't handle uppercase or unicode characters when
909
+ // in quirks mode.
910
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
911
+ return;
912
}
913
+
914
+ Sizzle = function(query, context, extra, seed){
915
+ context = context || document;
916
+
917
+ // Only use querySelectorAll on non-XML documents
918
+ // (ID selectors don't work in non-HTML documents)
919
+ if ( !seed && context.nodeType === 9 && !Sizzle.isXML(context) ) {
920
+ try {
921
+ return makeArray( context.querySelectorAll(query), extra );
922
+ } catch(e){}
923
+ }
924
925
+ return oldSizzle(query, context, extra, seed);
926
+ };
927
928
+ for ( var prop in oldSizzle ) {
929
+ Sizzle[ prop ] = oldSizzle[ prop ];
930
+ }
931
932
+ div = null; // release memory in IE
933
+ })();
934
+ }
935
+
936
+ (function(){
937
var div = document.createElement("div");
938
+
939
div.innerHTML = "<div class='test e'></div><div class='test'></div>";
940
941
// Opera can't find a second classname (in 9.6)
942
+ // Also, make sure that getElementsByClassName actually exists
943
+ if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
944
return;
945
+ }
946
947
// Safari caches class attributes, doesn't catch changes (in 3.2)
948
div.lastChild.className = "e";
949
950
+ if ( div.getElementsByClassName("e").length === 1 ) {
951
return;
952
+ }
953
+
954
Expr.order.splice(1, 0, "CLASS");
955
Expr.find.CLASS = function(match, context, isXML) {
956
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
957
return context.getElementsByClassName(match[1]);
958
}
959
};
960
+
961
+ div = null; // release memory in IE
962
})();
963
964
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
965
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
966
var elem = checkSet[i];
967
if ( elem ) {
968
elem = elem[dir];
969
var match = false;
970
979
elem.sizset = i;
980
}
981
982
+ if ( elem.nodeName.toLowerCase() === cur ) {
983
match = elem;
984
break;
985
}
993
}
994
995
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
996
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
997
var elem = checkSet[i];
998
if ( elem ) {
999
elem = elem[dir];
1000
var match = false;
1001
1030
}
1031
}
1032
1033
+ Sizzle.contains = document.compareDocumentPosition ? function(a, b){
1034
+ return !!(a.compareDocumentPosition(b) & 16);
1035
} : function(a, b){
1036
return a !== b && (a.contains ? a.contains(b) : true);
1037
};
1038
1039
+ Sizzle.isXML = function(elem){
1040
+ // documentElement is verified for cases where it doesn't yet exist
1041
+ // (such as loading iframes in IE - #4833)
1042
+ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
1043
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
1044
};
1045
1046
var posProcess = function(selector, context){
js/tiny_mce/classes/dom/TridentSelection.js CHANGED
@@ -12,35 +12,9 @@
12
function Selection(selection) {
13
var t = this, invisibleChar = '\uFEFF', range, lastIERng, dom = selection.dom, TRUE = true, FALSE = false;
14
15
- // Compares two IE specific ranges to see if they are different
16
- // this method is useful when invalidating the cached selection range
17
- function compareRanges(rng1, rng2) {
18
- if (rng1 && rng2) {
19
- // Both are control ranges and the selected element matches
20
- if (rng1.item && rng2.item && rng1.item(0) === rng2.item(0))
21
- return TRUE;
22
-
23
- // Both are text ranges and the range matches
24
- if (rng1.isEqual && rng2.isEqual && rng2.isEqual(rng1)) {
25
- // IE will say that the range is equal then produce an invalid argument exception
26
- // if you perform specific operations in a keyup event. For example Ctrl+Del.
27
- // This hack will invalidate the range cache if the exception occurs
28
- try {
29
- // Try accessing nextSibling will producer an invalid argument some times
30
- range.startContainer.nextSibling;
31
- return TRUE;
32
- } catch (ex) {
33
- // Ignore
34
- }
35
- }
36
- }
37
-
38
- return FALSE;
39
- };
40
-
41
// Returns a W3C DOM compatible range object by using the IE Range API
42
function getRange() {
43
- var ieRange = selection.getRng(), domRange = dom.createRng(), ieRange2, element, collapsed, isMerged;
44
45
// If selection is outside the current document just return an empty range
46
element = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
@@ -55,84 +29,96 @@
55
return domRange;
56
}
57
58
- // Duplicare IE selection range and check if the range is collapsed
59
- ieRange2 = ieRange.duplicate();
60
collapsed = selection.isCollapsed();
61
62
- // Insert invisible start marker
63
- ieRange.collapse();
64
- ieRange.pasteHTML('<span id="_mce_start" style="display:none;line-height:0">' + invisibleChar + '</span>');
65
66
- // Insert invisible end marker
67
- if (!collapsed) {
68
- ieRange2.collapse(FALSE);
69
- ieRange2.pasteHTML('<span id="_mce_end" style="display:none;line-height:0">' + invisibleChar + '</span>');
70
- }
71
72
- // Sets the end point of the range by looking for the marker
73
- // This method also merges the text nodes it splits so that
74
- // the DOM doesn't get fragmented.
75
- function setEndPoint(start) {
76
- var container, offset, marker, sibling;
77
-
78
- // Look for endpoint marker
79
- marker = dom.get('_mce_' + (start ? 'start' : 'end'));
80
- sibling = marker.previousSibling;
81
-
82
- // Is marker after a text node
83
- if (sibling && sibling.nodeType == 3) {
84
- // Get container node and calc offset
85
- container = sibling;
86
- offset = container.nodeValue.length;
87
dom.remove(marker);
88
89
- // Merge text nodes to reduce DOM fragmentation
90
- sibling = container.nextSibling;
91
- if (sibling && sibling.nodeType == 3) {
92
- isMerged = TRUE;
93
- container.appendData(sibling.nodeValue);
94
- dom.remove(sibling);
95
}
96
- } else {
97
- sibling = marker.nextSibling;
98
99
- // Is marker before a text node
100
- if (sibling && sibling.nodeType == 3) {
101
- container = sibling;
102
- offset = 0;
103
- } else {
104
- // Is marker before an element
105
- if (sibling)
106
- offset = dom.nodeIndex(sibling) - 1;
107
- else
108
- offset = dom.nodeIndex(marker);
109
110
- container = marker.parentNode;
111
}
112
113
dom.remove(marker);
114
}
115
116
- // Set start of range
117
- if (start)
118
- domRange.setStart(container, offset);
119
-
120
- // Set end of range or automatically if it's collapsed to increase performance
121
- if (!start || collapsed)
122
- domRange.setEnd(container, offset);
123
};
124
125
- // Set start of range
126
- setEndPoint(TRUE);
127
128
- // Set end of range if needed
129
if (!collapsed)
130
- setEndPoint(FALSE);
131
-
132
- // Restore selection if the range contents was merged
133
- // since the selection was then moved since the text nodes got changed
134
- if (isMerged)
135
- t.addRange(domRange);
136
137
return domRange;
138
};
@@ -236,7 +222,10 @@