tinymce-rails 3.5.6 → 3.5.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,9 +6,9 @@
6
6
  var tinymce = {
7
7
  majorVersion : '3',
8
8
 
9
- minorVersion : '5.6',
9
+ minorVersion : '5.7',
10
10
 
11
- releaseDate : '2012-07-26',
11
+ releaseDate : '2012-09-20',
12
12
 
13
13
  _init : function() {
14
14
  var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
@@ -107,12 +107,16 @@
107
107
  if (!t)
108
108
  return o !== undef;
109
109
 
110
- if (t == 'array' && (o.hasOwnProperty && o instanceof Array))
110
+ if (t == 'array' && tinymce.isArray(o))
111
111
  return true;
112
112
 
113
113
  return typeof(o) == t;
114
114
  },
115
115
 
116
+ isArray: Array.isArray || function(obj) {
117
+ return Object.prototype.toString.call(obj) === "[object Array]";
118
+ },
119
+
116
120
  makeMap : function(items, delim, map) {
117
121
  var i;
118
122
 
@@ -921,7 +925,7 @@ tinymce.create('tinymce.util.Dispatcher', {
921
925
  }
922
926
 
923
927
  if (t == 'object') {
924
- if (o.hasOwnProperty && o instanceof Array) {
928
+ if (o.hasOwnProperty && Object.prototype.toString.call(o) === '[object Array]') {
925
929
  for (i=0, v = '['; i<o.length; i++)
926
930
  v += (i > 0 ? ',' : '') + serialize(o[i], quote);
927
931
 
@@ -1093,7 +1097,8 @@ tinymce.create('static tinymce.util.XHR', {
1093
1097
  })(tinymce);
1094
1098
 
1095
1099
  tinymce.util.Quirks = function(editor) {
1096
- var VK = tinymce.VK, BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, settings = editor.settings;
1100
+ var VK = tinymce.VK, BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection,
1101
+ settings = editor.settings, parser = editor.parser, serializer = editor.serializer;
1097
1102
 
1098
1103
  function setEditorCommandState(cmd, state) {
1099
1104
  try {
@@ -1109,6 +1114,10 @@ tinymce.util.Quirks = function(editor) {
1109
1114
  return documentMode ? documentMode : 6;
1110
1115
  };
1111
1116
 
1117
+ function isDefaultPrevented(e) {
1118
+ return e.isDefaultPrevented();
1119
+ };
1120
+
1112
1121
  function cleanupStylesWhenDeleting() {
1113
1122
  function removeMergedFormatSpans(isDelete) {
1114
1123
  var rng, blockElm, node, clonedSpan;
@@ -1158,7 +1167,7 @@ tinymce.util.Quirks = function(editor) {
1158
1167
  var isDelete;
1159
1168
 
1160
1169
  isDelete = e.keyCode == DELETE;
1161
- if (!e.isDefaultPrevented() && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
1170
+ if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
1162
1171
  e.preventDefault();
1163
1172
  removeMergedFormatSpans(isDelete);
1164
1173
  }
@@ -1189,7 +1198,7 @@ tinymce.util.Quirks = function(editor) {
1189
1198
  var keyCode = e.keyCode, isCollapsed;
1190
1199
 
1191
1200
  // Empty the editor if it's needed for example backspace at <p><b>|</b></p>
1192
- if (!e.isDefaultPrevented() && (keyCode == DELETE || keyCode == BACKSPACE)) {
1201
+ if (!isDefaultPrevented(e) && (keyCode == DELETE || keyCode == BACKSPACE)) {
1193
1202
  isCollapsed = editor.selection.isCollapsed();
1194
1203
 
1195
1204
  // Selection is collapsed but the editor isn't empty
@@ -1217,7 +1226,7 @@ tinymce.util.Quirks = function(editor) {
1217
1226
 
1218
1227
  function selectAll() {
1219
1228
  editor.onKeyDown.add(function(editor, e) {
1220
- if (e.keyCode == 65 && VK.metaKeyPressed(e)) {
1229
+ if (!isDefaultPrevented(e) && e.keyCode == 65 && VK.metaKeyPressed(e)) {
1221
1230
  e.preventDefault();
1222
1231
  editor.execCommand('SelectAll');
1223
1232
  }
@@ -1243,7 +1252,7 @@ tinymce.util.Quirks = function(editor) {
1243
1252
 
1244
1253
  function removeHrOnBackspace() {
1245
1254
  editor.onKeyDown.add(function(editor, e) {
1246
- if (!e.isDefaultPrevented() && e.keyCode === BACKSPACE) {
1255
+ if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
1247
1256
  if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
1248
1257
  var node = selection.getNode();
1249
1258
  var previousSibling = node.previousSibling;
@@ -1262,7 +1271,7 @@ tinymce.util.Quirks = function(editor) {
1262
1271
  // wouldn't get proper focus if the user clicked on the HTML element
1263
1272
  if (!Range.prototype.getClientRects) { // Detect getClientRects got introduced in FF 4
1264
1273
  editor.onMouseDown.add(function(editor, e) {
1265
- if (e.target.nodeName === "HTML") {
1274
+ if (!isDefaultPrevented(e) && e.target.nodeName === "HTML") {
1266
1275
  var body = editor.getBody();
1267
1276
 
1268
1277
  // Blur the body it's focused but not correctly focused
@@ -1325,7 +1334,7 @@ tinymce.util.Quirks = function(editor) {
1325
1334
  editor.onKeyPress.add(function(editor, e) {
1326
1335
  var applyAttributes;
1327
1336
 
1328
- if ((e.keyCode == 8 || e.keyCode == 46) && isSelectionAcrossElements()) {
1337
+ if (!isDefaultPrevented(e) && (e.keyCode == 8 || e.keyCode == 46) && isSelectionAcrossElements()) {
1329
1338
  applyAttributes = getAttributeApplyFunction();
1330
1339
  editor.getDoc().execCommand('delete', false, null);
1331
1340
  applyAttributes();
@@ -1337,7 +1346,7 @@ tinymce.util.Quirks = function(editor) {
1337
1346
  dom.bind(editor.getDoc(), 'cut', function(e) {
1338
1347
  var applyAttributes;
1339
1348
 
1340
- if (isSelectionAcrossElements()) {
1349
+ if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
1341
1350
  applyAttributes = getAttributeApplyFunction();
1342
1351
  editor.onKeyUp.addToTop(blockEvent);
1343
1352
 
@@ -1376,7 +1385,7 @@ tinymce.util.Quirks = function(editor) {
1376
1385
 
1377
1386
  function disableBackspaceIntoATable() {
1378
1387
  editor.onKeyDown.add(function(editor, e) {
1379
- if (!e.isDefaultPrevented() && e.keyCode === BACKSPACE) {
1388
+ if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
1380
1389
  if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
1381
1390
  var previousSibling = selection.getNode().previousSibling;
1382
1391
  if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "table") {
@@ -1400,7 +1409,7 @@ tinymce.util.Quirks = function(editor) {
1400
1409
  dom.addClass(editor.getBody(), 'mceHideBrInPre');
1401
1410
 
1402
1411
  // Adds a \n before all BR elements in PRE to get them visual
1403
- editor.parser.addNodeFilter('pre', function(nodes, name) {
1412
+ parser.addNodeFilter('pre', function(nodes, name) {
1404
1413
  var i = nodes.length, brNodes, j, brElm, sibling;
1405
1414
 
1406
1415
  while (i--) {
@@ -1421,7 +1430,7 @@ tinymce.util.Quirks = function(editor) {
1421
1430
  });
1422
1431
 
1423
1432
  // Removes any \n before BR elements in PRE since other browsers and in contentEditable=false mode they will be visible
1424
- editor.serializer.addNodeFilter('pre', function(nodes, name) {
1433
+ serializer.addNodeFilter('pre', function(nodes, name) {
1425
1434
  var i = nodes.length, brNodes, j, brElm, sibling;
1426
1435
 
1427
1436
  while (i--) {
@@ -1464,7 +1473,7 @@ tinymce.util.Quirks = function(editor) {
1464
1473
  var isDelete, rng, container, offset, brElm, sibling, collapsed;
1465
1474
 
1466
1475
  isDelete = e.keyCode == DELETE;
1467
- if (!e.isDefaultPrevented() && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
1476
+ if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
1468
1477
  rng = selection.getRng();
1469
1478
  container = rng.startContainer;
1470
1479
  offset = rng.startOffset;
@@ -1504,7 +1513,7 @@ tinymce.util.Quirks = function(editor) {
1504
1513
  editor.onKeyDown.add(function(editor, e) {
1505
1514
  var rng, container, offset, root, parent;
1506
1515
 
1507
- if (e.isDefaultPrevented() || e.keyCode != VK.BACKSPACE) {
1516
+ if (isDefaultPrevented(e) || e.keyCode != VK.BACKSPACE) {
1508
1517
  return;
1509
1518
  }
1510
1519
 
@@ -1528,10 +1537,10 @@ tinymce.util.Quirks = function(editor) {
1528
1537
  editor.formatter.toggle('blockquote', null, parent);
1529
1538
 
1530
1539
  // Move the caret to the beginning of container
1540
+ rng = dom.createRng();
1531
1541
  rng.setStart(container, 0);
1532
1542
  rng.setEnd(container, 0);
1533
1543
  selection.setRng(rng);
1534
- selection.collapse(false);
1535
1544
  }
1536
1545
  });
1537
1546
  };
@@ -1606,7 +1615,7 @@ tinymce.util.Quirks = function(editor) {
1606
1615
  editor.onKeyDown.add(function(editor, e) {
1607
1616
  var rng;
1608
1617
 
1609
- if (!e.isDefaultPrevented() && e.keyCode == BACKSPACE) {
1618
+ if (!isDefaultPrevented(e) && e.keyCode == BACKSPACE) {
1610
1619
  rng = editor.getDoc().selection.createRange();
1611
1620
  if (rng && rng.item) {
1612
1621
  e.preventDefault();
@@ -1865,6 +1874,46 @@ tinymce.util.Quirks = function(editor) {
1865
1874
  });
1866
1875
  }
1867
1876
 
1877
+ function keepNoScriptContents() {
1878
+ if (getDocumentMode() < 9) {
1879
+ parser.addNodeFilter('noscript', function(nodes) {
1880
+ var i = nodes.length, node, textNode;
1881
+
1882
+ while (i--) {
1883
+ node = nodes[i];
1884
+ textNode = node.firstChild;
1885
+
1886
+ if (textNode) {
1887
+ node.attr('data-mce-innertext', textNode.value);
1888
+ }
1889
+ }
1890
+ });
1891
+
1892
+ serializer.addNodeFilter('noscript', function(nodes) {
1893
+ var i = nodes.length, node, textNode, value;
1894
+
1895
+ while (i--) {
1896
+ node = nodes[i];
1897
+ textNode = nodes[i].firstChild;
1898
+
1899
+ if (textNode) {
1900
+ textNode.value = tinymce.html.Entities.decode(textNode.value);
1901
+ } else {
1902
+ // Old IE can't retain noscript value so an attribute is used to store it
1903
+ value = node.attributes.map['data-mce-innertext'];
1904
+ if (value) {
1905
+ node.attr('data-mce-innertext', null);
1906
+ textNode = new tinymce.html.Node('#text', 3);
1907
+ textNode.value = value;
1908
+ textNode.raw = true;
1909
+ node.append(textNode);
1910
+ }
1911
+ }
1912
+ }
1913
+ });
1914
+ }
1915
+ }
1916
+
1868
1917
  // All browsers
1869
1918
  disableBackspaceIntoATable();
1870
1919
  removeBlockQuoteOnBackSpace();
@@ -1895,6 +1944,7 @@ tinymce.util.Quirks = function(editor) {
1895
1944
  removePreSerializedStylesWhenSelectingControls();
1896
1945
  deleteControlItemOnBackSpace();
1897
1946
  renderEmptyBlocksFix();
1947
+ keepNoScriptContents();
1898
1948
  }
1899
1949
 
1900
1950
  // Gecko
@@ -2449,7 +2499,7 @@ tinymce.html.Styles = function(settings, schema) {
2449
2499
  'form[A|accept-charset|action|autocomplete|enctype|method|name|novalidate|target][C]' +
2450
2500
  'fieldset[A|disabled|form|name][C|legend]' +
2451
2501
  'label[A|form|for][B]' +
2452
- 'input[A|type|accept|alt|autocomplete|checked|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|list|max|maxlength|min|' +
2502
+ 'input[A|type|accept|alt|autocomplete|autofocus|checked|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|list|max|maxlength|min|' +
2453
2503
  'multiple|pattern|placeholder|readonly|required|size|src|step|width|files|value|name][]' +
2454
2504
  'button[A|autofocus|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|name|value|type][B]' +
2455
2505
  'select[A|autofocus|disabled|form|multiple|name|size][option|optgroup]' +
@@ -2653,14 +2703,15 @@ tinymce.html.Styles = function(settings, schema) {
2653
2703
  }
2654
2704
 
2655
2705
  // Setup map objects
2656
- whiteSpaceElementsMap = createLookupTable('whitespace_elements', 'pre script style textarea');
2706
+ whiteSpaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea');
2657
2707
  selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
2658
2708
  shortEndedElementsMap = createLookupTable('short_ended_elements', 'area base basefont br col frame hr img input isindex link meta param embed source wbr');
2659
2709
  boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls');
2660
2710
  nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object', shortEndedElementsMap);
2661
- blockElementsMap = createLookupTable('block_elements', 'h1 h2 h3 h4 h5 h6 hr p div address pre form table tbody thead tfoot ' +
2662
- 'th tr td li ol ul caption blockquote center dl dt dd dir fieldset ' +
2663
- 'noscript menu isindex samp header footer article section hgroup aside nav figure option datalist select optgroup');
2711
+ textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' +
2712
+ 'blockquote center dir fieldset header footer article section hgroup aside nav figure');
2713
+ blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' +
2714
+ 'th tr td li ol ul caption dl dt dd noscript menu isindex samp option datalist select optgroup', textBlockElementsMap);
2664
2715
 
2665
2716
  // Converts a wildcard expression string to a regexp for example *a will become /.*a/.
2666
2717
  function patternToRegExp(str) {
@@ -2834,8 +2885,15 @@ tinymce.html.Styles = function(settings, schema) {
2834
2885
  customElementsMap[name] = cloneName;
2835
2886
 
2836
2887
  // If it's not marked as inline then add it to valid block elements
2837
- if (!inline)
2888
+ if (!inline) {
2889
+ blockElementsMap[name.toUpperCase()] = {};
2838
2890
  blockElementsMap[name] = {};
2891
+ }
2892
+
2893
+ // Add elements clone if needed
2894
+ if (!elements[name]) {
2895
+ elements[name] = elements[cloneName];
2896
+ }
2839
2897
 
2840
2898
  // Add custom elements at span/div positions
2841
2899
  each(children, function(element, child) {
@@ -2960,6 +3018,10 @@ tinymce.html.Styles = function(settings, schema) {
2960
3018
  return blockElementsMap;
2961
3019
  };
2962
3020
 
3021
+ self.getTextBlockElements = function() {
3022
+ return textBlockElementsMap;
3023
+ };
3024
+
2963
3025
  self.getShortEndedElements = function() {
2964
3026
  return shortEndedElementsMap;
2965
3027
  };
@@ -3025,6 +3087,8 @@ tinymce.html.Styles = function(settings, schema) {
3025
3087
  self.addCustomElements = addCustomElements;
3026
3088
 
3027
3089
  self.addValidChildren = addValidChildren;
3090
+
3091
+ self.elements = elements;
3028
3092
  };
3029
3093
  })(tinymce);
3030
3094
 
@@ -3082,7 +3146,7 @@ tinymce.html.Styles = function(settings, schema) {
3082
3146
  value = name in fillAttrsMap ? name : decode(value || val2 || val3 || ''); // Handle boolean attribute than value attribute
3083
3147
 
3084
3148
  // Validate name and value
3085
- if (validate && !isInternalElement && name.indexOf('data-') !== 0) {
3149
+ if (validate && !isInternalElement && name.indexOf('data-mce-') !== 0) {
3086
3150
  attrRule = validAttributesMap[name];
3087
3151
 
3088
3152
  // Find rule by pattern matching
@@ -3123,10 +3187,10 @@ tinymce.html.Styles = function(settings, schema) {
3123
3187
  '(?:!DOCTYPE([\\w\\W]*?)>)|' + // DOCTYPE
3124
3188
  '(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|' + // PI
3125
3189
  '(?:\\/([^>]+)>)|' + // End element
3126
- '(?:([A-Za-z0-9\\-\\:]+)((?:\\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\\/|\\s+)>)' + // Start element
3190
+ '(?:([A-Za-z0-9\\-\\:\\.]+)((?:\\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\\/|\\s+)>)' + // Start element
3127
3191
  ')', 'g');
3128
3192
 
3129
- attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:\\.|[^\"])*)\")|(?:\'((?:\\.|[^\'])*)\')|([^>\s]+)))?/g;
3193
+ attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g;
3130
3194
  specialElements = {
3131
3195
  'script' : /<\/script[^>]*>/gi,
3132
3196
  'style' : /<\/style[^>]*>/gi,
@@ -3609,7 +3673,7 @@ tinymce.html.Styles = function(settings, schema) {
3609
3673
  i = node.attributes.length;
3610
3674
  while (i--) {
3611
3675
  name = node.attributes[i].name;
3612
- if (name === "name" || name.indexOf('data-') === 0)
3676
+ if (name === "name" || name.indexOf('data-mce-') === 0)
3613
3677
  return false;
3614
3678
  }
3615
3679
  }
@@ -3665,18 +3729,41 @@ tinymce.html.Styles = function(settings, schema) {
3665
3729
 
3666
3730
  function fixInvalidChildren(nodes) {
3667
3731
  var ni, node, parent, parents, newParent, currentNode, tempNode, childNode, i,
3668
- childClone, nonEmptyElements, nonSplitableElements, sibling, nextNode;
3732
+ childClone, nonEmptyElements, nonSplitableElements, textBlockElements, sibling, nextNode;
3669
3733
 
3670
3734
  nonSplitableElements = tinymce.makeMap('tr,td,th,tbody,thead,tfoot,table');
3671
3735
  nonEmptyElements = schema.getNonEmptyElements();
3736
+ textBlockElements = schema.getTextBlockElements();
3672
3737
 
3673
3738
  for (ni = 0; ni < nodes.length; ni++) {
3674
3739
  node = nodes[ni];
3675
3740
 
3676
- // Already removed
3677
- if (!node.parent)
3741
+ // Already removed or fixed
3742
+ if (!node.parent || node.fixed)
3678
3743
  continue;
3679
3744
 
3745
+ // If the invalid element is a text block and the text block is within a parent LI element
3746
+ // Then unwrap the first text block and convert other sibling text blocks to LI elements similar to Word/Open Office
3747
+ if (textBlockElements[node.name] && node.parent.name == 'li') {
3748
+ // Move sibling text blocks after LI element
3749
+ sibling = node.next;
3750
+ while (sibling) {
3751
+ if (textBlockElements[sibling.name]) {
3752
+ sibling.name = 'li';
3753
+ sibling.fixed = true;
3754
+ node.parent.insert(sibling, node.parent);
3755
+ } else {
3756
+ break;
3757
+ }
3758
+
3759
+ sibling = sibling.next;
3760
+ }
3761
+
3762
+ // Unwrap current text block
3763
+ node.unwrap(node);
3764
+ continue;
3765
+ }
3766
+
3680
3767
  // Get list of all parent nodes until we find a valid parent to stick the child into
3681
3768
  parents = [node];
3682
3769
  for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && !nonSplitableElements[parent.name]; parent = parent.parent)
@@ -4054,7 +4141,8 @@ tinymce.html.Styles = function(settings, schema) {
4054
4141
  }
4055
4142
 
4056
4143
  // Trim start white space
4057
- textNode = node.prev;
4144
+ // Removed due to: #5424
4145
+ /*textNode = node.prev;
4058
4146
  if (textNode && textNode.type === 3) {
4059
4147
  text = textNode.value.replace(startWhiteSpaceRegExp, '');
4060
4148
 
@@ -4062,7 +4150,7 @@ tinymce.html.Styles = function(settings, schema) {
4062
4150
  textNode.value = text;
4063
4151
  else
4064
4152
  textNode.remove();
4065
- }
4153
+ }*/
4066
4154
  }
4067
4155
 
4068
4156
  // Check if we exited a whitespace preserved element
@@ -4572,6 +4660,12 @@ tinymce.dom = {};
4572
4660
  }
4573
4661
  }
4574
4662
 
4663
+ // Page already loaded then fire it directly
4664
+ if (doc.readyState == "complete") {
4665
+ readyHandler();
4666
+ return;
4667
+ }
4668
+
4575
4669
  // Use W3C method
4576
4670
  if (w3cEventModel) {
4577
4671
  addEvent(win, 'DOMContentLoaded', readyHandler);
@@ -10396,6 +10490,18 @@ window.tinymce.dom.Sizzle = Sizzle;
10396
10490
  }
10397
10491
  });
10398
10492
 
10493
+ htmlParser.addNodeFilter('noscript', function(nodes) {
10494
+ var i = nodes.length, node;
10495
+
10496
+ while (i--) {
10497
+ node = nodes[i].firstChild;
10498
+
10499
+ if (node) {
10500
+ node.value = tinymce.html.Entities.decode(node.value);
10501
+ }
10502
+ }
10503
+ });
10504
+
10399
10505
  // Force script into CDATA sections and remove the mce- prefix also add comments around styles
10400
10506
  htmlParser.addNodeFilter('script,style', function(nodes, name) {
10401
10507
  var i = nodes.length, node, value;
@@ -13037,6 +13143,9 @@ tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {
13037
13143
  if (id === undef)
13038
13144
  return this.editors;
13039
13145
 
13146
+ if (!this.editors.hasOwnProperty(id))
13147
+ return undef;
13148
+
13040
13149
  return this.editors[id];
13041
13150
  },
13042
13151
 
@@ -14189,7 +14298,11 @@ tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {
14189
14298
 
14190
14299
  // We must save before we hide so Safari doesn't crash
14191
14300
  self.save();
14192
- DOM.hide(self.getContainer());
14301
+
14302
+ // defer the call to hide to prevent an IE9 crash #4921
14303
+ setTimeout(function() {
14304
+ DOM.hide(self.getContainer());
14305
+ }, 1);
14193
14306
  DOM.setStyle(self.id, 'display', self.orgDisplay);
14194
14307
  },
14195
14308
 
@@ -16248,6 +16361,7 @@ tinymce.ForceBlocks = function(editor) {
16248
16361
  TreeWalker = tinymce.dom.TreeWalker,
16249
16362
  rangeUtils = new tinymce.dom.RangeUtils(dom),
16250
16363
  isValid = ed.schema.isValidChild,
16364
+ isArray = tinymce.isArray,
16251
16365
  isBlock = dom.isBlock,
16252
16366
  forcedRootBlock = ed.settings.forced_root_block,
16253
16367
  nodeIndex = dom.nodeIndex,
@@ -16259,9 +16373,9 @@ tinymce.ForceBlocks = function(editor) {
16259
16373
  undef,
16260
16374
  getContentEditable = dom.getContentEditable;
16261
16375
 
16262
- function isArray(obj) {
16263
- return obj instanceof Array;
16264
- };
16376
+ function isTextBlock(name) {
16377
+ return !!ed.schema.getTextBlocks()[name.toLowerCase()];
16378
+ }
16265
16379
 
16266
16380
  function getParents(node, selector) {
16267
16381
  return dom.getParents(node, selector, dom.getRoot());
@@ -17320,6 +17434,10 @@ tinymce.ForceBlocks = function(editor) {
17320
17434
  siblingName = start ? 'previousSibling' : 'nextSibling';
17321
17435
  root = dom.getRoot();
17322
17436
 
17437
+ function isBogusBr(node) {
17438
+ return node.nodeName == "BR" && node.getAttribute('data-mce-bogus') && !node.nextSibling;
17439
+ };
17440
+
17323
17441
  // If it's a text node and the offset is inside the text
17324
17442
  if (container.nodeType == 3 && !isWhiteSpaceNode(container)) {
17325
17443
  if (start ? startOffset > 0 : endOffset < container.nodeValue.length) {
@@ -17334,7 +17452,7 @@ tinymce.ForceBlocks = function(editor) {
17334
17452
 
17335
17453
  // Walk left/right
17336
17454
  for (sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
17337
- if (!isBookmarkNode(sibling) && !isWhiteSpaceNode(sibling)) {
17455
+ if (!isBookmarkNode(sibling) && !isWhiteSpaceNode(sibling) && !isBogusBr(sibling)) {
17338
17456
  return parent;
17339
17457
  }
17340
17458
  }
@@ -17493,7 +17611,7 @@ tinymce.ForceBlocks = function(editor) {
17493
17611
 
17494
17612
  // Expand to first wrappable block element or any block element
17495
17613
  if (!node)
17496
- node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, isBlock);
17614
+ node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, isTextBlock);
17497
17615
 
17498
17616
  // Exclude inner lists from wrapping
17499
17617
  if (node && format[0].wrapper)
@@ -18440,6 +18558,11 @@ tinymce.onAddEditor.add(function(tinymce, ed) {
18440
18558
  if (settings.keep_styles !== false) {
18441
18559
  do {
18442
18560
  if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(node.nodeName)) {
18561
+ // Never clone a caret containers
18562
+ if (node.id == '_mce_caret') {
18563
+ continue;
18564
+ }
18565
+
18443
18566
  clonedNode = node.cloneNode(false);
18444
18567
  dom.setAttrib(clonedNode, 'id', ''); // Remove ID since it needs to be document unique
18445
18568
 
@@ -18456,7 +18579,7 @@ tinymce.onAddEditor.add(function(tinymce, ed) {
18456
18579
 
18457
18580
  // BR is needed in empty blocks on non IE browsers
18458
18581
  if (!tinymce.isIE) {
18459
- caretNode.innerHTML = '<br>';
18582
+ caretNode.innerHTML = '<br data-mce-bogus="1">';
18460
18583
  }
18461
18584
 
18462
18585
  return block;
@@ -18772,6 +18895,12 @@ tinymce.onAddEditor.add(function(tinymce, ed) {
18772
18895
  parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
18773
18896
  containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
18774
18897
 
18898
+ // Enter inside block contained within a LI then split or insert before/after LI
18899
+ if (containerBlockName == 'LI' && !evt.ctrlKey) {
18900
+ parentBlock = containerBlock;
18901
+ parentBlockName = containerBlockName;
18902
+ }
18903
+
18775
18904
  // Handle enter in LI
18776
18905
  if (parentBlockName == 'LI') {
18777
18906
  if (!newBlockName && shiftKey) {