tinymce-rails 3.5b3 → 3.5
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/tinymce/rails/helper.rb +6 -4
- data/lib/tinymce/rails/version.rb +2 -2
- data/vendor/assets/javascripts/tinymce/plugins/autolink/editor_plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autolink/editor_plugin_src.js +6 -6
- data/vendor/assets/javascripts/tinymce/plugins/fullscreen/editor_plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/fullscreen/editor_plugin_src.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/noneditable/editor_plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/noneditable/editor_plugin_src.js +86 -0
- data/vendor/assets/javascripts/tinymce/themes/advanced/editor_template.js +1 -1
- data/vendor/assets/javascripts/tinymce/themes/advanced/editor_template_src.js +16 -2
- data/vendor/assets/javascripts/tinymce/themes/advanced/js/image.js +4 -2
- data/vendor/assets/javascripts/tinymce/themes/advanced/skins/default/ui.css +5 -1
- data/vendor/assets/javascripts/tinymce/themes/advanced/skins/highcontrast/ui.css +5 -1
- data/vendor/assets/javascripts/tinymce/themes/advanced/skins/o2k7/ui.css +5 -1
- data/vendor/assets/javascripts/tinymce/tiny_mce.js +1 -1
- data/vendor/assets/javascripts/tinymce/tiny_mce_jquery.js +1 -1
- data/vendor/assets/javascripts/tinymce/tiny_mce_jquery_src.js +283 -137
- data/vendor/assets/javascripts/tinymce/tiny_mce_src.js +283 -118
- metadata +8 -12
@@ -6,9 +6,9 @@
|
|
6
6
|
var tinymce = {
|
7
7
|
majorVersion : '3',
|
8
8
|
|
9
|
-
minorVersion : '
|
9
|
+
minorVersion : '5',
|
10
10
|
|
11
|
-
releaseDate : '2012-03
|
11
|
+
releaseDate : '2012-05-03',
|
12
12
|
|
13
13
|
_init : function() {
|
14
14
|
var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
|
@@ -506,52 +506,64 @@
|
|
506
506
|
tinymce.create('tinymce.util.Dispatcher', {
|
507
507
|
scope : null,
|
508
508
|
listeners : null,
|
509
|
+
inDispatch: false,
|
509
510
|
|
510
|
-
Dispatcher : function(
|
511
|
-
this.scope =
|
511
|
+
Dispatcher : function(scope) {
|
512
|
+
this.scope = scope || this;
|
512
513
|
this.listeners = [];
|
513
514
|
},
|
514
515
|
|
515
|
-
add : function(
|
516
|
-
this.listeners.push({cb :
|
516
|
+
add : function(callback, scope) {
|
517
|
+
this.listeners.push({cb : callback, scope : scope || this.scope});
|
517
518
|
|
518
|
-
return
|
519
|
+
return callback;
|
519
520
|
},
|
520
521
|
|
521
|
-
addToTop : function(
|
522
|
-
this
|
522
|
+
addToTop : function(callback, scope) {
|
523
|
+
var self = this, listener = {cb : callback, scope : scope || self.scope};
|
523
524
|
|
524
|
-
|
525
|
+
// Create new listeners if addToTop is executed in a dispatch loop
|
526
|
+
if (self.inDispatch) {
|
527
|
+
self.listeners = [listener].concat(self.listeners);
|
528
|
+
} else {
|
529
|
+
self.listeners.unshift(listener);
|
530
|
+
}
|
531
|
+
|
532
|
+
return callback;
|
525
533
|
},
|
526
534
|
|
527
|
-
remove : function(
|
528
|
-
var
|
535
|
+
remove : function(callback) {
|
536
|
+
var listeners = this.listeners, output = null;
|
529
537
|
|
530
|
-
tinymce.each(
|
531
|
-
if (
|
532
|
-
|
533
|
-
|
538
|
+
tinymce.each(listeners, function(listener, i) {
|
539
|
+
if (callback == listener.cb) {
|
540
|
+
output = listener;
|
541
|
+
listeners.splice(i, 1);
|
534
542
|
return false;
|
535
543
|
}
|
536
544
|
});
|
537
545
|
|
538
|
-
return
|
546
|
+
return output;
|
539
547
|
},
|
540
548
|
|
541
549
|
dispatch : function() {
|
542
|
-
var
|
550
|
+
var self = this, returnValue, args = arguments, i, listeners = self.listeners, listener;
|
543
551
|
|
552
|
+
self.inDispatch = true;
|
553
|
+
|
544
554
|
// Needs to be a real loop since the listener count might change while looping
|
545
555
|
// And this is also more efficient
|
546
|
-
for (i = 0; i<
|
547
|
-
|
548
|
-
|
556
|
+
for (i = 0; i < listeners.length; i++) {
|
557
|
+
listener = listeners[i];
|
558
|
+
returnValue = listener.cb.apply(listener.scope, args.length > 0 ? args : [listener.scope]);
|
549
559
|
|
550
|
-
if (
|
560
|
+
if (returnValue === false)
|
551
561
|
break;
|
552
562
|
}
|
553
563
|
|
554
|
-
|
564
|
+
self.inDispatch = false;
|
565
|
+
|
566
|
+
return returnValue;
|
555
567
|
}
|
556
568
|
|
557
569
|
});
|
@@ -1134,12 +1146,8 @@ tinymce.util.Quirks = function(editor) {
|
|
1134
1146
|
editor.onKeyDown.add(function(editor, e) {
|
1135
1147
|
var isDelete;
|
1136
1148
|
|
1137
|
-
if (e.isDefaultPrevented()) {
|
1138
|
-
return;
|
1139
|
-
}
|
1140
|
-
|
1141
1149
|
isDelete = e.keyCode == DELETE;
|
1142
|
-
if ((isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
|
1150
|
+
if (!e.isDefaultPrevented() && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
|
1143
1151
|
e.preventDefault();
|
1144
1152
|
removeMergedFormatSpans(isDelete);
|
1145
1153
|
}
|
@@ -1147,33 +1155,73 @@ tinymce.util.Quirks = function(editor) {
|
|
1147
1155
|
|
1148
1156
|
editor.addCommand('Delete', function() {removeMergedFormatSpans();});
|
1149
1157
|
};
|
1150
|
-
|
1158
|
+
|
1151
1159
|
function emptyEditorWhenDeleting() {
|
1152
|
-
function
|
1153
|
-
var
|
1154
|
-
var contents = rng.cloneContents();
|
1155
|
-
body.appendChild(contents);
|
1156
|
-
return selection.serializer.serialize(body, {format: 'html'});
|
1157
|
-
}
|
1160
|
+
function getEndPointNode(rng, start) {
|
1161
|
+
var container, offset, prefix = start ? 'start' : 'end';
|
1158
1162
|
|
1159
|
-
|
1160
|
-
|
1163
|
+
container = rng[prefix + 'Container'];
|
1164
|
+
offset = rng[prefix + 'Offset'];
|
1161
1165
|
|
1162
|
-
|
1163
|
-
|
1166
|
+
// Resolve indexed container
|
1167
|
+
if (container.nodeType == 1 && container.hasChildNodes()) {
|
1168
|
+
container = container.childNodes[Math.min(start ? offset : (offset > 0 ? offset - 1 : 0), container.childNodes.length - 1)]
|
1169
|
+
}
|
1164
1170
|
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1171
|
+
return container;
|
1172
|
+
};
|
1173
|
+
|
1174
|
+
function isAtStartEndOfBody(rng, start) {
|
1175
|
+
var container, offset, root, childNode, prefix = start ? 'start' : 'end', isAfter;
|
1176
|
+
|
1177
|
+
container = rng[prefix + 'Container'];
|
1178
|
+
offset = rng[prefix + 'Offset'];
|
1179
|
+
root = dom.getRoot();
|
1180
|
+
|
1181
|
+
// Resolve indexed container
|
1182
|
+
if (container.nodeType == 1) {
|
1183
|
+
isAfter = offset >= container.childNodes.length;
|
1184
|
+
container = getEndPointNode(rng, start);
|
1185
|
+
|
1186
|
+
if (container.nodeType == 3) {
|
1187
|
+
offset = start && !isAfter ? 0 : container.nodeValue.length;
|
1188
|
+
}
|
1189
|
+
}
|
1190
|
+
|
1191
|
+
// Check if start/end is in the middle of text
|
1192
|
+
if (container.nodeType == 3 && ((start && offset > 0) || (!start && offset < container.nodeValue.length))) {
|
1193
|
+
return false;
|
1194
|
+
}
|
1195
|
+
|
1196
|
+
// Walk up the DOM tree to see if the endpoint is at the beginning/end of body
|
1197
|
+
while (container !== root) {
|
1198
|
+
childNode = container.parentNode[start ? 'firstChild' : 'lastChild'];
|
1199
|
+
|
1200
|
+
// If first/last element is a BR then jump to it's sibling in case: <p>x<br></p>
|
1201
|
+
if (childNode.nodeName == "BR") {
|
1202
|
+
childNode = childNode[start ? 'nextSibling' : 'previousSibling'] || childNode;
|
1203
|
+
}
|
1204
|
+
|
1205
|
+
// If the childNode isn't the container node then break in case <p><span>A</span>[X]</p>
|
1206
|
+
if (childNode !== container) {
|
1207
|
+
return false;
|
1208
|
+
}
|
1209
|
+
|
1210
|
+
container = container.parentNode;
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
return true;
|
1214
|
+
};
|
1168
1215
|
|
1169
1216
|
editor.onKeyDown.addToTop(function(editor, e) {
|
1170
|
-
var keyCode = e.keyCode;
|
1217
|
+
var rng, keyCode = e.keyCode;
|
1171
1218
|
|
1172
|
-
if (keyCode == DELETE || keyCode == BACKSPACE) {
|
1173
|
-
|
1219
|
+
if (!e.isDefaultPrevented() && (keyCode == DELETE || keyCode == BACKSPACE)) {
|
1220
|
+
rng = selection.getRng(true);
|
1174
1221
|
|
1175
|
-
if (
|
1176
|
-
|
1222
|
+
if (isAtStartEndOfBody(rng, true) && isAtStartEndOfBody(rng, false) &&
|
1223
|
+
(rng.collapsed || dom.findCommonAncestor(getEndPointNode(rng, true), getEndPointNode(rng)) === dom.getRoot())) {
|
1224
|
+
editor.setContent('');
|
1177
1225
|
editor.nodeChanged();
|
1178
1226
|
e.preventDefault();
|
1179
1227
|
}
|
@@ -1182,14 +1230,25 @@ tinymce.util.Quirks = function(editor) {
|
|
1182
1230
|
};
|
1183
1231
|
|
1184
1232
|
function inputMethodFocus() {
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1233
|
+
if (!editor.settings.content_editable) {
|
1234
|
+
// Case 1 IME doesn't initialize if you focus the document
|
1235
|
+
dom.bind(editor.getDoc(), 'focusin', function(e) {
|
1236
|
+
selection.setRng(selection.getRng());
|
1237
|
+
});
|
1238
|
+
|
1239
|
+
// Case 2 IME doesn't initialize if you click the documentElement it also doesn't properly fire the focusin event
|
1240
|
+
dom.bind(editor.getDoc(), 'mousedown', function(e) {
|
1241
|
+
if (e.target == editor.getDoc().documentElement) {
|
1242
|
+
editor.getWin().focus();
|
1243
|
+
selection.setRng(selection.getRng());
|
1244
|
+
}
|
1245
|
+
});
|
1246
|
+
}
|
1188
1247
|
};
|
1189
1248
|
|
1190
1249
|
function removeHrOnBackspace() {
|
1191
1250
|
editor.onKeyDown.add(function(editor, e) {
|
1192
|
-
if (e.keyCode === BACKSPACE) {
|
1251
|
+
if (!e.isDefaultPrevented() && e.keyCode === BACKSPACE) {
|
1193
1252
|
if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
|
1194
1253
|
var node = selection.getNode();
|
1195
1254
|
var previousSibling = node.previousSibling;
|
@@ -1322,7 +1381,7 @@ tinymce.util.Quirks = function(editor) {
|
|
1322
1381
|
|
1323
1382
|
function disableBackspaceIntoATable() {
|
1324
1383
|
editor.onKeyDown.add(function(editor, e) {
|
1325
|
-
if (e.keyCode === BACKSPACE) {
|
1384
|
+
if (!e.isDefaultPrevented() && e.keyCode === BACKSPACE) {
|
1326
1385
|
if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
|
1327
1386
|
var previousSibling = selection.getNode().previousSibling;
|
1328
1387
|
if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "table") {
|
@@ -1410,12 +1469,8 @@ tinymce.util.Quirks = function(editor) {
|
|
1410
1469
|
editor.onKeyDown.add(function(editor, e) {
|
1411
1470
|
var isDelete, rng, container, offset, brElm, sibling, collapsed;
|
1412
1471
|
|
1413
|
-
if (e.isDefaultPrevented()) {
|
1414
|
-
return;
|
1415
|
-
}
|
1416
|
-
|
1417
1472
|
isDelete = e.keyCode == DELETE;
|
1418
|
-
if ((isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
|
1473
|
+
if (!e.isDefaultPrevented() && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
|
1419
1474
|
rng = selection.getRng();
|
1420
1475
|
container = rng.startContainer;
|
1421
1476
|
offset = rng.startOffset;
|
@@ -1455,7 +1510,7 @@ tinymce.util.Quirks = function(editor) {
|
|
1455
1510
|
editor.onKeyDown.add(function(editor, e) {
|
1456
1511
|
var rng, container, offset, root, parent;
|
1457
1512
|
|
1458
|
-
if (e.keyCode != VK.BACKSPACE) {
|
1513
|
+
if (e.isDefaultPrevented() || e.keyCode != VK.BACKSPACE) {
|
1459
1514
|
return;
|
1460
1515
|
}
|
1461
1516
|
|
@@ -1469,7 +1524,7 @@ tinymce.util.Quirks = function(editor) {
|
|
1469
1524
|
return;
|
1470
1525
|
}
|
1471
1526
|
|
1472
|
-
while (parent && parent.parentNode.firstChild == parent && parent.parentNode != root) {
|
1527
|
+
while (parent && parent.parentNode && parent.parentNode.firstChild == parent && parent.parentNode != root) {
|
1473
1528
|
parent = parent.parentNode;
|
1474
1529
|
}
|
1475
1530
|
|
@@ -1547,7 +1602,7 @@ tinymce.util.Quirks = function(editor) {
|
|
1547
1602
|
|
1548
1603
|
function deleteImageOnBackSpace() {
|
1549
1604
|
editor.onKeyDown.add(function(editor, e) {
|
1550
|
-
if (e.keyCode == 8 && selection.getNode().nodeName == 'IMG') {
|
1605
|
+
if (!e.isDefaultPrevented() && e.keyCode == 8 && selection.getNode().nodeName == 'IMG') {
|
1551
1606
|
e.preventDefault();
|
1552
1607
|
editor.undoManager.beforeChange();
|
1553
1608
|
dom.remove(selection.getNode());
|
@@ -1559,12 +1614,12 @@ tinymce.util.Quirks = function(editor) {
|
|
1559
1614
|
// All browsers
|
1560
1615
|
disableBackspaceIntoATable();
|
1561
1616
|
removeBlockQuoteOnBackSpace();
|
1617
|
+
emptyEditorWhenDeleting();
|
1562
1618
|
|
1563
1619
|
// WebKit
|
1564
1620
|
if (tinymce.isWebKit) {
|
1565
1621
|
keepInlineElementOnDeleteBackspace();
|
1566
1622
|
cleanupStylesWhenDeleting();
|
1567
|
-
emptyEditorWhenDeleting();
|
1568
1623
|
inputMethodFocus();
|
1569
1624
|
selectControlElements();
|
1570
1625
|
|
@@ -1577,7 +1632,6 @@ tinymce.util.Quirks = function(editor) {
|
|
1577
1632
|
// IE
|
1578
1633
|
if (tinymce.isIE) {
|
1579
1634
|
removeHrOnBackspace();
|
1580
|
-
emptyEditorWhenDeleting();
|
1581
1635
|
ensureBodyHasRoleApplication();
|
1582
1636
|
addNewLinesBeforeBrInPre();
|
1583
1637
|
removePreSerializedStylesWhenSelectingControls();
|
@@ -3459,7 +3513,7 @@ tinymce.html.Styles = function(settings, schema) {
|
|
3459
3513
|
self.parse = function(html, args) {
|
3460
3514
|
var parser, rootNode, node, nodes, i, l, fi, fl, list, name, validate,
|
3461
3515
|
blockElements, startWhiteSpaceRegExp, invalidChildren = [], isInWhiteSpacePreservedElement,
|
3462
|
-
endWhiteSpaceRegExp, allWhiteSpaceRegExp, whiteSpaceElements, children, nonEmptyElements, rootBlockName;
|
3516
|
+
endWhiteSpaceRegExp, allWhiteSpaceRegExp, isAllWhiteSpaceRegExp, whiteSpaceElements, children, nonEmptyElements, rootBlockName;
|
3463
3517
|
|
3464
3518
|
args = args || {};
|
3465
3519
|
matchedNodes = {};
|
@@ -3474,6 +3528,7 @@ tinymce.html.Styles = function(settings, schema) {
|
|
3474
3528
|
startWhiteSpaceRegExp = /^[ \t\r\n]+/;
|
3475
3529
|
endWhiteSpaceRegExp = /[ \t\r\n]+$/;
|
3476
3530
|
allWhiteSpaceRegExp = /[ \t\r\n]+/g;
|
3531
|
+
isAllWhiteSpaceRegExp = /^[ \t\r\n]+$/;
|
3477
3532
|
|
3478
3533
|
function addRootBlocks() {
|
3479
3534
|
var node = rootNode.firstChild, next, rootBlockNode;
|
@@ -3626,10 +3681,12 @@ tinymce.html.Styles = function(settings, schema) {
|
|
3626
3681
|
if (elementRule) {
|
3627
3682
|
if (blockElements[name]) {
|
3628
3683
|
if (!isInWhiteSpacePreservedElement) {
|
3629
|
-
// Trim whitespace
|
3630
|
-
|
3684
|
+
// Trim whitespace of the first node in a block
|
3685
|
+
textNode = node.firstChild;
|
3686
|
+
if (textNode && textNode.type === 3) {
|
3631
3687
|
text = textNode.value.replace(startWhiteSpaceRegExp, '');
|
3632
3688
|
|
3689
|
+
// Any characters left after trim or should we remove it
|
3633
3690
|
if (text.length > 0) {
|
3634
3691
|
textNode.value = text;
|
3635
3692
|
textNode = textNode.next;
|
@@ -3638,12 +3695,27 @@ tinymce.html.Styles = function(settings, schema) {
|
|
3638
3695
|
textNode.remove();
|
3639
3696
|
textNode = sibling;
|
3640
3697
|
}
|
3698
|
+
|
3699
|
+
// Remove any pure whitespace siblings
|
3700
|
+
while (textNode && textNode.type === 3) {
|
3701
|
+
text = textNode.value;
|
3702
|
+
sibling = textNode.next;
|
3703
|
+
|
3704
|
+
if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
|
3705
|
+
textNode.remove();
|
3706
|
+
textNode = sibling;
|
3707
|
+
}
|
3708
|
+
|
3709
|
+
textNode = sibling;
|
3710
|
+
}
|
3641
3711
|
}
|
3642
3712
|
|
3643
|
-
// Trim whitespace
|
3644
|
-
|
3713
|
+
// Trim whitespace of the last node in a block
|
3714
|
+
textNode = node.lastChild;
|
3715
|
+
if (textNode && textNode.type === 3) {
|
3645
3716
|
text = textNode.value.replace(endWhiteSpaceRegExp, '');
|
3646
3717
|
|
3718
|
+
// Any characters left after trim or should we remove it
|
3647
3719
|
if (text.length > 0) {
|
3648
3720
|
textNode.value = text;
|
3649
3721
|
textNode = textNode.prev;
|
@@ -3652,6 +3724,19 @@ tinymce.html.Styles = function(settings, schema) {
|
|
3652
3724
|
textNode.remove();
|
3653
3725
|
textNode = sibling;
|
3654
3726
|
}
|
3727
|
+
|
3728
|
+
// Remove any pure whitespace siblings
|
3729
|
+
while (textNode && textNode.type === 3) {
|
3730
|
+
text = textNode.value;
|
3731
|
+
sibling = textNode.prev;
|
3732
|
+
|
3733
|
+
if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
|
3734
|
+
textNode.remove();
|
3735
|
+
textNode = sibling;
|
3736
|
+
}
|
3737
|
+
|
3738
|
+
textNode = sibling;
|
3739
|
+
}
|
3655
3740
|
}
|
3656
3741
|
}
|
3657
3742
|
|
@@ -4532,7 +4617,11 @@ tinymce.dom = {};
|
|
4532
4617
|
return self.bind(target, events instanceof Array ? events.join(' ') : events, func, scope);
|
4533
4618
|
};
|
4534
4619
|
|
4535
|
-
self.remove = function(target, events, func) {
|
4620
|
+
self.remove = function(target, events, func, scope) {
|
4621
|
+
if (!target) {
|
4622
|
+
return self;
|
4623
|
+
}
|
4624
|
+
|
4536
4625
|
// Old API supported direct ID assignment
|
4537
4626
|
if (typeof(target) === "string") {
|
4538
4627
|
target = document.getElementById(target);
|
@@ -4540,7 +4629,7 @@ tinymce.dom = {};
|
|
4540
4629
|
|
4541
4630
|
// Old API supported multiple targets
|
4542
4631
|
if (target instanceof Array) {
|
4543
|
-
var i = target;
|
4632
|
+
var i = target.length;
|
4544
4633
|
|
4545
4634
|
while (i--) {
|
4546
4635
|
self.remove(target[i], events, func, scope);
|
@@ -8967,6 +9056,29 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
8967
9056
|
return index;
|
8968
9057
|
};
|
8969
9058
|
|
9059
|
+
function normalizeTableCellSelection(rng) {
|
9060
|
+
function moveEndPoint(start) {
|
9061
|
+
var container, offset, childNodes, prefix = start ? 'start' : 'end';
|
9062
|
+
|
9063
|
+
container = rng[prefix + 'Container'];
|
9064
|
+
offset = rng[prefix + 'Offset'];
|
9065
|
+
|
9066
|
+
if (container.nodeType == 1 && container.nodeName == "TR") {
|
9067
|
+
childNodes = container.childNodes;
|
9068
|
+
container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
|
9069
|
+
if (container) {
|
9070
|
+
offset = start ? 0 : container.childNodes.length;
|
9071
|
+
rng['set' + (start ? 'Start' : 'End')](container, offset);
|
9072
|
+
}
|
9073
|
+
}
|
9074
|
+
};
|
9075
|
+
|
9076
|
+
moveEndPoint(true);
|
9077
|
+
moveEndPoint();
|
9078
|
+
|
9079
|
+
return rng;
|
9080
|
+
};
|
9081
|
+
|
8970
9082
|
function getLocation() {
|
8971
9083
|
var rng = t.getRng(true), root = dom.getRoot(), bookmark = {};
|
8972
9084
|
|
@@ -9061,13 +9173,8 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9061
9173
|
if (name == 'IMG')
|
9062
9174
|
return {name : name, index : findIndex(name, element)};
|
9063
9175
|
|
9064
|
-
// Can't insert a node into the root of document WebKit defaults to document
|
9065
|
-
if (rng.startContainer.nodeType == 9) {
|
9066
|
-
return;
|
9067
|
-
}
|
9068
|
-
|
9069
9176
|
// W3C method
|
9070
|
-
rng2 = rng.cloneRange();
|
9177
|
+
rng2 = normalizeTableCellSelection(rng.cloneRange());
|
9071
9178
|
|
9072
9179
|
// Insert end marker
|
9073
9180
|
if (!collapsed) {
|
@@ -9075,6 +9182,7 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9075
9182
|
rng2.insertNode(dom.create('span', {'data-mce-type' : "bookmark", id : id + '_end', style : styles}, chr));
|
9076
9183
|
}
|
9077
9184
|
|
9185
|
+
rng = normalizeTableCellSelection(rng);
|
9078
9186
|
rng.collapse(true);
|
9079
9187
|
rng.insertNode(dom.create('span', {'data-mce-type' : "bookmark", id : id + '_start', style : styles}, chr));
|
9080
9188
|
}
|
@@ -9299,48 +9407,58 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9299
9407
|
},
|
9300
9408
|
|
9301
9409
|
getRng : function(w3c) {
|
9302
|
-
var
|
9410
|
+
var self = this, selection, rng, elm, doc = self.win.document;
|
9303
9411
|
|
9304
9412
|
// Found tridentSel object then we need to use that one
|
9305
|
-
if (w3c &&
|
9306
|
-
return
|
9413
|
+
if (w3c && self.tridentSel) {
|
9414
|
+
return self.tridentSel.getRangeAt(0);
|
9415
|
+
}
|
9307
9416
|
|
9308
9417
|
try {
|
9309
|
-
if (
|
9310
|
-
|
9418
|
+
if (selection = self.getSel()) {
|
9419
|
+
rng = selection.rangeCount > 0 ? selection.getRangeAt(0) : (selection.createRange ? selection.createRange() : doc.createRange());
|
9420
|
+
}
|
9311
9421
|
} catch (ex) {
|
9312
9422
|
// IE throws unspecified error here if TinyMCE is placed in a frame/iframe
|
9313
9423
|
}
|
9314
9424
|
|
9315
9425
|
// We have W3C ranges and it's IE then fake control selection since IE9 doesn't handle that correctly yet
|
9316
|
-
if (tinymce.isIE &&
|
9426
|
+
if (tinymce.isIE && rng && rng.setStart && doc.selection.createRange().item) {
|
9317
9427
|
elm = doc.selection.createRange().item(0);
|
9318
|
-
|
9319
|
-
|
9320
|
-
|
9428
|
+
rng = doc.createRange();
|
9429
|
+
rng.setStartBefore(elm);
|
9430
|
+
rng.setEndAfter(elm);
|
9321
9431
|
}
|
9322
9432
|
|
9323
9433
|
// No range found then create an empty one
|
9324
9434
|
// This can occur when the editor is placed in a hidden container element on Gecko
|
9325
9435
|
// Or on IE when there was an exception
|
9326
|
-
if (!
|
9327
|
-
|
9436
|
+
if (!rng) {
|
9437
|
+
rng = doc.createRange ? doc.createRange() : doc.body.createTextRange();
|
9438
|
+
}
|
9328
9439
|
|
9329
|
-
|
9330
|
-
|
9440
|
+
// If range is at start of document then move it to start of body
|
9441
|
+
if (rng.setStart && rng.startContainer.nodeType === 9 && rng.collapsed) {
|
9442
|
+
elm = self.dom.getRoot();
|
9443
|
+
rng.setStart(elm, 0);
|
9444
|
+
rng.setEnd(elm, 0);
|
9445
|
+
}
|
9446
|
+
|
9447
|
+
if (self.selectedRange && self.explicitRange) {
|
9448
|
+
if (rng.compareBoundaryPoints(rng.START_TO_START, self.selectedRange) === 0 && rng.compareBoundaryPoints(rng.END_TO_END, self.selectedRange) === 0) {
|
9331
9449
|
// Safari, Opera and Chrome only ever select text which causes the range to change.
|
9332
9450
|
// This lets us use the originally set range if the selection hasn't been changed by the user.
|
9333
|
-
|
9451
|
+
rng = self.explicitRange;
|
9334
9452
|
} else {
|
9335
|
-
|
9336
|
-
|
9453
|
+
self.selectedRange = null;
|
9454
|
+
self.explicitRange = null;
|
9337
9455
|
}
|
9338
9456
|
}
|
9339
9457
|
|
9340
|
-
return
|
9458
|
+
return rng;
|
9341
9459
|
},
|
9342
9460
|
|
9343
|
-
setRng : function(r) {
|
9461
|
+
setRng : function(r, forward) {
|
9344
9462
|
var s, t = this;
|
9345
9463
|
|
9346
9464
|
if (!t.tridentSel) {
|
@@ -9356,6 +9474,13 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9356
9474
|
}
|
9357
9475
|
|
9358
9476
|
s.addRange(r);
|
9477
|
+
|
9478
|
+
// Forward is set to false and we have an extend function
|
9479
|
+
if (forward === false && s.extend) {
|
9480
|
+
s.collapse(r.endContainer, r.endOffset);
|
9481
|
+
s.extend(r.startContainer, r.startOffset);
|
9482
|
+
}
|
9483
|
+
|
9359
9484
|
// adding range isn't always successful so we need to check range count otherwise an exception can occur
|
9360
9485
|
t.selectedRange = s.rangeCount > 0 ? s.getRangeAt(0) : null;
|
9361
9486
|
}
|
@@ -9471,12 +9596,41 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9471
9596
|
return bl;
|
9472
9597
|
},
|
9473
9598
|
|
9599
|
+
isForward: function(){
|
9600
|
+
var dom = this.dom, sel = this.getSel(), anchorRange, focusRange;
|
9601
|
+
|
9602
|
+
// No support for selection direction then always return true
|
9603
|
+
if (!sel || sel.anchorNode == null || sel.focusNode == null) {
|
9604
|
+
return true;
|
9605
|
+
}
|
9606
|
+
|
9607
|
+
anchorRange = dom.createRng();
|
9608
|
+
anchorRange.setStart(sel.anchorNode, sel.anchorOffset);
|
9609
|
+
anchorRange.collapse(true);
|
9610
|
+
|
9611
|
+
focusRange = dom.createRng();
|
9612
|
+
focusRange.setStart(sel.focusNode, sel.focusOffset);
|
9613
|
+
focusRange.collapse(true);
|
9614
|
+
|
9615
|
+
return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
|
9616
|
+
},
|
9617
|
+
|
9474
9618
|
normalize : function() {
|
9475
|
-
var self = this, rng, normalized, collapsed;
|
9619
|
+
var self = this, rng, normalized, collapsed, node, sibling;
|
9476
9620
|
|
9477
9621
|
function normalizeEndPoint(start) {
|
9478
9622
|
var container, offset, walker, dom = self.dom, body = dom.getRoot(), node, nonEmptyElementsMap, nodeName;
|
9479
9623
|
|
9624
|
+
function hasBrBeforeAfter(node, left) {
|
9625
|
+
var walker = new TreeWalker(node, dom.getParent(node.parentNode, dom.isBlock) || body);
|
9626
|
+
|
9627
|
+
while (node = walker[left ? 'prev' : 'next']()) {
|
9628
|
+
if (node.nodeName === "BR") {
|
9629
|
+
return true;
|
9630
|
+
}
|
9631
|
+
}
|
9632
|
+
};
|
9633
|
+
|
9480
9634
|
// Walks the dom left/right to find a suitable text node to move the endpoint into
|
9481
9635
|
// It will only walk within the current parent block or body and will stop if it hits a block or a BR/IMG
|
9482
9636
|
function findTextNodeRelative(left, startNode) {
|
@@ -9517,7 +9671,7 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9517
9671
|
|
9518
9672
|
// If the container is a document move it to the body element
|
9519
9673
|
if (container.nodeType === 9) {
|
9520
|
-
container =
|
9674
|
+
container = dom.getRoot();
|
9521
9675
|
offset = 0;
|
9522
9676
|
}
|
9523
9677
|
|
@@ -9540,7 +9694,7 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9540
9694
|
offset = 0;
|
9541
9695
|
|
9542
9696
|
// Don't walk into elements that doesn't have any child nodes like a IMG
|
9543
|
-
if (container.hasChildNodes()) {
|
9697
|
+
if (container.hasChildNodes() && !/TABLE/.test(container.nodeName)) {
|
9544
9698
|
// Walk the DOM to find a text node to place the caret at or a BR
|
9545
9699
|
node = container;
|
9546
9700
|
walker = new TreeWalker(container, body);
|
@@ -9572,7 +9726,6 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9572
9726
|
}
|
9573
9727
|
}
|
9574
9728
|
|
9575
|
-
|
9576
9729
|
// Lean the caret to the left if possible
|
9577
9730
|
if (collapsed) {
|
9578
9731
|
// So this: <b>x</b><i>|x</i>
|
@@ -9586,8 +9739,11 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9586
9739
|
// So this: <i><b></b><i>|<br></i>
|
9587
9740
|
// Becomes: <i><b>|</b><i><br></i>
|
9588
9741
|
// Seems that only gecko has issues with this
|
9589
|
-
if (container.nodeType === 1
|
9590
|
-
|
9742
|
+
if (container.nodeType === 1) {
|
9743
|
+
node = container.childNodes[offset];
|
9744
|
+
if(node && node.nodeName === 'BR' && !hasBrBeforeAfter(node) && !hasBrBeforeAfter(node, true)) {
|
9745
|
+
findTextNodeRelative(true, container.childNodes[offset]);
|
9746
|
+
}
|
9591
9747
|
}
|
9592
9748
|
}
|
9593
9749
|
|
@@ -9603,9 +9759,6 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9603
9759
|
rng['set' + (start ? 'Start' : 'End')](container, offset);
|
9604
9760
|
};
|
9605
9761
|
|
9606
|
-
// TODO:
|
9607
|
-
// Retain selection direction.
|
9608
|
-
|
9609
9762
|
// Normalize only on non IE browsers for now
|
9610
9763
|
if (tinymce.isIE)
|
9611
9764
|
return;
|
@@ -9627,7 +9780,7 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9627
9780
|
}
|
9628
9781
|
|
9629
9782
|
//console.log(self.dom.dumpRng(rng));
|
9630
|
-
self.setRng(rng);
|
9783
|
+
self.setRng(rng, self.isForward());
|
9631
9784
|
}
|
9632
9785
|
},
|
9633
9786
|
|
@@ -9771,13 +9924,13 @@ window.tinymce.dom.Sizzle = Sizzle;
|
|
9771
9924
|
}
|
9772
9925
|
});
|
9773
9926
|
|
9774
|
-
// Remove internal classes mceItem<..>
|
9927
|
+
// Remove internal classes mceItem<..> or mceSelected
|
9775
9928
|
htmlParser.addAttributeFilter('class', function(nodes, name) {
|
9776
9929
|
var i = nodes.length, node, value;
|
9777
9930
|
|
9778
9931
|
while (i--) {
|
9779
9932
|
node = nodes[i];
|
9780
|
-
value = node.attr('class').replace(
|
9933
|
+
value = node.attr('class').replace(/(?:^|\s)mce(Item\w+|Selected)(?!\S)/g, '');
|
9781
9934
|
node.attr('class', value.length > 0 ? value : null);
|
9782
9935
|
}
|
9783
9936
|
});
|
@@ -10851,8 +11004,8 @@ tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
|
|
10851
11004
|
update : function() {
|
10852
11005
|
var t = this, s = t.settings, tb = DOM.get('menu_' + t.id + '_tbl'), co = DOM.get('menu_' + t.id + '_co'), tw, th;
|
10853
11006
|
|
10854
|
-
tw = s.max_width ? Math.min(tb.
|
10855
|
-
th = s.max_height ? Math.min(tb.
|
11007
|
+
tw = s.max_width ? Math.min(tb.offsetWidth, s.max_width) : tb.offsetWidth;
|
11008
|
+
th = s.max_height ? Math.min(tb.offsetHeight, s.max_height) : tb.offsetHeight;
|
10856
11009
|
|
10857
11010
|
if (!DOM.boxModel)
|
10858
11011
|
t.element.setStyles({width : tw + 2, height : th + 2});
|
@@ -11397,7 +11550,7 @@ tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
|
|
11397
11550
|
m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
|
11398
11551
|
menu_line : 1,
|
11399
11552
|
'class' : t.classPrefix + 'Menu mceNoIcons',
|
11400
|
-
max_width :
|
11553
|
+
max_width : 250,
|
11401
11554
|
max_height : 150
|
11402
11555
|
});
|
11403
11556
|
|
@@ -13515,7 +13668,7 @@ tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {
|
|
13515
13668
|
},
|
13516
13669
|
|
13517
13670
|
hide : function() {
|
13518
|
-
var self = this, doc =
|
13671
|
+
var self = this, doc = self.getDoc();
|
13519
13672
|
|
13520
13673
|
// Fixed bug where IE has a blinking cursor left from the editor
|
13521
13674
|
if (isIE && doc)
|
@@ -14642,9 +14795,7 @@ tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {
|
|
14642
14795
|
// Override justify commands
|
14643
14796
|
'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull' : function(command) {
|
14644
14797
|
var name = 'align' + command.substring(7);
|
14645
|
-
|
14646
|
-
// and right align buttons can be active. This could occur when selected nodes have align right and the parent has align left.
|
14647
|
-
var nodes = selection.isCollapsed() ? [selection.getNode()] : selection.getSelectedBlocks();
|
14798
|
+
var nodes = selection.isCollapsed() ? [dom.getParent(selection.getNode(), dom.isBlock)] : selection.getSelectedBlocks();
|
14648
14799
|
var matches = tinymce.map(nodes, function(node) {
|
14649
14800
|
return !!formatter.matchNode(node, name);
|
14650
14801
|
});
|
@@ -14926,7 +15077,7 @@ tinymce.ForceBlocks = function(editor) {
|
|
14926
15077
|
var settings = editor.settings, dom = editor.dom, selection = editor.selection, blockElements = editor.schema.getBlockElements();
|
14927
15078
|
|
14928
15079
|
function addRootBlocks() {
|
14929
|
-
var node = selection.getStart(), rootNode = editor.getBody(), rng, startContainer, startOffset, endContainer, endOffset, rootBlockNode, tempNode, offset = -0xFFFFFF;
|
15080
|
+
var node = selection.getStart(), rootNode = editor.getBody(), rng, startContainer, startOffset, endContainer, endOffset, rootBlockNode, tempNode, offset = -0xFFFFFF, wrapped;
|
14930
15081
|
|
14931
15082
|
if (!node || node.nodeType !== 1 || !settings.forced_root_block)
|
14932
15083
|
return;
|
@@ -14972,6 +15123,7 @@ tinymce.ForceBlocks = function(editor) {
|
|
14972
15123
|
if (!rootBlockNode) {
|
14973
15124
|
rootBlockNode = dom.create(settings.forced_root_block);
|
14974
15125
|
node.parentNode.insertBefore(rootBlockNode, node);
|
15126
|
+
wrapped = true;
|
14975
15127
|
}
|
14976
15128
|
|
14977
15129
|
tempNode = node;
|
@@ -15003,13 +15155,16 @@ tinymce.ForceBlocks = function(editor) {
|
|
15003
15155
|
}
|
15004
15156
|
}
|
15005
15157
|
|
15006
|
-
|
15158
|
+
// Only trigger nodeChange when we wrapped nodes to prevent a forever loop
|
15159
|
+
if (wrapped) {
|
15160
|
+
editor.nodeChanged();
|
15161
|
+
}
|
15007
15162
|
};
|
15008
15163
|
|
15009
15164
|
// Force root blocks
|
15010
15165
|
if (settings.forced_root_block) {
|
15011
15166
|
editor.onKeyUp.add(addRootBlocks);
|
15012
|
-
editor.
|
15167
|
+
editor.onNodeChange.add(addRootBlocks);
|
15013
15168
|
}
|
15014
15169
|
};
|
15015
15170
|
|
@@ -15105,6 +15260,8 @@ tinymce.ForceBlocks = function(editor) {
|
|
15105
15260
|
if (v = ed.getParam('skin_variant'))
|
15106
15261
|
s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1);
|
15107
15262
|
|
15263
|
+
s['class'] += ed.settings.directionality == "rtl" ? ' mceRtl' : '';
|
15264
|
+
|
15108
15265
|
id = t.prefix + id;
|
15109
15266
|
cls = cc || t._cls.dropmenu || tinymce.ui.DropMenu;
|
15110
15267
|
c = t.controls[id] = new cls(id, s);
|
@@ -16218,9 +16375,8 @@ tinymce.ForceBlocks = function(editor) {
|
|
16218
16375
|
if (startContainer != endContainer) {
|
16219
16376
|
// WebKit will render the table incorrectly if we wrap a TD in a SPAN so lets see if the can use the first child instead
|
16220
16377
|
// This will happen if you tripple click a table cell and use remove formatting
|
16221
|
-
|
16222
|
-
|
16223
|
-
startContainer = node;
|
16378
|
+
if (/^(TR|TD)$/.test(startContainer.nodeName) && startContainer.firstChild) {
|
16379
|
+
startContainer = (startContainer.nodeName == "TD" ? startContainer.firstChild : startContainer.firstChild.firstChild) || startContainer;
|
16224
16380
|
}
|
16225
16381
|
|
16226
16382
|
// Wrap start/end nodes in span element since these might be cloned/moved
|
@@ -17381,6 +17537,15 @@ tinymce.ForceBlocks = function(editor) {
|
|
17381
17537
|
}
|
17382
17538
|
});
|
17383
17539
|
|
17540
|
+
// Remove bogus state if they got filled by contents using editor.selection.setContent
|
17541
|
+
selection.onSetContent.add(function() {
|
17542
|
+
dom.getParent(selection.getStart(), function(node) {
|
17543
|
+
if (node.id !== caretContainerId && dom.getAttrib(node, 'data-mce-bogus') && !dom.isEmpty(node)) {
|
17544
|
+
dom.setAttrib(node, 'data-mce-bogus', null);
|
17545
|
+
}
|
17546
|
+
});
|
17547
|
+
});
|
17548
|
+
|
17384
17549
|
self._hasCaretEvents = true;
|
17385
17550
|
}
|
17386
17551
|
|