suneditor 2.45.0 → 2.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/lib/core.js CHANGED
@@ -44,6 +44,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
44
44
  _editorHeightPadding: 0,
45
45
  _listCamel: options.__listCommonStyle,
46
46
  _listKebab: util.camelToKebabCase(options.__listCommonStyle),
47
+ __focusTemp: context.element._focusTemp,
47
48
 
48
49
  /**
49
50
  * @description Document object of the iframe if created as an iframe || _d
@@ -56,7 +57,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
56
57
  * @private
57
58
  */
58
59
  _ww: null,
59
-
60
+
60
61
  /**
61
62
  * @description Closest ShadowRoot to editor if found
62
63
  * @private
@@ -103,7 +104,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
103
104
  * @description History object for undo, redo
104
105
  */
105
106
  history: null,
106
-
107
+
107
108
  /**
108
109
  * @description Elements and user options parameters of the suneditor
109
110
  */
@@ -231,7 +232,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
231
232
  * @description Tag blacklist RegExp object used in "_consistencyCheckOfHTML" method
232
233
  * @private
233
234
  */
234
- _htmlCheckBlacklistRegExp: null,
235
+ _htmlCheckBlacklistRegExp: null,
235
236
 
236
237
  /**
237
238
  * @description RegExp when using check disallowd tags. (b, i, ins, strike, s)
@@ -474,8 +475,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
474
475
  * @private
475
476
  */
476
477
  _cleanStyleRegExp: {
478
+ div: new _w.RegExp('\\s*[^-a-zA-Z](.+)\\s*:[^;]+(?!;)*', 'ig'),
477
479
  span: new _w.RegExp('\\s*[^-a-zA-Z](font-family|font-size|color|background-color)\\s*:[^;]+(?!;)*', 'ig'),
478
- format: new _w.RegExp('\\s*[^-a-zA-Z](text-align|margin-left|margin-right)\\s*:[^;]+(?!;)*', 'ig'),
480
+ format: new _w.RegExp('\\s*[^-a-zA-Z](text-align|margin-left|margin-right|width|height)\\s*:[^;]+(?!;)*', 'ig'),
479
481
  fontSizeUnit: new _w.RegExp('\\d+' + options.fontSizeUnit + '$', 'i'),
480
482
  },
481
483
 
@@ -524,7 +526,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
524
526
  * @description Save the current buttons states to "allCommandButtons" object
525
527
  * @private
526
528
  */
527
- _saveButtonStates: function () {
529
+ _saveButtonStates: function () {
528
530
  if (!this.allCommandButtons) this.allCommandButtons = {};
529
531
 
530
532
  const currentButtons = this.context.element._buttonTray.querySelectorAll('.se-menu-list button[data-display]');
@@ -542,9 +544,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
542
544
  */
543
545
  _recoverButtonStates: function () {
544
546
  if (this.allCommandButtons) {
545
- const currentButtons = this.context.element._buttonTray.querySelectorAll('.se-menu-list button[data-display]');
547
+ const currentButtons = this.context.element._buttonTray.querySelectorAll('.se-menu-list button[data-display]');
546
548
  for (let i = 0, button, command, oldButton; i < currentButtons.length; i++) {
547
- button = currentButtons[i];
549
+ button = currentButtons[i];
548
550
  command = button.getAttribute('data-command');
549
551
 
550
552
  oldButton = this.allCommandButtons[command];
@@ -552,7 +554,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
552
554
  button.parentElement.replaceChild(oldButton, button);
553
555
  if (this.context.tool[command]) this.context.tool[command] = oldButton;
554
556
  }
555
- }
557
+ }
556
558
  }
557
559
  },
558
560
 
@@ -579,7 +581,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
579
581
  this.commandMap[pluginName] = _target;
580
582
  this.activePlugins.push(pluginName);
581
583
  }
582
-
584
+
583
585
  if (typeof callBackFunction === 'function') callBackFunction();
584
586
  },
585
587
 
@@ -612,7 +614,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
612
614
  l += el.scrollLeft;
613
615
  el = el.parentElement;
614
616
  }
615
-
617
+
616
618
  el = this._shadowRoot ? this._shadowRoot.host : null;
617
619
  while (el) {
618
620
  t += el.scrollTop;
@@ -655,7 +657,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
655
657
  const menu = this.submenu = this._menuTray[submenuName];
656
658
  this.submenuActiveButton = element;
657
659
  this._setMenuPosition(element, menu);
658
-
660
+
659
661
  this._bindedSubmenuOff = this.submenuOff.bind(this);
660
662
  this.addDocEvent('mousedown', this._bindedSubmenuOff, false);
661
663
 
@@ -705,7 +707,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
705
707
  const menu = this.container = this._menuTray[containerName];
706
708
  this.containerActiveButton = element;
707
709
  this._setMenuPosition(element, menu);
708
-
710
+
709
711
  this._bindedContainerOff = this.containerOff.bind(this);
710
712
  this.addDocEvent('mousedown', this._bindedContainerOff, false);
711
713
 
@@ -790,7 +792,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
790
792
  let menuTop = -1 * (menuHeight - bt + 3);
791
793
  const insTop = toolbarTop - scrollTop + menuTop;
792
794
  const menuHeight_top = menuHeight + (insTop < 0 ? insTop : 0);
793
-
795
+
794
796
  if (menuHeight_top > menuHeight_bottom) {
795
797
  menu.style.height = menuHeight_top + 'px';
796
798
  menuTop = -1 * (menuHeight_top - bt + 3);
@@ -818,7 +820,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
818
820
  for (let i = 0, arg; i < arguments.length; i++) {
819
821
  arg = arguments[i];
820
822
  if (!arg) continue;
821
-
823
+
822
824
  if (typeof arg === 'string') {
823
825
  this.currentControllerName = arg;
824
826
  continue;
@@ -863,7 +865,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
863
865
  if (typeof this.controllerArray[i].contains === 'function' && this.controllerArray[i].contains(e.target)) return;
864
866
  }
865
867
  }
866
-
868
+
867
869
  if (this._fileManager.pluginRegExp.test(this.currentControllerName) && e && e.type === 'keydown' && e.keyCode !== 27) return;
868
870
  context.element.lineBreaker_t.style.display = context.element.lineBreaker_b.style.display = 'none';
869
871
  this._variable._lineBreakComp = null;
@@ -916,7 +918,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
916
918
  const l = offset.left - context.element.wysiwygFrame.scrollLeft + addOffset.left;
917
919
  const controllerW = controller.offsetWidth;
918
920
  const referElW = referEl.offsetWidth;
919
-
921
+
920
922
  const allow = util.hasClass(controller.firstElementChild, 'se-arrow') ? controller.firstElementChild : null;
921
923
 
922
924
  // rtl (Width value of the arrow element is 22px)
@@ -924,11 +926,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
924
926
  const rtlW = (controllerW > referElW) ? controllerW - referElW : 0;
925
927
  const rtlL = rtlW > 0 ? 0 : referElW - controllerW;
926
928
  controller.style.left = (l - rtlW + rtlL) + 'px';
927
-
929
+
928
930
  if (rtlW > 0) {
929
931
  if (allow) allow.style.left = ((controllerW - 14 < 10 + rtlW) ? (controllerW - 14) : (10 + rtlW)) + 'px';
930
932
  }
931
-
933
+
932
934
  const overSize = context.element.wysiwygFrame.offsetLeft - controller.offsetLeft;
933
935
  if (overSize > 0) {
934
936
  controller.style.left = '0px';
@@ -1065,7 +1067,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1065
1067
  endCon = endCon.childNodes[endOff] || endCon.childNodes[endOff - 1] || endCon;
1066
1068
  endOff = endOff > 0 ? endCon.nodeType === 1 ? 1 : endCon.textContent ? endCon.textContent.length : 0 : 0;
1067
1069
  }
1068
-
1070
+
1069
1071
  const range = this._wd.createRange();
1070
1072
 
1071
1073
  try {
@@ -1108,7 +1110,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1108
1110
  const range = this._variable._range || this._createDefaultRange();
1109
1111
  const selection = this.getSelection();
1110
1112
  if (range.collapsed === selection.isCollapsed || !context.element.wysiwyg.contains(selection.focusNode)) return range;
1111
-
1113
+
1112
1114
  if (selection.rangeCount > 0) {
1113
1115
  this._variable._range = selection.getRangeAt(0);
1114
1116
  return this._variable._range;
@@ -1162,10 +1164,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1162
1164
  * @returns {Node}
1163
1165
  */
1164
1166
  getSelectionNode: function () {
1165
- if (!context.element.wysiwyg.contains(this._variable._selectionNode)) this._editorRange();
1167
+ if (!context.element.wysiwyg.contains(this._variable._selectionNode)) this._editorRange();
1166
1168
  if (!this._variable._selectionNode) {
1167
1169
  const selectionNode = util.getChildElement(context.element.wysiwyg.firstChild, function (current) { return current.childNodes.length === 0 || current.nodeType === 3; }, false);
1168
- if (!selectionNode) {
1170
+ if (!selectionNode) {
1169
1171
  this._editorRange();
1170
1172
  } else {
1171
1173
  this._variable._selectionNode = selectionNode;
@@ -1244,7 +1246,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1244
1246
 
1245
1247
  range.setStart(focusEl, 0);
1246
1248
  range.setEnd(focusEl, 0);
1247
-
1249
+
1248
1250
  return range;
1249
1251
  },
1250
1252
 
@@ -1267,7 +1269,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1267
1269
  _resetRangeToTextNode: function () {
1268
1270
  const range = this.getRange();
1269
1271
  if (this._selectionVoid(range)) return false;
1270
-
1272
+
1271
1273
  let startCon = range.startContainer;
1272
1274
  let startOff = range.startOffset;
1273
1275
  let endCon = range.endContainer;
@@ -1306,7 +1308,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1306
1308
  tempCon = tempCon.childNodes[tempOffset] || tempCon.nextElementSibling || tempCon.nextSibling;
1307
1309
  tempOffset = 0;
1308
1310
  }
1309
-
1311
+
1310
1312
  let format = util.getFormatElement(tempCon, null);
1311
1313
  if (format === util.getRangeFormatElement(format, null)) {
1312
1314
  format = util.createElement(util.getParentElement(tempCon, util.isCell) ? 'DIV' : options.defaultTag);
@@ -1345,7 +1347,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1345
1347
  tempCon = tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] || !/FIGURE/i.test(tempChild[0].nodeName) ? tempChild[0] : (tempCon.previousElementSibling || tempCon.previousSibling || startCon);
1346
1348
  tempOffset = tempOffset > 0 ? tempCon.textContent.length : tempOffset;
1347
1349
  }
1348
-
1350
+
1349
1351
  let format = util.getFormatElement(tempCon, null);
1350
1352
  if (format === util.getRangeFormatElement(format, null)) {
1351
1353
  format = util.createElement(util.isCell(format) ? 'DIV' : options.defaultTag);
@@ -1406,7 +1408,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1406
1408
  let endLine = util.getFormatElement(endCon, null);
1407
1409
  let startIdx = null;
1408
1410
  let endIdx = null;
1409
-
1411
+
1410
1412
  const onlyTable = function (current) {
1411
1413
  return util.isTable(current) ? /^TABLE$/i.test(current.nodeName) : true;
1412
1414
  };
@@ -1415,7 +1417,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1415
1417
  let endRangeEl = util.getRangeFormatElement(endLine, onlyTable);
1416
1418
  if (util.isTable(startRangeEl) && util.isListCell(startRangeEl.parentNode)) startRangeEl = startRangeEl.parentNode;
1417
1419
  if (util.isTable(endRangeEl) && util.isListCell(endRangeEl.parentNode)) endRangeEl = endRangeEl.parentNode;
1418
-
1420
+
1419
1421
  const sameRange = startRangeEl === endRangeEl;
1420
1422
  for (let i = 0, len = lineNodes.length, line; i < len; i++) {
1421
1423
  line = lineNodes[i];
@@ -1446,13 +1448,13 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1446
1448
  getSelectedElementsAndComponents: function (removeDuplicate) {
1447
1449
  const commonCon = this.getRange().commonAncestorContainer;
1448
1450
  const myComponent = util.getParentElement(commonCon, util.isComponent);
1449
- const selectedLines = util.isTable(commonCon) ?
1451
+ const selectedLines = util.isTable(commonCon) ?
1450
1452
  this.getSelectedElements(null) :
1451
1453
  this.getSelectedElements(function (current) {
1452
1454
  const component = this.getParentElement(current, this.isComponent);
1453
1455
  return (this.isFormatElement(current) && (!component || component === myComponent)) || (this.isComponent(current) && !this.getFormatElement(current));
1454
1456
  }.bind(util));
1455
-
1457
+
1456
1458
  if (removeDuplicate) {
1457
1459
  for (let i = 0, len = selectedLines.length; i < len; i++) {
1458
1460
  for (let j = i - 1; j >= 0; j--) {
@@ -1583,7 +1585,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1583
1585
 
1584
1586
  if (!notSelect) {
1585
1587
  this.setRange(element, 0, element, 0);
1586
-
1588
+
1587
1589
  const fileComponentInfo = this.getFileComponent(element);
1588
1590
  if (fileComponentInfo) {
1589
1591
  this.selectComponent(fileComponentInfo.target, fileComponentInfo.pluginName);
@@ -1703,7 +1705,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1703
1705
 
1704
1706
  _dupleCheck: function (oNode, parentNode) {
1705
1707
  if (!util.isTextStyleElement(oNode)) return;
1706
-
1708
+
1707
1709
  const oStyles = (oNode.style.cssText.match(/[^;]+;/g) || []).map(function(v){ return v.trim(); });
1708
1710
  const nodeName = oNode.nodeName;
1709
1711
  if (/^span$/i.test(nodeName) && oStyles.length === 0) return oNode;
@@ -1757,7 +1759,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1757
1759
  let range = this.getRange();
1758
1760
  let line = util.isListCell(range.commonAncestorContainer) ? range.commonAncestorContainer : util.getFormatElement(this.getSelectionNode(), null);
1759
1761
  let insertListCell = util.isListCell(line) && (util.isListCell(oNode) || util.isList(oNode));
1760
-
1762
+
1761
1763
  let parentNode, originAfter, tempAfterNode, tempParentNode = null;
1762
1764
  const freeFormat = util.isFreeFormatElement(line);
1763
1765
  const isFormats = (!freeFormat && (util.isFormatElement(oNode) || util.isRangeFormatElement(oNode))) || util.isComponent(oNode);
@@ -1836,7 +1838,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1836
1838
  if (startCon.nodeType === 3) {
1837
1839
  parentNode = startCon.parentNode;
1838
1840
  }
1839
-
1841
+
1840
1842
  /** No Select range node */
1841
1843
  if (range.collapsed) {
1842
1844
  if (commonCon.nodeType === 3) {
@@ -1866,10 +1868,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1866
1868
  if (isSameContainer) {
1867
1869
  if (this.isEdgePoint(endCon, endOff)) afterNode = endCon.nextSibling;
1868
1870
  else afterNode = endCon.splitText(endOff);
1869
-
1871
+
1870
1872
  let removeNode = startCon;
1871
1873
  if (!this.isEdgePoint(startCon, startOff)) removeNode = startCon.splitText(startOff);
1872
-
1874
+
1873
1875
  parentNode.removeChild(removeNode);
1874
1876
  if (parentNode.childNodes.length === 0 && isFormats) {
1875
1877
  parentNode.innerHTML = '<br>';
@@ -1887,7 +1889,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1887
1889
  container.innerHTML = '<' + options.defaultTag + '><br></' + options.defaultTag + '>';
1888
1890
  }
1889
1891
  }
1890
-
1892
+
1891
1893
  if (util.isListCell(container) && oNode.nodeType === 3) {
1892
1894
  parentNode = container;
1893
1895
  afterNode = null;
@@ -1911,7 +1913,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1911
1913
  afterNode = isFormats ? endCon : container === prevContainer ? container.nextSibling : container;
1912
1914
  parentNode = (!afterNode || !afterNode.parentNode) ? commonCon : afterNode.parentNode;
1913
1915
  }
1914
-
1916
+
1915
1917
  while (afterNode && !util.isFormatElement(afterNode) && afterNode.parentNode !== commonCon) {
1916
1918
  afterNode = afterNode.parentNode;
1917
1919
  }
@@ -1931,7 +1933,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1931
1933
  parentNode = context.element.wysiwyg;
1932
1934
  afterNode = null;
1933
1935
  }
1934
-
1936
+
1935
1937
  if (util.isFormatElement(oNode) || util.isRangeFormatElement(oNode) || (!util.isListCell(parentNode) && util.isComponent(oNode))) {
1936
1938
  const oldParent = parentNode;
1937
1939
  if (util.isList(afterNode)) {
@@ -1946,15 +1948,15 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1946
1948
  parentNode = rangeCon ? container : container.parentNode;
1947
1949
  afterNode = rangeCon ? null : container.nextSibling;
1948
1950
  }
1949
-
1951
+
1950
1952
  if (oldParent.childNodes.length === 0 && parentNode !== oldParent) util.removeItem(oldParent);
1951
1953
  }
1952
-
1954
+
1953
1955
  if (isFormats && !freeFormat && !util.isRangeFormatElement(parentNode) && !util.isListCell(parentNode) && !util.isWysiwygDiv(parentNode)) {
1954
1956
  afterNode = parentNode.nextElementSibling;
1955
1957
  parentNode = parentNode.parentNode;
1956
1958
  }
1957
-
1959
+
1958
1960
  if (util.isWysiwygDiv(parentNode) && (oNode.nodeType === 3 || util.isBreak(oNode))) {
1959
1961
  const fNode = util.createElement(options.defaultTag);
1960
1962
  fNode.appendChild(oNode);
@@ -2051,12 +2053,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2051
2053
  const next = oNode.nextSibling;
2052
2054
  const previousText = (!previous || previous.nodeType === 1 || util.onlyZeroWidthSpace(previous)) ? '' : previous.textContent;
2053
2055
  const nextText = (!next || next.nodeType === 1 || util.onlyZeroWidthSpace(next)) ? '' : next.textContent;
2054
-
2056
+
2055
2057
  if (previous && previousText.length > 0) {
2056
2058
  oNode.textContent = previousText + oNode.textContent;
2057
2059
  util.removeItem(previous);
2058
2060
  }
2059
-
2061
+
2060
2062
  if (next && next.length > 0) {
2061
2063
  oNode.textContent += nextText;
2062
2064
  util.removeItem(next);
@@ -2069,7 +2071,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2069
2071
  };
2070
2072
 
2071
2073
  this.setRange(oNode, newRange.startOffset, oNode, newRange.endOffset);
2072
-
2074
+
2073
2075
  return newRange;
2074
2076
  } else if (!util.isBreak(oNode) && !util.isListCell(oNode) && util.isFormatElement(parentNode)) {
2075
2077
  let zeroWidth = null;
@@ -2077,18 +2079,18 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2077
2079
  zeroWidth = util.createTextNode(util.zeroWidthSpace);
2078
2080
  oNode.parentNode.insertBefore(zeroWidth, oNode);
2079
2081
  }
2080
-
2082
+
2081
2083
  if (!oNode.nextSibling || util.isBreak(oNode.nextSibling)) {
2082
2084
  zeroWidth = util.createTextNode(util.zeroWidthSpace);
2083
2085
  oNode.parentNode.insertBefore(zeroWidth, oNode.nextSibling);
2084
2086
  }
2085
-
2087
+
2086
2088
  if (util._isIgnoreNodeChange(oNode)) {
2087
2089
  oNode = oNode.nextSibling;
2088
2090
  offset = 0;
2089
2091
  }
2090
2092
  }
2091
-
2093
+
2092
2094
  this.setRange(oNode, offset, oNode, offset);
2093
2095
  }
2094
2096
 
@@ -2102,11 +2104,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2102
2104
  _setIntoFreeFormat: function (oNode) {
2103
2105
  const parentNode = oNode.parentNode;
2104
2106
  let oNodeChildren, lastONode;
2105
-
2107
+
2106
2108
  while (util.isFormatElement(oNode) || util.isRangeFormatElement(oNode)) {
2107
2109
  oNodeChildren = oNode.childNodes;
2108
2110
  lastONode = null;
2109
-
2111
+
2110
2112
  while (oNodeChildren[0]) {
2111
2113
  lastONode = oNodeChildren[0];
2112
2114
  if (util.isFormatElement(lastONode) || util.isRangeFormatElement(lastONode)) {
@@ -2115,10 +2117,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2115
2117
  oNodeChildren = oNode.childNodes;
2116
2118
  continue;
2117
2119
  }
2118
-
2120
+
2119
2121
  parentNode.insertBefore(lastONode, oNode);
2120
2122
  }
2121
-
2123
+
2122
2124
  if (oNode.childNodes.length === 0) util.removeItem(oNode);
2123
2125
  oNode = util.createElement('BR');
2124
2126
  parentNode.insertBefore(oNode, lastONode.nextSibling);
@@ -2136,6 +2138,27 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2136
2138
  this._resetRangeToTextNode();
2137
2139
 
2138
2140
  const range = this.getRange();
2141
+
2142
+ if (range.startContainer === range.endContainer) {
2143
+ const fileComponent = util.getParentElement(range.startContainer, util.isMediaComponent);
2144
+ if (fileComponent) {
2145
+ const br = util.createElement('BR');
2146
+ const format = util.createElement(options.defaultTag);
2147
+ format.appendChild(br);
2148
+
2149
+ util.changeElement(fileComponent, format);
2150
+
2151
+ core.setRange(format, 0, format, 0);
2152
+ this.history.push(true);
2153
+
2154
+ return {
2155
+ container: format,
2156
+ offset: 0,
2157
+ prevContainer: null
2158
+ };
2159
+ }
2160
+ }
2161
+
2139
2162
  const isStartEdge = range.startOffset === 0;
2140
2163
  const isEndEdge = core.isEdgePoint(range.endContainer, range.endOffset, 'end');
2141
2164
  let prevContainer = null;
@@ -2143,8 +2166,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2143
2166
  let endNextEl = null;
2144
2167
  if (isStartEdge) {
2145
2168
  startPrevEl = util.getFormatElement(range.startContainer);
2146
- prevContainer = startPrevEl.previousElementSibling;
2147
- startPrevEl = startPrevEl ? prevContainer : startPrevEl;
2169
+ if (startPrevEl) {
2170
+ prevContainer = startPrevEl.previousElementSibling;
2171
+ startPrevEl = prevContainer;
2172
+ }
2148
2173
  }
2149
2174
  if (isEndEdge) {
2150
2175
  endNextEl = util.getFormatElement(range.endContainer);
@@ -2192,7 +2217,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2192
2217
  startNode = startNode.parentNode;
2193
2218
  }
2194
2219
  }
2195
-
2220
+
2196
2221
  for (let i = endIndex - 1, endNode = endCon; i > startIndex; i--) {
2197
2222
  if (childNodes[i] === endNode.parentNode && childNodes[i].nodeType === 1) {
2198
2223
  childNodes.splice(i, 1);
@@ -2288,7 +2313,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2288
2313
  container = endCon && endCon.parentNode ? endCon : startCon && startCon.parentNode ? startCon : (range.endContainer || range.startContainer);
2289
2314
  offset = (!isStartEdge && !isEndEdge) ? offset : isEndEdge ? container.textContent.length : 0;
2290
2315
  }
2291
-
2316
+
2292
2317
  if (!util.isWysiwygDiv(container) && container.childNodes.length === 0) {
2293
2318
  const rc = util.removeItemAllParents(container, null, null);
2294
2319
  if (rc) container = rc.sc || rc.ec || context.element.wysiwyg;
@@ -2321,7 +2346,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2321
2346
  util.removeItem(item);
2322
2347
 
2323
2348
  if(!util.isListCell(format)) return;
2324
-
2349
+
2325
2350
  util.removeItemAllParents(format, null, null);
2326
2351
 
2327
2352
  if (format && util.isList(format.firstChild)) {
@@ -2384,7 +2409,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2384
2409
  beforeTag = standTag.nextSibling;
2385
2410
  pElement = standTag.parentNode;
2386
2411
  }
2387
-
2412
+
2388
2413
  let parentDepth = util.getElementDepth(standTag);
2389
2414
  let listParent = null;
2390
2415
  const lineArr = [];
@@ -2397,7 +2422,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2397
2422
 
2398
2423
  return cc ? cc.ec : before;
2399
2424
  };
2400
-
2425
+
2401
2426
  for (let i = 0, len = rangeLines.length, line, originParent, depth, before, nextLine, nextList, nested; i < len; i++) {
2402
2427
  line = rangeLines[i];
2403
2428
  originParent = line.parentNode;
@@ -2465,7 +2490,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2465
2490
  pElement = originParent;
2466
2491
  beforeTag = line.nextSibling;
2467
2492
  }
2468
-
2493
+
2469
2494
  rangeElement.appendChild(line);
2470
2495
 
2471
2496
  if (pElement !== originParent) {
@@ -2521,7 +2546,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2521
2546
  let firstNode = null;
2522
2547
  let lastNode = null;
2523
2548
  let rangeEl = rangeElement.cloneNode(false);
2524
-
2549
+
2525
2550
  const removeArray = [];
2526
2551
  const newList = util.isList(newRangeElement);
2527
2552
  let insertedNew = false;
@@ -2538,7 +2563,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2538
2563
  parent.insertBefore(insNode, sibling);
2539
2564
  return insNode;
2540
2565
  }
2541
-
2566
+
2542
2567
  const insChildren = (moveComplete ? insNode : originNode).childNodes;
2543
2568
  let format = insNode.cloneNode(false);
2544
2569
  let first = null;
@@ -2595,7 +2620,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2595
2620
  for (let i = 0, len = children.length, insNode, lineIndex, next; i < len; i++) {
2596
2621
  insNode = children[i];
2597
2622
  if (insNode.nodeType === 3 && util.isList(rangeEl)) continue;
2598
-
2623
+
2599
2624
  moveComplete = false;
2600
2625
  if (remove && i === 0) {
2601
2626
  if (!selectedFormats || selectedFormats.length === len || selectedFormats[0] === insNode) {
@@ -2651,7 +2676,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2651
2676
  } else {
2652
2677
  insNode = appendNode(parent, insNode, rangeElement, children[i]);
2653
2678
  }
2654
-
2679
+
2655
2680
  if (!reset) {
2656
2681
  if (selectedFormats) {
2657
2682
  lastNode = insNode;
@@ -2685,7 +2710,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2685
2710
  if (rangeEl && rangeEl.children.length > 0) {
2686
2711
  rangeParent.insertBefore(rangeEl, rangeRight);
2687
2712
  }
2688
-
2713
+
2689
2714
  if (newRangeElement) firstNode = newRangeElement.previousSibling;
2690
2715
  else if (!firstNode) firstNode = rangeElement.previousSibling;
2691
2716
  rangeRight = rangeElement.nextSibling !== rangeEl ? rangeElement.nextSibling : rangeEl ? rangeEl.nextSibling : null;
@@ -2722,7 +2747,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2722
2747
 
2723
2748
  this.effectNode = null;
2724
2749
  if (notHistoryPush) return edge;
2725
-
2750
+
2726
2751
  if (!remove && edge) {
2727
2752
  if (!selectedFormats) {
2728
2753
  this.setRange(edge.sc, 0, edge.sc, 0);
@@ -2819,7 +2844,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2819
2844
  let range = this.getRange_addLine(this.getRange(), null);
2820
2845
  styleArray = styleArray && styleArray.length > 0 ? styleArray : false;
2821
2846
  removeNodeArray = removeNodeArray && removeNodeArray.length > 0 ? removeNodeArray : false;
2822
-
2847
+
2823
2848
  const isRemoveNode = !appendNode;
2824
2849
  const isRemoveFormat = isRemoveNode && !removeNodeArray && !styleArray;
2825
2850
  let startCon = range.startContainer;
@@ -2878,7 +2903,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2878
2903
  let sNode = startCon;
2879
2904
  let checkCnt = 0;
2880
2905
  const checkAttrs = [];
2881
-
2906
+
2882
2907
  const checkStyles = appendNode.style;
2883
2908
  for (let i = 0, len = checkStyles.length; i < len; i++) {
2884
2909
  checkAttrs.push(checkStyles[i]);
@@ -2895,7 +2920,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2895
2920
  if (sNode.nodeType === 1) {
2896
2921
  const s = checkAttrs[i];
2897
2922
  const classReg = /^\./.test(s) ? new wRegExp('\\s*' + s.replace(/^\./, '') + '(\\s+|$)', 'ig') : false;
2898
-
2923
+
2899
2924
  const styleCheck = isRemoveNode ? !!sNode.style[s] : (!!sNode.style[s] && !!appendNode.style[s] && sNode.style[s] === appendNode.style[s]);
2900
2925
  const classCheck = classReg === false ? false : isRemoveNode ? !!sNode.className.match(classReg) : !!sNode.className.match(classReg) && !!appendNode.className.match(classReg);
2901
2926
  if (styleCheck || classCheck) {
@@ -2905,7 +2930,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
2905
2930
  }
2906
2931
  sNode = sNode.parentNode;
2907
2932
  }
2908
-
2933
+
2909
2934
  if (checkCnt >= checkAttrs.length) return;
2910
2935
  }
2911
2936
  }
@@ -3029,7 +3054,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3029
3054
  endOff = endCon.textContent.length;
3030
3055
  }
3031
3056
 
3032
-
3057
+
3033
3058
  const oneLine = util.getFormatElement(startCon, null) === util.getFormatElement(endCon, null);
3034
3059
  const endLength = lineNodes.length - (oneLine ? 0 : 1);
3035
3060
 
@@ -3056,7 +3081,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3056
3081
  start.offset = newRange.startOffset;
3057
3082
  end.container = newRange.endContainer;
3058
3083
  end.offset = newRange.endOffset;
3059
-
3084
+
3060
3085
  if (start.container === end.container && util.onlyZeroWidthSpace(start.container)) {
3061
3086
  start.offset = end.offset = 1;
3062
3087
  }
@@ -3126,7 +3151,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3126
3151
 
3127
3152
  const children = util.getArrayItem((el).childNodes, function (current) { return !util.isBreak(current); }, true);
3128
3153
  const elStyles = el.style;
3129
-
3154
+
3130
3155
  const ec = [], ek = [], elKeys = util.getValues(elStyles);
3131
3156
  for (let i = 0, len = this._listKebab.length; i < len; i++) {
3132
3157
  if (elKeys.indexOf(this._listKebab[i]) > -1 && styleArray.indexOf(this._listKebab[i]) > -1) {
@@ -3161,7 +3186,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3161
3186
  appliedEl = true;
3162
3187
  }
3163
3188
  }
3164
-
3189
+
3165
3190
  if (sel.childNodes.length > 0) {
3166
3191
  el.insertBefore(sel, r);
3167
3192
  appliedEl = true;
@@ -3181,12 +3206,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3181
3206
  */
3182
3207
  _setCommonListStyle: function (el, child) {
3183
3208
  if (!util.isListCell(el)) return;
3184
-
3209
+
3185
3210
  const children = util.getArrayItem((child || el).childNodes, function (current) { return !util.isBreak(current); }, true);
3186
3211
  child = children[0];
3187
-
3212
+
3188
3213
  if (!child || children.length > 1 || child.nodeType !== 1) return;
3189
-
3214
+
3190
3215
  // set cell style---
3191
3216
  const childStyle = child.style;
3192
3217
  const elStyle = el.style;
@@ -3232,7 +3257,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3232
3257
  _stripRemoveNode: function (removeNode) {
3233
3258
  const element = removeNode.parentNode;
3234
3259
  if (!removeNode || removeNode.nodeType === 3 || !element) return;
3235
-
3260
+
3236
3261
  const children = removeNode.childNodes;
3237
3262
  while (children[0]) {
3238
3263
  element.insertBefore(children[0], removeNode);
@@ -3291,7 +3316,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3291
3316
  if (util.onlyZeroWidthSpace(startCon.textContent.slice(0, startOff)) && util.onlyZeroWidthSpace(endCon.textContent.slice(endOff))) {
3292
3317
  const children = parentCon.childNodes;
3293
3318
  let sameTag = true;
3294
-
3319
+
3295
3320
  for (let i = 0, len = children.length, c, s, e, z; i < len; i++) {
3296
3321
  c = children[i];
3297
3322
  z = !util.onlyZeroWidthSpace(c);
@@ -3308,10 +3333,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3308
3333
  break;
3309
3334
  }
3310
3335
  }
3311
-
3336
+
3312
3337
  if (sameTag) {
3313
3338
  util.copyTagAttributes(parentCon, newInnerNode);
3314
-
3339
+
3315
3340
  return {
3316
3341
  ancestor: element,
3317
3342
  startContainer: startCon,
@@ -3345,7 +3370,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3345
3370
  if (regExp && vNode.style.cssText.length > 0) {
3346
3371
  style = regExp.test(vNode.style.cssText);
3347
3372
  }
3348
-
3373
+
3349
3374
  return !style;
3350
3375
  }
3351
3376
 
@@ -3363,11 +3388,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3363
3388
  let line = pNode;
3364
3389
  anchorNode = _getMaintainedNode(child);
3365
3390
  const prevNode = util.createTextNode(startContainer.nodeType === 1 ? '' : startContainer.substringData(0, startOffset));
3366
- const textNode = util.createTextNode(startContainer.nodeType === 1 ? '' : startContainer.substringData(startOffset,
3367
- isSameNode ?
3368
- (endOffset >= startOffset ? endOffset - startOffset : startContainer.data.length - startOffset) :
3391
+ const textNode = util.createTextNode(startContainer.nodeType === 1 ? '' : startContainer.substringData(startOffset,
3392
+ isSameNode ?
3393
+ (endOffset >= startOffset ? endOffset - startOffset : startContainer.data.length - startOffset) :
3369
3394
  startContainer.data.length - startOffset)
3370
- );
3395
+ );
3371
3396
 
3372
3397
  if (anchorNode) {
3373
3398
  const a = _getMaintainedNode(ancestor);
@@ -3386,7 +3411,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3386
3411
  }
3387
3412
  anchorNode = anchorNode.cloneNode(false);
3388
3413
  }
3389
-
3414
+
3390
3415
  if (!util.onlyZeroWidthSpace(prevNode)) {
3391
3416
  ancestor.appendChild(prevNode);
3392
3417
  }
@@ -3564,13 +3589,13 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3564
3589
  appendNode.appendChild(newNode);
3565
3590
  appendNode = newNode;
3566
3591
  }
3567
-
3592
+
3568
3593
  if (_isMaintainedNode(newInnerNode.parentNode) && !_isMaintainedNode(childNode) && !util.onlyZeroWidthSpace(newInnerNode)) {
3569
3594
  newInnerNode = newInnerNode.cloneNode(false);
3570
3595
  pNode.appendChild(newInnerNode);
3571
3596
  nNodeArray.push(newInnerNode);
3572
3597
  }
3573
-
3598
+
3574
3599
  if (!endPass && !anchorNode && _isMaintainedNode(childNode)) {
3575
3600
  newInnerNode = newInnerNode.cloneNode(false);
3576
3601
  const aChildren = childNode.childNodes;
@@ -3631,7 +3656,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3631
3656
  for (let i = 0; i < nNodeArray.length; i++) {
3632
3657
  let removeNode = nNodeArray[i];
3633
3658
  let textNode, textNode_s, textNode_e;
3634
-
3659
+
3635
3660
  if (collapsed) {
3636
3661
  textNode = util.createTextNode(util.zeroWidthSpace);
3637
3662
  pNode.replaceChild(textNode, removeNode);
@@ -3660,7 +3685,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3660
3685
  this._stripRemoveNode(nNodeArray[i]);
3661
3686
  }
3662
3687
  }
3663
-
3688
+
3664
3689
  if (collapsed) {
3665
3690
  startContainer = endContainer = newInnerNode;
3666
3691
  }
@@ -3745,7 +3770,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3745
3770
 
3746
3771
  if (sameTag) {
3747
3772
  util.copyTagAttributes(parentCon, newInnerNode);
3748
-
3773
+
3749
3774
  return {
3750
3775
  ancestor: element,
3751
3776
  container: startCon,
@@ -3823,7 +3848,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
3823
3848
  pNode.appendChild(newInnerNode);
3824
3849
  nNodeArray.push(newInnerNode);
3825
3850
  }
3826
-
3851
+
3827
3852
  if (!anchorNode && _isMaintainedNode(childNode)) {
3828
3853
  newInnerNode = newInnerNode.cloneNode(false);
3829
3854
  const aChildren = childNode.childNodes;
@@ -4073,7 +4098,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4073
4098
  pNode.appendChild(newInnerNode);
4074
4099
  newInnerNode = newInnerNode.cloneNode(false);
4075
4100
  }
4076
-
4101
+
4077
4102
  cloneChild = child.cloneNode(true);
4078
4103
  pNode.appendChild(cloneChild);
4079
4104
  pNode.appendChild(newInnerNode);
@@ -4108,7 +4133,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4108
4133
  if (isRemoveFormat && isRemoveNode) {
4109
4134
  for (let i = 0; i < nNodeArray.length; i++) {
4110
4135
  let removeNode = nNodeArray[i];
4111
-
4136
+
4112
4137
  const rChildren = removeNode.childNodes;
4113
4138
  while (rChildren[0]) {
4114
4139
  pNode.insertBefore(rChildren[0], removeNode);
@@ -4149,7 +4174,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4149
4174
  if (parentCon.nodeName === newInnerNode.nodeName) break;
4150
4175
  parentCon = parentCon.parentNode;
4151
4176
  }
4152
-
4177
+
4153
4178
  if (!isRemoveNode && parentCon.nodeName === newInnerNode.nodeName && !util.isFormatElement(parentCon) && !parentCon.previousSibling && util.onlyZeroWidthSpace(endCon.textContent.slice(endOff))) {
4154
4179
  let sameTag = true;
4155
4180
  let e = endCon.nextSibling;
@@ -4163,7 +4188,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4163
4188
 
4164
4189
  if (sameTag) {
4165
4190
  util.copyTagAttributes(parentCon, newInnerNode);
4166
-
4191
+
4167
4192
  return {
4168
4193
  ancestor: element,
4169
4194
  container: endCon,
@@ -4326,7 +4351,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4326
4351
  }
4327
4352
 
4328
4353
  if (util.isBreak(child)) newInnerNode.appendChild(child.cloneNode(false));
4329
-
4354
+
4330
4355
  if (anchorNode) {
4331
4356
  anchorNode.insertBefore(newInnerNode, anchorNode.firstChild);
4332
4357
  pNode.insertBefore(anchorNode, pNode.firstChild);
@@ -4367,7 +4392,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4367
4392
  if (isRemoveFormat) {
4368
4393
  for (let i = 0; i < nNodeArray.length; i++) {
4369
4394
  let removeNode = nNodeArray[i];
4370
-
4395
+
4371
4396
  const rChildren = removeNode.childNodes;
4372
4397
  let textNode = null;
4373
4398
  while (rChildren[0]) {
@@ -4414,7 +4439,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4414
4439
  container = newInnerNode;
4415
4440
  offset = 1;
4416
4441
  }
4417
-
4442
+
4418
4443
  // node change
4419
4444
  const offsets = {s: 0, e: 0};
4420
4445
  const path = util.getNodePath(container, pNode, offsets);
@@ -4465,16 +4490,16 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4465
4490
 
4466
4491
  event._showToolbarBalloon();
4467
4492
  event._showToolbarInline();
4468
- }
4493
+ }
4469
4494
  }
4470
4495
  return;
4471
4496
  }
4472
-
4497
+
4473
4498
  if (/container/.test(display) && (this._menuTray[command] === null || target !== this.containerActiveButton)) {
4474
4499
  this.callPlugin(command, this.containerOn.bind(this, target), target);
4475
4500
  return;
4476
- }
4477
-
4501
+ }
4502
+
4478
4503
  if (this.isReadOnly && util.arrayIncludes(this.resizingDisabledButtons, target)) return;
4479
4504
  if (/submenu/.test(display) && (this._menuTray[command] === null || target !== this.submenuActiveButton)) {
4480
4505
  this.callPlugin(command, this.submenuOn.bind(this, target), target);
@@ -4692,16 +4717,16 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4692
4717
  this._variable._wysiwygOriginCssText = this._variable._wysiwygOriginCssText.replace(/(\s?display(\s+)?:(\s+)?)[a-zA-Z]+(?=;)/, 'display: block');
4693
4718
 
4694
4719
  if (options.height === 'auto' && !options.codeMirrorEditor) context.element.code.style.height = '0px';
4695
-
4720
+
4696
4721
  this._variable.isCodeView = false;
4697
-
4722
+
4698
4723
  if (!this._variable.isFullScreen) {
4699
4724
  this._notHideToolbar = false;
4700
4725
  if (/balloon|balloon-always/i.test(options.mode)) {
4701
4726
  context.element._arrow.style.display = '';
4702
4727
  this._isInline = false;
4703
4728
  this._isBalloon = true;
4704
- event._hideToolbar();
4729
+ event._hideToolbar();
4705
4730
  }
4706
4731
  }
4707
4732
 
@@ -4720,9 +4745,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4720
4745
 
4721
4746
  if (this._variable.isFullScreen) context.element.code.style.height = '100%';
4722
4747
  else if (options.height === 'auto' && !options.codeMirrorEditor) context.element.code.style.height = context.element.code.scrollHeight > 0 ? (context.element.code.scrollHeight + 'px') : 'auto';
4723
-
4748
+
4724
4749
  if (options.codeMirrorEditor) options.codeMirrorEditor.refresh();
4725
-
4750
+
4726
4751
  this._variable.isCodeView = true;
4727
4752
 
4728
4753
  if (!this._variable.isFullScreen) {
@@ -4735,7 +4760,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4735
4760
  event._showToolbarInline();
4736
4761
  }
4737
4762
  }
4738
-
4763
+
4739
4764
  this._variable._range = null;
4740
4765
  context.element.code.focus();
4741
4766
  util.addClass(this._styleCommandMap.codeView, 'active');
@@ -4825,12 +4850,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4825
4850
  const code = context.element.code;
4826
4851
  const _var = this._variable;
4827
4852
  this.controllersOff();
4828
-
4853
+
4829
4854
  const wasToolbarHidden = (toolbar.style.display === 'none' || (this._isInline && !this._inlineToolbarAttr.isShow));
4830
4855
 
4831
4856
  if (!_var.isFullScreen) {
4832
4857
  _var.isFullScreen = true;
4833
-
4858
+
4834
4859
  _var._fullScreenAttrs.inline = this._isInline;
4835
4860
  _var._fullScreenAttrs.balloon = this._isBalloon;
4836
4861
 
@@ -4838,7 +4863,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4838
4863
  this._isInline = false;
4839
4864
  this._isBalloon = false;
4840
4865
  }
4841
-
4866
+
4842
4867
  if (!!options.toolbarContainer) context.element.relative.insertBefore(toolbar, editorArea);
4843
4868
 
4844
4869
  topArea.style.position = 'fixed';
@@ -4998,7 +5023,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
4998
5023
  core.submenuOff();
4999
5024
  core.containerOff();
5000
5025
  core.controllersOff();
5001
-
5026
+
5002
5027
  const contentsHTML = options.previewTemplate ? options.previewTemplate.replace(/\{\{\s*contents\s*\}\}/i, this.getContents(true)) : this.getContents(true);
5003
5028
  const windowObject = _w.open('', '_blank');
5004
5029
  windowObject.mimeType = 'text/html';
@@ -5026,7 +5051,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5026
5051
  for (let i = 0, len = styles.length; i < len; i++) {
5027
5052
  linkHTML += styles[i].outerHTML;
5028
5053
  }
5029
-
5054
+
5030
5055
  windowObject.document.write('' +
5031
5056
  '<!DOCTYPE html><html>' +
5032
5057
  '<head>' +
@@ -5111,7 +5136,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5111
5136
  */
5112
5137
  setContents: function (html) {
5113
5138
  this.removeRange();
5114
-
5139
+
5115
5140
  const convertValue = (html === null || html === undefined) ? '' : this.convertContentsForEditor(html, null, null);
5116
5141
  if (!this._variable.isCodeView) {
5117
5142
  context.element.wysiwyg.innerHTML = convertValue;
@@ -5190,7 +5215,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5190
5215
  ch[i].outerHTML = ch[i].innerHTML;
5191
5216
  }
5192
5217
 
5193
- if (!requireFormat || (util.isFormatElement(node) || util.isRangeFormatElement(node) || util.isComponent(node) || util.isMedia(node) || (util.isAnchor(node) && util.isMedia(node.firstElementChild)))) {
5218
+ if (!requireFormat || (util.isFormatElement(node) || util.isRangeFormatElement(node) || util.isComponent(node) || util.isFigures(node) || (util.isAnchor(node) && util.isMedia(node.firstElementChild)))) {
5194
5219
  return util.isSpanWithoutAttr(node) ? node.innerHTML : node.outerHTML;
5195
5220
  } else {
5196
5221
  return '<' + defaultTag + '>' + (util.isSpanWithoutAttr(node) ? node.innerHTML : node.outerHTML) + '</' + defaultTag + '>';
@@ -5237,16 +5262,16 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5237
5262
  * @private
5238
5263
  */
5239
5264
  _deleteDisallowedTags: function (html) {
5240
- html = html
5241
- .replace(this.__disallowedTagsRegExp, '')
5242
- .replace(/<[a-z0-9]+\:[a-z0-9]+[^>^\/]*>[^>]*<\/[a-z0-9]+\:[a-z0-9]+>/gi, '');
5265
+ html = html
5266
+ .replace(this.__disallowedTagsRegExp, '')
5267
+ .replace(/<[a-z0-9]+\:[a-z0-9]+[^>^\/]*>[^>]*<\/[a-z0-9]+\:[a-z0-9]+>/gi, '');
5243
5268
 
5244
5269
  if (!/\bfont\b/i.test(this.options._editorTagsWhitelist)) {
5245
5270
  html = html.replace(/(<\/?)font(\s?)/gi, '$1span$2');
5246
5271
  }
5247
5272
 
5248
- return html.replace(this.editorTagsWhitelistRegExp, '').replace(this.editorTagsBlacklistRegExp, '');
5249
- },
5273
+ return html.replace(this.editorTagsWhitelistRegExp, '').replace(this.editorTagsBlacklistRegExp, '');
5274
+ },
5250
5275
 
5251
5276
  _convertFontSize: function (to, size) {
5252
5277
  const math = this._w.Math;
@@ -5254,7 +5279,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5254
5279
  const sizeNum = value ? value[1] * 1 : util.fontValueMap[size];
5255
5280
  const from = value ? value[2] : 'rem';
5256
5281
  let pxSize = sizeNum;
5257
-
5282
+
5258
5283
  if (/em/.test(from)) {
5259
5284
  pxSize = math.round(sizeNum / 0.0625);
5260
5285
  } else if (from === 'pt') {
@@ -5277,7 +5302,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5277
5302
 
5278
5303
  _cleanStyle: function (m, v, name) {
5279
5304
  let sv = (m.match(/style\s*=\s*(?:"|')[^"']*(?:"|')/) || [])[0];
5280
- if (/span/i.test(name) && !sv && (m.match(/<span\s(.+)/) || [])[1]) {
5305
+ if (/span/i.test(name) && !sv && (m.match(/<[^\s]+\s(.+)/) || [])[1]) {
5281
5306
  const size = (m.match(/\ssize="([^"]+)"/i) || [])[1];
5282
5307
  const face = (m.match(/\sface="([^"]+)"/i) || [])[1];
5283
5308
  const color = (m.match(/\scolor="([^"]+)"/i) || [])[1];
@@ -5292,7 +5317,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5292
5317
  if (style) {
5293
5318
  const allowedStyle = [];
5294
5319
  for (let i = 0, len = style.length, r; i < len; i++) {
5295
- r = style[i].match(/([a-zA-Z0-9-]+)(:)([^"]+)/);
5320
+ r = style[i].match(/([a-zA-Z0-9-]+)(:)([^"']+)/);
5296
5321
  if (r && !/inherit|initial|revert|unset/i.test(r[3])) {
5297
5322
  const k = util.kebabToCamelCase(r[1].trim());
5298
5323
  const v = this.wwComputedStyle[k].replace(/"/g, '');
@@ -5314,7 +5339,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5314
5339
  if (!options.plugins.hiliteColor || /rgba\(([0-9]+\s*,\s*){3}0\)|windowtext/i.test(c)) continue;
5315
5340
  break;
5316
5341
  }
5317
-
5342
+
5318
5343
  if (v !== c) {
5319
5344
  allowedStyle.push(r[0]);
5320
5345
  }
@@ -5337,23 +5362,23 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5337
5362
  */
5338
5363
  _cleanTags: function (lowLevelCheck, m, t) {
5339
5364
  if (/^<[a-z0-9]+\:[a-z0-9]+/i.test(m)) return m;
5340
-
5365
+
5341
5366
  let v = null;
5342
5367
  const tagName = t.match(/(?!<)[a-zA-Z0-9\-]+/)[0].toLowerCase();
5343
-
5368
+
5344
5369
  // blacklist
5345
5370
  const bAttr = this._attributesTagsBlacklist[tagName];
5346
5371
  m = m.replace(/\s(?:on[a-z]+)\s*=\s*(")[^"]*\1/ig, '');
5347
5372
  if (bAttr) m = m.replace(bAttr, '');
5348
5373
  else m = m.replace(this._attributesBlacklistRegExp, '');
5349
-
5374
+
5350
5375
  // whitelist
5351
5376
  const wAttr = this._attributesTagsWhitelist[tagName];
5352
5377
  if (wAttr) v = m.match(wAttr);
5353
5378
  else v = m.match(lowLevelCheck ? this._attributesWhitelistRegExp : this._attributesWhitelistRegExp_all_data);
5354
-
5379
+
5355
5380
  // attribute
5356
- if (lowLevelCheck || tagName === 'span') {
5381
+ if (lowLevelCheck || tagName === 'span' || tagName === 'li' || this._cleanStyleRegExp[tagName]) {
5357
5382
  if (tagName === 'a') {
5358
5383
  const sv = m.match(/(?:(?:id|name)\s*=\s*(?:"|')[^"']*(?:"|'))/g);
5359
5384
  if (sv) {
@@ -5361,8 +5386,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5361
5386
  v.push(sv[0]);
5362
5387
  }
5363
5388
  } else if (!v || !/style=/i.test(v.toString())) {
5364
- if (tagName === 'span') {
5389
+ if (tagName === 'span' || tagName === 'li') {
5365
5390
  v = this._cleanStyle(m, v, 'span');
5391
+ } if (this._cleanStyleRegExp[tagName]) {
5392
+ v = this._cleanStyle(m, v, tagName);
5366
5393
  } else if (/^(P|DIV|H[1-6]|PRE)$/i.test(tagName)) {
5367
5394
  v = this._cleanStyle(m, v, 'format');
5368
5395
  }
@@ -5400,7 +5427,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5400
5427
  _editFormat: function (dom) {
5401
5428
  let value = '', f;
5402
5429
  const tempTree = dom.childNodes;
5403
-
5430
+
5404
5431
  for (let i = 0, len = tempTree.length, n; i < len; i++) {
5405
5432
  n = tempTree[i];
5406
5433
  if (n.nodeType === 8) {
@@ -5472,6 +5499,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5472
5499
  * @returns {String}
5473
5500
  */
5474
5501
  cleanHTML: function (html, whitelist, blacklist) {
5502
+ if (!options.strictMode) return html;
5503
+
5475
5504
  html = this._deleteDisallowedTags(this._parser.parseFromString(util.htmlCompress(html), 'text/html').body.innerHTML).replace(/(<[a-zA-Z0-9\-]+)[^>]*(?=>)/g, this._cleanTags.bind(this, true)).replace(/<br\/?>$/i, '');
5476
5505
  const dom = _d.createRange().createContextualFragment(html);
5477
5506
  try {
@@ -5479,7 +5508,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5479
5508
  } catch (error) {
5480
5509
  console.warn('[SUNEDITOR.cleanHTML.consistencyCheck.fail] ' + error);
5481
5510
  }
5482
-
5511
+
5483
5512
  if (this.managedTagsInfo && this.managedTagsInfo.query) {
5484
5513
  const textCompList = dom.querySelectorAll(this.managedTagsInfo.query);
5485
5514
  for (let i = 0, len = textCompList.length, initMethod, classList; i < len; i++) {
@@ -5528,6 +5557,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5528
5557
  * @returns {String}
5529
5558
  */
5530
5559
  convertContentsForEditor: function (contents) {
5560
+ if (!options.strictMode) return contents;
5531
5561
  contents = this._deleteDisallowedTags(this._parser.parseFromString(util.htmlCompress(contents), 'text/html').body.innerHTML).replace(/(<[a-zA-Z0-9\-]+)[^>]*(?=>)/g, this._cleanTags.bind(this, true));
5532
5562
  const dom = _d.createRange().createContextualFragment(contents);
5533
5563
 
@@ -5550,7 +5580,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5550
5580
  }
5551
5581
  }
5552
5582
  }
5553
-
5583
+
5554
5584
  const domTree = dom.childNodes;
5555
5585
  let cleanHTML = '', p = null;
5556
5586
  for (let i = 0, t; i < domTree.length; i++) {
@@ -5561,7 +5591,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5561
5591
  continue;
5562
5592
  }
5563
5593
 
5564
- if (!util.isFormatElement(t) && !util.isRangeFormatElement(t) && !util.isComponent(t) && !util.isMedia(t) && t.nodeType !== 8 && !/__se__tag/.test(t.className)) {
5594
+ if (!util.isFormatElement(t) && !util.isRangeFormatElement(t) && !util.isComponent(t) && !util.isFigures(t) && t.nodeType !== 8 && !/__se__tag/.test(t.className)) {
5565
5595
  if (!p) p = util.createElement(options.defaultTag);
5566
5596
  p.appendChild(t);
5567
5597
  i--;
@@ -5659,7 +5689,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5659
5689
 
5660
5690
  /**
5661
5691
  * @description Remove events from document.
5662
-   * When created as an Iframe, the event of the document inside the Iframe is also removed.
5692
+ * When created as an Iframe, the event of the document inside the Iframe is also removed.
5663
5693
  * @param {String} type Event type
5664
5694
  * @param {Function} listener Event listener
5665
5695
  */
@@ -5687,7 +5717,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5687
5717
  if (maxCharCount > 0) {
5688
5718
  let over = false;
5689
5719
  const count = functions.getCharCount(countType);
5690
-
5720
+
5691
5721
  if (count > maxCharCount) {
5692
5722
  over = true;
5693
5723
  if (nextCharCount > 0) {
@@ -5696,7 +5726,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5696
5726
  const endOff = range.endOffset - 1;
5697
5727
  const text = this.getSelectionNode().textContent;
5698
5728
  const slicePosition = range.endOffset - (count - maxCharCount);
5699
-
5729
+
5700
5730
  this.getSelectionNode().textContent = text.slice(0, slicePosition < 0 ? 0 : slicePosition) + text.slice(range.endOffset, text.length);
5701
5731
  this.setRange(range.endContainer, endOff, range.endContainer, endOff);
5702
5732
  }
@@ -5778,7 +5808,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5778
5808
  */
5779
5809
  _setCharCount: function () {
5780
5810
  if (context.element.charCounter) {
5781
- _w.setTimeout(function () { context.element.charCounter.textContent = functions.getCharCount(options.charCounterType); });
5811
+ _w.setTimeout(function (functions, options) {
5812
+ if (this.textContent && functions) {
5813
+ this.textContent = functions.getCharCount(options.charCounterType);
5814
+ }
5815
+ }.bind(context.element.charCounter, functions, options), 0);
5782
5816
  }
5783
5817
  },
5784
5818
 
@@ -5936,7 +5970,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5936
5970
  }
5937
5971
  }
5938
5972
  }
5939
-
5973
+
5940
5974
  this._attributesWhitelistRegExp = new wRegExp('\\s(?:' + (allAttr || defaultAttr + '|' + dataAttr) + ')' + regEndStr, 'ig');
5941
5975
  this._attributesWhitelistRegExp_all_data = new wRegExp('\\s(?:' + ((allAttr || defaultAttr) + '|data-[a-z0-9\\-]+') + ')' + regEndStr, 'ig');
5942
5976
  this._attributesTagsWhitelist = tagsAttr;
@@ -6014,7 +6048,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6014
6048
  this._fileManager.queryString = this._fileManager.tags.join(',');
6015
6049
  this._fileManager.regExp = new wRegExp('^(' + (this._fileManager.tags.join('|') || '^') + ')$', 'i');
6016
6050
  this._fileManager.pluginRegExp = new wRegExp('^(' + (filePluginRegExp.length === 0 ? '^' : filePluginRegExp.join('|')) + ')$', 'i');
6017
-
6051
+
6018
6052
  // cache editor's element
6019
6053
  this._variable._originCssText = context.element.topArea.style.cssText;
6020
6054
  this._placeholder = context.element.placeholder;
@@ -6034,7 +6068,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6034
6068
  if (options._editorStyles.editor) context.element.wysiwyg.style.cssText = options._editorStyles.editor;
6035
6069
  if (options.height === 'auto') this._iframeAuto = this._wd.body;
6036
6070
  }
6037
-
6071
+
6038
6072
  this._initWysiwygArea(reload, _initHTML);
6039
6073
  },
6040
6074
 
@@ -6056,7 +6090,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6056
6090
  commandMap[options.textTags.strike.toUpperCase()] = tool.strike;
6057
6091
  commandMap[options.textTags.sub.toUpperCase()] = tool.subscript;
6058
6092
  commandMap[options.textTags.sup.toUpperCase()] = tool.superscript;
6059
-
6093
+
6060
6094
  this._styleCommandMap = {
6061
6095
  fullScreen: tool.fullScreen,
6062
6096
  showBlocks: tool.showBlocks,
@@ -6073,7 +6107,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6073
6107
  * @private
6074
6108
  */
6075
6109
  _initWysiwygArea: function (reload, _initHTML) {
6076
- context.element.wysiwyg.innerHTML = reload ? _initHTML : this.convertContentsForEditor((typeof _initHTML === 'string' ? _initHTML : /TEXTAREA/i.test(context.element.originElement) ? context.element.originElement.value : context.element.originElement.innerHTML) || '');
6110
+ context.element.wysiwyg.innerHTML = reload ? _initHTML : this.convertContentsForEditor((typeof _initHTML === 'string' ? _initHTML : /^TEXTAREA$/i.test(context.element.originElement.nodeName) ? context.element.originElement.value : context.element.originElement.innerHTML) || '');
6077
6111
  },
6078
6112
 
6079
6113
  /**
@@ -6104,7 +6138,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6104
6138
  */
6105
6139
  _iframeAutoHeight: function () {
6106
6140
  if (this._iframeAuto) {
6107
- _w.setTimeout(function () {
6141
+ _w.setTimeout(function () {
6108
6142
  const h = core._iframeAuto.offsetHeight;
6109
6143
  context.element.wysiwygFrame.style.height = h + 'px';
6110
6144
  if (!util.isResizeObserverSupported) core.__callResizeFunction(h, null);
@@ -6183,7 +6217,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6183
6217
  focusNode = util.createTextNode(util.zeroWidthSpace);
6184
6218
  format.insertBefore(focusNode, format.firstChild);
6185
6219
  }
6186
-
6220
+
6187
6221
  offset = focusNode.textContent.length;
6188
6222
  this.setRange(focusNode, offset, focusNode, offset);
6189
6223
  return;
@@ -6202,17 +6236,26 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6202
6236
  return;
6203
6237
  }
6204
6238
 
6205
- this.execCommand('formatBlock', false, (formatName || options.defaultTag));
6206
- focusNode = util.getEdgeChildNodes(commonCon, commonCon);
6207
- focusNode = focusNode ? focusNode.ec : commonCon;
6208
-
6209
- format = util.getFormatElement(focusNode, null);
6210
- if (!format) {
6239
+ try {
6240
+ if (commonCon.nodeType === 3) {
6241
+ format = util.createElement(formatName || options.defaultTag);
6242
+ commonCon.parentNode.insertBefore(format, commonCon);
6243
+ format.appendChild(commonCon);
6244
+ }
6245
+
6246
+ if (util.isBreak(format.nextSibling)) util.removeItem(format.nextSibling);
6247
+ if (util.isBreak(format.previousSibling)) util.removeItem(format.previousSibling);
6248
+ if (util.isBreak(focusNode)) {
6249
+ const zeroWidth = util.createTextNode(util.zeroWidthSpace);
6250
+ focusNode.parentNode.insertBefore(zeroWidth, focusNode);
6251
+ focusNode = zeroWidth;
6252
+ }
6253
+ } catch (e) {
6254
+ this.execCommand('formatBlock', false, (formatName || options.defaultTag));
6211
6255
  this.removeRange();
6212
6256
  this._editorRange();
6213
- return;
6214
6257
  }
6215
-
6258
+
6216
6259
  if (util.isBreak(format.nextSibling)) util.removeItem(format.nextSibling);
6217
6260
  if (util.isBreak(format.previousSibling)) util.removeItem(format.previousSibling);
6218
6261
  if (util.isBreak(focusNode)) {
@@ -6264,7 +6307,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6264
6307
  this._componentsInfoReset = false;
6265
6308
 
6266
6309
  this.history.reset(true);
6267
-
6310
+
6268
6311
  _w.setTimeout(function () {
6269
6312
  if (typeof core._resourcesStateChange !== 'function') return;
6270
6313
 
@@ -6489,19 +6532,45 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6489
6532
  } else {
6490
6533
  let command = target.getAttribute('data-command');
6491
6534
  let className = target.className;
6492
-
6535
+
6493
6536
  while (!command && !/se-menu-list/.test(className) && !/sun-editor-common/.test(className)) {
6494
6537
  target = target.parentNode;
6495
6538
  command = target.getAttribute('data-command');
6496
6539
  className = target.className;
6497
6540
  }
6498
-
6541
+
6499
6542
  if (command === core._submenuName || command === core._containerName) {
6500
6543
  e.stopPropagation();
6501
6544
  }
6502
6545
  }
6503
6546
  },
6504
6547
 
6548
+ addGlobalEvent(type, listener, useCapture) {
6549
+ if (options.iframe) {
6550
+ core._ww.addEventListener(type, listener, useCapture);
6551
+ }
6552
+ core._w.addEventListener(type, listener, useCapture);
6553
+ return {
6554
+ type: type,
6555
+ listener: listener,
6556
+ useCapture: useCapture
6557
+ };
6558
+ },
6559
+
6560
+ removeGlobalEvent(type, listener, useCapture) {
6561
+ if (!type) return;
6562
+
6563
+ if (typeof type === 'object') {
6564
+ listener = type.listener;
6565
+ useCapture = type.useCapture;
6566
+ type = type.type;
6567
+ }
6568
+ if (options.iframe) {
6569
+ core._ww.removeEventListener(type, listener, useCapture);
6570
+ }
6571
+ core._w.removeEventListener(type, listener, useCapture);
6572
+ },
6573
+
6505
6574
  onClick_toolbar: function (e) {
6506
6575
  let target = e.target;
6507
6576
  let display = target.getAttribute('data-display');
@@ -6522,6 +6591,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6522
6591
  core.actionCall(command, display, target);
6523
6592
  },
6524
6593
 
6594
+ __selectionSyncEvent: null,
6525
6595
  onMouseDown_wysiwyg: function (e) {
6526
6596
  if (core.isReadOnly || util.isNonEditable(context.element.wysiwyg)) return;
6527
6597
  if (util._isExcludeSelectionElement(e.target)) {
@@ -6529,11 +6599,15 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6529
6599
  return;
6530
6600
  }
6531
6601
 
6532
- _w.setTimeout(core._editorRange.bind(core));
6602
+ event.removeGlobalEvent(event.__selectionSyncEvent);
6603
+ event.__selectionSyncEvent = event.addGlobalEvent('mouseup', function() {
6604
+ core._editorRange();
6605
+ event.removeGlobalEvent(event.__selectionSyncEvent);
6606
+ });
6533
6607
 
6534
6608
  // user event
6535
6609
  if (typeof functions.onMouseDown === 'function' && functions.onMouseDown(e, core) === false) return;
6536
-
6610
+
6537
6611
  const tableCell = util.getParentElement(e.target, util.isCell);
6538
6612
  if (tableCell) {
6539
6613
  const tablePlugin = core.plugins.table;
@@ -6602,6 +6676,16 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6602
6676
  const selectionNode = core.getSelectionNode();
6603
6677
  const formatEl = util.getFormatElement(selectionNode, null);
6604
6678
  const rangeEl = util.getRangeFormatElement(selectionNode, null);
6679
+
6680
+ let selectionNodeDeepestFirstChild = selectionNode;
6681
+ while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
6682
+
6683
+ const selectedComponentInfo = core.getFileComponent(selectionNodeDeepestFirstChild);
6684
+ if (selectedComponentInfo) {
6685
+ const range = core.getRange();
6686
+ if (!rangeEl && range.startContainer === range.endContainer) core.selectComponent(selectedComponentInfo.target, selectedComponentInfo.pluginName);
6687
+ } else if (core.currentFileComponentInfo) core.controllersOff();
6688
+
6605
6689
  if (!formatEl && !util.isNonEditable(targetElement) && !util.isList(rangeEl)) {
6606
6690
  const range = core.getRange();
6607
6691
  if (util.getFormatElement(range.startContainer) === util.getFormatElement(range.endContainer)) {
@@ -6675,7 +6759,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6675
6759
  const offsets = event._getEditorOffsets(null);
6676
6760
  const stickyTop = offsets.top;
6677
6761
  const editorLeft = offsets.left;
6678
-
6762
+
6679
6763
  toolbar.style.top = '-10000px';
6680
6764
  toolbar.style.visibility = 'hidden';
6681
6765
  toolbar.style.display = 'block';
@@ -6719,7 +6803,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6719
6803
  bottom: rects.bottom + iframeRects.bottom - iframeRects.height
6720
6804
  };
6721
6805
  }
6722
-
6806
+
6723
6807
  event._setToolbarOffset(isDirTop, rects, toolbar, editorLeft, editorWidth, scrollLeft, scrollTop, stickyTop, arrowMargin);
6724
6808
  if (toolbarWidth !== toolbar.offsetWidth || toolbarHeight !== toolbar.offsetHeight) {
6725
6809
  event._setToolbarOffset(isDirTop, rects, toolbar, editorLeft, editorWidth, scrollLeft, scrollTop, stickyTop, arrowMargin);
@@ -6752,7 +6836,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6752
6836
 
6753
6837
  const absoluteLeft = (isDirTop ? rects.left : rects.right) - editorLeft - (toolbarWidth / 2) + scrollLeft;
6754
6838
  const overRight = absoluteLeft + toolbarWidth - editorWidth;
6755
-
6839
+
6756
6840
  let t = (isDirTop ? rects.top - toolbarHeight - arrowMargin : rects.bottom + arrowMargin) - (rects.noText ? 0 : stickyTop) + scrollTop;
6757
6841
  let l = absoluteLeft < 0 ? padding : overRight < 0 ? absoluteLeft : absoluteLeft - overRight - padding - 1;
6758
6842
 
@@ -6791,12 +6875,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6791
6875
  const toolbar = context.element.toolbar;
6792
6876
  if (options.toolbarContainer) toolbar.style.position = 'relative';
6793
6877
  else toolbar.style.position = 'absolute';
6794
-
6878
+
6795
6879
  toolbar.style.visibility = 'hidden';
6796
6880
  toolbar.style.display = 'block';
6797
6881
  core._inlineToolbarAttr.width = toolbar.style.width = options.toolbarWidth;
6798
6882
  core._inlineToolbarAttr.top = toolbar.style.top = (options.toolbarContainer ? 0 : (-1 - toolbar.offsetHeight)) + 'px';
6799
-
6883
+
6800
6884
  if (typeof functions.showInline === 'function') functions.showInline(toolbar, context, core);
6801
6885
 
6802
6886
  event.onScroll_window();
@@ -6812,6 +6896,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6812
6896
  },
6813
6897
 
6814
6898
  onInput_wysiwyg: function (e) {
6899
+ if (/AUDIO/.test(e.target.nodeName)) return false;
6815
6900
  if (core.isReadOnly || core.isDisabled) {
6816
6901
  e.preventDefault();
6817
6902
  e.stopPropagation();
@@ -6821,7 +6906,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6821
6906
 
6822
6907
  core._editorRange();
6823
6908
 
6824
- const data = (e.data === null ? '' : e.data === undefined ? ' ' : e.data) || '';
6909
+ const data = (e.data === null ? '' : e.data === undefined ? ' ' : e.data) || '';
6825
6910
  if (!core._charCount(data)) {
6826
6911
  e.preventDefault();
6827
6912
  e.stopPropagation();
@@ -6907,6 +6992,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6907
6992
  let formatEl = util.getFormatElement(selectionNode, null) || selectionNode;
6908
6993
  let rangeEl = util.getRangeFormatElement(formatEl, null);
6909
6994
 
6995
+ const isArrowKey = /37|38|39|40/.test(e.keyCode);
6996
+ if (isArrowKey && event._onKeyDown_wysiwyg_arrowKey(e) === false) return;
6997
+
6910
6998
  switch (keyCode) {
6911
6999
  case 8: /** backspace key */
6912
7000
  if (!selectRange) {
@@ -6930,8 +7018,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6930
7018
  return false;
6931
7019
  }
6932
7020
 
6933
- if (!selectRange && !formatEl.previousElementSibling && (range.startOffset === 0 && !selectionNode.previousSibling && !util.isListCell(formatEl) &&
6934
- (util.isFormatElement(formatEl) && (!util.isFreeFormatElement(formatEl) || util.isClosureFreeFormatElement(formatEl))))) {
7021
+ if (!selectRange && !formatEl.previousElementSibling && (range.startOffset === 0 && !selectionNode.previousSibling && !util.isListCell(formatEl) &&
7022
+ (util.isFormatElement(formatEl) && (!util.isFreeFormatElement(formatEl) || util.isClosureFreeFormatElement(formatEl))))) {
6935
7023
  // closure range
6936
7024
  if (util.isClosureRangeFormatElement(formatEl.parentNode)) {
6937
7025
  e.preventDefault();
@@ -7006,7 +7094,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7006
7094
  rangeEl = util.getRangeFormatElement(formatEl, null);
7007
7095
  if (rangeEl && formatEl && !util.isCell(rangeEl) && !/^FIGCAPTION$/i.test(rangeEl.nodeName)) {
7008
7096
  if (util.isListCell(formatEl) && util.isList(rangeEl) && (util.isListCell(rangeEl.parentNode) || formatEl.previousElementSibling) && (selectionNode === formatEl || (selectionNode.nodeType === 3 && (!selectionNode.previousSibling || util.isList(selectionNode.previousSibling)))) &&
7009
- (util.getFormatElement(range.startContainer, null) !== util.getFormatElement(range.endContainer, null) ? rangeEl.contains(range.startContainer) : (range.startOffset === 0 && range.collapsed))) {
7097
+ (util.getFormatElement(range.startContainer, null) !== util.getFormatElement(range.endContainer, null) ? rangeEl.contains(range.startContainer) : (range.startOffset === 0 && range.collapsed))) {
7010
7098
  if (range.startContainer !== range.endContainer) {
7011
7099
  e.preventDefault();
7012
7100
 
@@ -7052,7 +7140,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7052
7140
  core.history.push(true);
7053
7141
  }
7054
7142
  }
7055
-
7143
+
7056
7144
  break;
7057
7145
  }
7058
7146
 
@@ -7069,7 +7157,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7069
7157
  }
7070
7158
  comm = comm.parentNode;
7071
7159
  }
7072
-
7160
+
7073
7161
  if (detach && rangeEl.parentNode) {
7074
7162
  e.preventDefault();
7075
7163
  core.detachRangeFormatElement(rangeEl, (util.isListCell(formatEl) ? [formatEl] : null), null, false, false);
@@ -7190,9 +7278,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7190
7278
  formatEl = util.getFormatElement(range.startContainer, null);
7191
7279
  rangeEl = util.getRangeFormatElement(formatEl, null);
7192
7280
  if (util.isListCell(formatEl) && util.isList(rangeEl) && (selectionNode === formatEl || (selectionNode.nodeType === 3 && (!selectionNode.nextSibling || util.isList(selectionNode.nextSibling)) &&
7193
- (util.getFormatElement(range.startContainer, null) !== util.getFormatElement(range.endContainer, null) ? rangeEl.contains(range.endContainer) : (range.endOffset === selectionNode.textContent.length && range.collapsed))))) {
7281
+ (util.getFormatElement(range.startContainer, null) !== util.getFormatElement(range.endContainer, null) ? rangeEl.contains(range.endContainer) : (range.endOffset === selectionNode.textContent.length && range.collapsed))))) {
7194
7282
  if (range.startContainer !== range.endContainer) core.removeNode();
7195
-
7283
+
7196
7284
  let next = util.getArrayItem(formatEl.children, util.isList, false);
7197
7285
  next = next || formatEl.nextElementSibling || rangeEl.parentNode.nextElementSibling;
7198
7286
  if (next && (util.isList(next) || util.getArrayItem(next.children, util.isList, false))) {
@@ -7228,7 +7316,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7228
7316
  e.preventDefault();
7229
7317
  if (ctrl || alt || util.isWysiwygDiv(selectionNode)) break;
7230
7318
 
7231
- const isEdge = (!range.collapsed || core.isEdgePoint(range.startContainer, range.startOffset));
7319
+ const isEdge = (!range.collapsed || core.isEdgePoint(range.startContainer, range.startOffset));
7232
7320
  const selectedFormats = core.getSelectedElements(null);
7233
7321
  selectionNode = core.getSelectionNode();
7234
7322
  const cells = [];
@@ -7247,7 +7335,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7247
7335
  lines.push(f);
7248
7336
  }
7249
7337
  }
7250
-
7338
+
7251
7339
  // Nested list
7252
7340
  if (cells.length > 0 && isEdge && core.plugins.list) {
7253
7341
  r = core.plugins.list.editInsideList.call(core, shift, cells);
@@ -7293,14 +7381,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7293
7381
  for (let i = 0, child; i <= len; i++) {
7294
7382
  child = lines[i].firstChild;
7295
7383
  if (!child) continue;
7296
-
7384
+
7297
7385
  if (util.isBreak(child)) {
7298
7386
  lines[i].insertBefore(tabText.cloneNode(false), child);
7299
7387
  } else {
7300
7388
  child.textContent = tabText.textContent + child.textContent;
7301
7389
  }
7302
7390
  }
7303
-
7391
+
7304
7392
  const firstChild = util.getChildElement(lines[0], 'text', false);
7305
7393
  const endChild = util.getChildElement(lines[len], 'text', true);
7306
7394
  if (!fc && firstChild) {
@@ -7320,17 +7408,17 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7320
7408
  child = line[c];
7321
7409
  if (!child) break;
7322
7410
  if (util.onlyZeroWidthSpace(child)) continue;
7323
-
7411
+
7324
7412
  if (/^\s{1,4}$/.test(child.textContent)) {
7325
7413
  util.removeItem(child);
7326
7414
  } else if (/^\s{1,4}/.test(child.textContent)) {
7327
7415
  child.textContent = child.textContent.replace(/^\s{1,4}/, '');
7328
7416
  }
7329
-
7417
+
7330
7418
  break;
7331
7419
  }
7332
7420
  }
7333
-
7421
+
7334
7422
  const firstChild = util.getChildElement(lines[0], 'text', false);
7335
7423
  const endChild = util.getChildElement(lines[len], 'text', true);
7336
7424
  if (!fc && firstChild) {
@@ -7347,9 +7435,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7347
7435
  core.setRange(r.sc, r.so, r.ec, r.eo);
7348
7436
  // history stack
7349
7437
  core.history.push(false);
7350
-
7438
+
7351
7439
  break;
7352
7440
  case 13: /** enter key */
7441
+ // enter login start
7353
7442
  const freeFormatEl = util.getFreeFormatElement(selectionNode, null);
7354
7443
 
7355
7444
  if (core._charTypeHTML) {
@@ -7366,13 +7455,13 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7366
7455
  }
7367
7456
  }
7368
7457
 
7369
- if (!shift) {
7458
+ if (!shift && !fileComponentName) {
7370
7459
  const formatEndEdge = core._isEdgeFormat(range.endContainer, range.endOffset, 'end');
7371
7460
  const formatStartEdge = core._isEdgeFormat(range.startContainer, range.startOffset, 'start');
7372
7461
 
7373
7462
  // add default format line
7374
7463
  if (formatEndEdge && (/^H[1-6]$/i.test(formatEl.nodeName) || /^HR$/i.test(formatEl.nodeName))) {
7375
- e.preventDefault();
7464
+ event._enterPrevent(e);
7376
7465
  let temp = null;
7377
7466
  const newFormat = core.appendFormatTag(formatEl, options.defaultTag);
7378
7467
 
@@ -7386,37 +7475,41 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7386
7475
  }
7387
7476
 
7388
7477
  temp = !temp ? newFormat.firstChild : temp.appendChild(newFormat.firstChild);
7389
- core.setRange(temp, 0, temp, 0);
7478
+ if (util.isBreak(temp)) {
7479
+ const zeroWidth = util.createTextNode(util.zeroWidthSpace);
7480
+ temp.parentNode.insertBefore(zeroWidth, temp);
7481
+ core.setRange(zeroWidth, 1, zeroWidth, 1);
7482
+ } else {
7483
+ core.setRange(temp, 0, temp, 0);
7484
+ }
7390
7485
  break;
7391
7486
  } else if (rangeEl && formatEl && !util.isCell(rangeEl) && !/^FIGCAPTION$/i.test(rangeEl.nodeName)) {
7392
7487
  const range = core.getRange();
7393
7488
  if(core.isEdgePoint(range.endContainer, range.endOffset) && util.isList(selectionNode.nextSibling)) {
7394
- e.preventDefault();
7489
+ event._enterPrevent(e);
7395
7490
  const newEl = util.createElement('LI');
7396
7491
  const br = util.createElement('BR');
7397
7492
  newEl.appendChild(br);
7398
-
7493
+
7399
7494
  formatEl.parentNode.insertBefore(newEl, formatEl.nextElementSibling);
7400
7495
  newEl.appendChild(selectionNode.nextSibling);
7401
-
7496
+
7402
7497
  core.setRange(br, 1, br, 1);
7403
7498
  break;
7404
7499
  }
7405
-
7500
+
7406
7501
  if ((range.commonAncestorContainer.nodeType === 3 ? !range.commonAncestorContainer.nextElementSibling : true) && util.onlyZeroWidthSpace(formatEl.innerText.trim()) && !util.isListCell(formatEl.nextElementSibling)) {
7407
- e.preventDefault();
7502
+ event._enterPrevent(e);
7408
7503
  let newEl = null;
7409
-
7504
+
7410
7505
  if (util.isListCell(rangeEl.parentNode)) {
7411
- rangeEl = formatEl.parentNode.parentNode.parentNode;
7412
- newEl = util.splitElement(formatEl, null, util.getElementDepth(formatEl) - 2);
7413
- if (!newEl) {
7414
- const newListCell = util.createElement('LI');
7415
- newListCell.innerHTML = '<br>';
7416
- util.copyTagAttributes(newListCell, formatEl, options.lineAttrReset);
7417
- rangeEl.insertBefore(newListCell, newEl);
7418
- newEl = newListCell;
7419
- }
7506
+ const parentLi = formatEl.parentNode.parentNode;
7507
+ rangeEl = parentLi.parentNode;
7508
+ const newListCell = util.createElement('LI');
7509
+ newListCell.innerHTML = '<br>';
7510
+ util.copyTagAttributes(newListCell, formatEl, options.lineAttrReset);
7511
+ newEl = newListCell;
7512
+ rangeEl.insertBefore(newEl, parentLi.nextElementSibling);
7420
7513
  } else {
7421
7514
  const newFormat = util.isCell(rangeEl.parentNode) ? 'DIV' : util.isList(rangeEl.parentNode) ? 'LI' : (util.isFormatElement(rangeEl.nextElementSibling) && !util.isRangeFormatElement(rangeEl.nextElementSibling)) ? rangeEl.nextElementSibling.nodeName : (util.isFormatElement(rangeEl.previousElementSibling) && !util.isRangeFormatElement(rangeEl.previousElementSibling)) ? rangeEl.previousElementSibling.nodeName : options.defaultTag;
7422
7515
  newEl = util.createElement(newFormat);
@@ -7424,7 +7517,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7424
7517
  const edge = core.detachRangeFormatElement(rangeEl, [formatEl], null, true, true);
7425
7518
  edge.cc.insertBefore(newEl, edge.ec);
7426
7519
  }
7427
-
7520
+
7428
7521
  newEl.innerHTML = '<br>';
7429
7522
  util.removeItemAllParents(formatEl, null, null);
7430
7523
  core.setRange(newEl, 1, newEl, 1);
@@ -7433,13 +7526,13 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7433
7526
  }
7434
7527
 
7435
7528
  if (freeFormatEl) {
7436
- e.preventDefault();
7529
+ event._enterPrevent(e);
7437
7530
  const selectionFormat = selectionNode === freeFormatEl;
7438
7531
  const wSelection = core.getSelection();
7439
7532
  const children = selectionNode.childNodes, offset = wSelection.focusOffset, prev = selectionNode.previousElementSibling, next = selectionNode.nextSibling;
7440
-
7533
+
7441
7534
  if (!util.isClosureFreeFormatElement(freeFormatEl) && !!children && ((selectionFormat && range.collapsed && children.length - 1 <= offset + 1 && util.isBreak(children[offset]) && (!children[offset + 1] || ((!children[offset + 2] || util.onlyZeroWidthSpace(children[offset + 2].textContent)) && children[offset + 1].nodeType === 3 && util.onlyZeroWidthSpace(children[offset + 1].textContent))) && offset > 0 && util.isBreak(children[offset - 1])) ||
7442
- (!selectionFormat && util.onlyZeroWidthSpace(selectionNode.textContent) && util.isBreak(prev) && (util.isBreak(prev.previousSibling) || !util.onlyZeroWidthSpace(prev.previousSibling.textContent)) && (!next || (!util.isBreak(next) && util.onlyZeroWidthSpace(next.textContent)))))) {
7535
+ (!selectionFormat && util.onlyZeroWidthSpace(selectionNode.textContent) && util.isBreak(prev) && (util.isBreak(prev.previousSibling) || !util.onlyZeroWidthSpace(prev.previousSibling.textContent)) && (!next || (!util.isBreak(next) && util.onlyZeroWidthSpace(next.textContent)))))) {
7443
7536
  if (selectionFormat) util.removeItem(children[offset - 1]);
7444
7537
  else util.removeItem(selectionNode);
7445
7538
  const newEl = core.appendFormatTag(freeFormatEl, (util.isFormatElement(freeFormatEl.nextElementSibling) && !util.isRangeFormatElement(freeFormatEl.nextElementSibling)) ? freeFormatEl.nextElementSibling : null);
@@ -7447,22 +7540,22 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7447
7540
  core.setRange(newEl, 1, newEl, 1);
7448
7541
  break;
7449
7542
  }
7450
-
7543
+
7451
7544
  if (selectionFormat) {
7452
7545
  functions.insertHTML(((range.collapsed && util.isBreak(range.startContainer.childNodes[range.startOffset - 1])) ? '<br>' : '<br><br>'), true, false);
7453
-
7546
+
7454
7547
  let focusNode = wSelection.focusNode;
7455
7548
  const wOffset = wSelection.focusOffset;
7456
7549
  if (freeFormatEl === focusNode) {
7457
7550
  focusNode = focusNode.childNodes[wOffset - offset > 1 ? wOffset - 1 : wOffset];
7458
7551
  }
7459
-
7552
+
7460
7553
  core.setRange(focusNode, 1, focusNode, 1);
7461
7554
  } else {
7462
7555
  const focusNext = wSelection.focusNode.nextSibling;
7463
7556
  const br = util.createElement('BR');
7464
7557
  core.insertNode(br, null, false);
7465
-
7558
+
7466
7559
  const brPrev = br.previousSibling, brNext = br.nextSibling;
7467
7560
  if (!util.isBreak(focusNext) && !util.isBreak(brPrev) && (!brNext || util.onlyZeroWidthSpace(brNext))) {
7468
7561
  br.parentNode.insertBefore(br.cloneNode(false), br);
@@ -7471,14 +7564,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7471
7564
  core.setRange(brNext, 0, brNext, 0);
7472
7565
  }
7473
7566
  }
7474
-
7567
+
7475
7568
  event._onShortcutKey = true;
7476
7569
  break;
7477
7570
  }
7478
-
7571
+
7479
7572
  // set format attrs - edge
7480
7573
  if (range.collapsed && (formatStartEdge || formatEndEdge)) {
7481
- e.preventDefault();
7574
+ event._enterPrevent(e);
7482
7575
  const focusBR = util.createElement('BR');
7483
7576
  const newFormat = util.createElement(formatEl.nodeName);
7484
7577
  util.copyTagAttributes(newFormat, formatEl, options.lineAttrReset);
@@ -7498,10 +7591,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7498
7591
  if (formatEndEdge) {
7499
7592
  core.setRange(focusBR, 1, focusBR, 1);
7500
7593
  }
7501
-
7594
+
7502
7595
  break;
7503
7596
  }
7504
-
7597
+
7505
7598
  if (formatEl) {
7506
7599
  e.stopPropagation();
7507
7600
 
@@ -7515,7 +7608,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7515
7608
  newEl = util.getFormatElement(r.container, null);
7516
7609
  if (!newEl) {
7517
7610
  if (util.isWysiwygDiv(r.container)) {
7518
- e.preventDefault();
7611
+ event._enterPrevent(e);
7519
7612
  context.element.wysiwyg.appendChild(newFormat);
7520
7613
  newEl = newFormat;
7521
7614
  util.copyTagAttributes(newEl, formatEl, options.lineAttrReset);
@@ -7523,7 +7616,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7523
7616
  }
7524
7617
  break;
7525
7618
  }
7526
-
7619
+
7527
7620
  const innerRange = util.getRangeFormatElement(r.container);
7528
7621
  newEl = newEl.contains(innerRange) ? util.getChildElement(innerRange, util.getFormatElement.bind(util)) : newEl;
7529
7622
  if (isMultiLine) {
@@ -7558,7 +7651,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7558
7651
  }
7559
7652
  }
7560
7653
 
7561
- e.preventDefault();
7654
+ event._enterPrevent(e);
7562
7655
  util.copyTagAttributes(newEl, formatEl, options.lineAttrReset);
7563
7656
  core.setRange(newEl, offset, newEl, offset);
7564
7657
 
@@ -7567,9 +7660,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7567
7660
  }
7568
7661
 
7569
7662
  if (selectRange) break;
7570
-
7663
+
7571
7664
  if (rangeEl && util.getParentElement(rangeEl, 'FIGCAPTION') && util.getParentElement(rangeEl, util.isList)) {
7572
- e.preventDefault();
7665
+ event._enterPrevent(e);
7573
7666
  formatEl = core.appendFormatTag(formatEl, null);
7574
7667
  core.setRange(formatEl, 0, formatEl, 0);
7575
7668
  }
@@ -7577,6 +7670,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7577
7670
  if (fileComponentName) {
7578
7671
  e.preventDefault();
7579
7672
  e.stopPropagation();
7673
+ core.containerOff();
7674
+ core.controllersOff();
7675
+
7580
7676
  const compContext = context[fileComponentName];
7581
7677
  const container = compContext._container;
7582
7678
  const sibling = container.previousElementSibling || container.nextElementSibling;
@@ -7589,13 +7685,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7589
7685
  newEl.innerHTML = '<br>';
7590
7686
  }
7591
7687
 
7592
- container.parentNode.insertBefore(newEl, container);
7593
-
7688
+ if (shift) container.parentNode.insertBefore(newEl, container);
7689
+ else container.parentNode.insertBefore(newEl, container.nextElementSibling);
7690
+
7594
7691
  core.callPlugin(fileComponentName, function () {
7595
7692
  if (core.selectComponent(compContext._element, fileComponentName) === false) core.blur();
7596
7693
  }, null);
7597
7694
  }
7598
-
7695
+
7599
7696
  break;
7600
7697
  case 27:
7601
7698
  if (fileComponentName) {
@@ -7640,6 +7737,82 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7640
7737
  }
7641
7738
  },
7642
7739
 
7740
+ _onKeyDown_wysiwyg_arrowKey: function (e) {
7741
+ if (e.shiftKey) return; // shiftkey needs(?) other custom handler. This one may be adapted (in 'selectNode(...)'), but not for table
7742
+
7743
+ let selectionNode = core.getSelectionNode();
7744
+
7745
+ const selectNode = function (node, offset = 0) {
7746
+ e.preventDefault();
7747
+ e.stopPropagation();
7748
+
7749
+ if (!node) return;
7750
+
7751
+ let componentInfo = core.getFileComponent(node);
7752
+ if (componentInfo) {
7753
+ core.selectComponent(componentInfo.target, componentInfo.pluginName); // more responsive for key holdness
7754
+ } else {
7755
+ core.setRange(node, offset, node, offset);
7756
+ core.controllersOff();
7757
+ }
7758
+ };
7759
+
7760
+ const table = util.getParentElement(selectionNode, 'table');
7761
+ if (table) {
7762
+ const currentRow = util.getParentElement(selectionNode, 'tr');
7763
+ const currentCell = util.getParentElement(selectionNode, 'td');
7764
+
7765
+ let currentCellFirstNode = currentCell;
7766
+ let currentCellLastNode = currentCell;
7767
+ if (currentCell) {
7768
+ while (currentCellFirstNode.firstChild) currentCellFirstNode = currentCellFirstNode.firstChild;
7769
+ while (currentCellLastNode.lastChild) currentCellLastNode = currentCellLastNode.lastChild;
7770
+ }
7771
+
7772
+ let selectionNodeDeepestFirstChild = selectionNode;
7773
+ while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
7774
+ const isCellFirstNode = (selectionNodeDeepestFirstChild === currentCellFirstNode);
7775
+ const isCellLastNode = (selectionNodeDeepestFirstChild === currentCellLastNode);
7776
+
7777
+ let siblingToSet = null;
7778
+ let offset = 0;
7779
+ if (e.keyCode === 38 && isCellFirstNode) { // UP
7780
+ const previousRow = currentRow && currentRow.previousElementSibling;
7781
+ if (previousRow) siblingToSet = previousRow.children[currentCell.cellIndex];
7782
+ else siblingToSet = util.getPreviousDeepestNode(table, core.context.element.wysiwyg);
7783
+
7784
+ while (siblingToSet.lastChild) siblingToSet = siblingToSet.lastChild;
7785
+ if (siblingToSet) offset = siblingToSet.textContent.length;
7786
+ } else if (e.keyCode === 40 && isCellLastNode) { // DOWN
7787
+ const nextRow = currentRow && currentRow.nextElementSibling;
7788
+ if (nextRow) siblingToSet = nextRow.children[currentCell.cellIndex];
7789
+ else siblingToSet = util.getNextDeepestNode(table, core.context.element.wysiwyg);
7790
+
7791
+ while (siblingToSet.firstChild) siblingToSet = siblingToSet.firstChild;
7792
+ }
7793
+
7794
+ if (siblingToSet) {
7795
+ selectNode(siblingToSet, offset);
7796
+ return false;
7797
+ }
7798
+ }
7799
+
7800
+ const componentInfo = core.getFileComponent(selectionNode);
7801
+ if (componentInfo) {
7802
+ const selectPrevious = /37|38/.test(e.keyCode);
7803
+ const selectNext = /39|40/.test(e.keyCode);
7804
+
7805
+ if (selectPrevious) {
7806
+ const previousDeepestNode = util.getPreviousDeepestNode(componentInfo.target, core.context.element.wysiwyg);
7807
+ selectNode(previousDeepestNode, previousDeepestNode && previousDeepestNode.textContent.length);
7808
+ } else if (selectNext) {
7809
+ const nextDeepestNode = util.getNextDeepestNode(componentInfo.target, core.context.element.wysiwyg);
7810
+ selectNode(nextDeepestNode);
7811
+ }
7812
+ }
7813
+
7814
+ },
7815
+
7643
7816
  onKeyUp_wysiwyg: function (e) {
7644
7817
  if (event._onShortcutKey) return;
7645
7818
 
@@ -7665,6 +7838,13 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7665
7838
  }
7666
7839
  }
7667
7840
 
7841
+ let selectionNodeDeepestFirstChild = selectionNode;
7842
+ while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
7843
+
7844
+ const selectedComponentInfo = core.getFileComponent(selectionNodeDeepestFirstChild);
7845
+ if (!(e.keyCode === 16 || e.shiftKey) && selectedComponentInfo) core.selectComponent(selectedComponentInfo.target, selectedComponentInfo.pluginName);
7846
+ else if (core.currentFileComponentInfo) core.controllersOff();
7847
+
7668
7848
  /** when format tag deleted */
7669
7849
  if (keyCode === 8 && util.isWysiwygDiv(selectionNode) && selectionNode.textContent === '' && selectionNode.children.length === 0) {
7670
7850
  e.preventDefault();
@@ -7735,7 +7915,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7735
7915
  if (core._antiBlur) return;
7736
7916
  core.hasFocus = true;
7737
7917
  _w.setTimeout(event._applyTagEffects);
7738
-
7918
+
7739
7919
  if (core._isInline) event._showToolbarInline();
7740
7920
 
7741
7921
  // user event
@@ -7810,7 +7990,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7810
7990
  event._showToolbarInline();
7811
7991
  return;
7812
7992
  }
7813
-
7993
+
7814
7994
  core._iframeAutoHeight();
7815
7995
 
7816
7996
  if (core._sticky) {
@@ -7827,7 +8007,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7827
8007
  const y = (this.scrollY || _d.documentElement.scrollTop) + options.stickyToolbar;
7828
8008
  const editorTop = event._getEditorOffsets(options.toolbarContainer).top - (core._isInline ? element.toolbar.offsetHeight : 0);
7829
8009
  const inlineOffset = core._isInline && (y - editorTop) > 0 ? y - editorTop - context.element.toolbar.offsetHeight : 0;
7830
-
8010
+
7831
8011
  if (y < editorTop) {
7832
8012
  event._offStickyToolbar();
7833
8013
  }
@@ -7898,7 +8078,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7898
8078
  const range = core.getRange();
7899
8079
  const sc = range.startContainer;
7900
8080
  const ec = range.endContainer;
7901
-
8081
+
7902
8082
  // table
7903
8083
  const sCell = util.getRangeFormatElement(sc);
7904
8084
  const eCell = util.getRangeFormatElement(ec);
@@ -7940,7 +8120,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7940
8120
 
7941
8121
  onCopy_wysiwyg: function (e) {
7942
8122
  const clipboardData = util.isIE ? _w.clipboardData : e.clipboardData;
7943
-
8123
+
7944
8124
  // user event
7945
8125
  if (typeof functions.onCopy === 'function' && functions.onCopy(e, clipboardData, core) === false) {
7946
8126
  e.preventDefault();
@@ -8000,28 +8180,52 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8000
8180
  const dataTransfer = e.dataTransfer;
8001
8181
  if (!dataTransfer) return true;
8002
8182
 
8003
- core.removeNode();
8004
8183
  event._setDropLocationSelection(e);
8184
+ core.removeNode();
8185
+
8186
+ if (!document.body.contains(core.currentControllerTarget)) core.controllersOff();
8187
+
8005
8188
  return event._dataTransferAction('drop', e, dataTransfer);
8006
8189
  },
8007
8190
 
8008
8191
  _setDropLocationSelection: function (e) {
8192
+ const range = { startContainer: null, startOffset: null, endContainer: null, endOffset: null };
8193
+
8194
+ let r = null;
8009
8195
  if (e.rangeParent) {
8010
- core.setRange(e.rangeParent, e.rangeOffset, e.rangeParent, e.rangeOffset);
8196
+ range.startContainer = e.rangeParent;
8197
+ range.startOffset = e.rangeOffset;
8198
+ range.endContainer = e.rangeParent;
8199
+ range.endOffset = e.rangeOffset;
8011
8200
  } else if (core._wd.caretRangeFromPoint) {
8012
- const r = core._wd.caretRangeFromPoint(e.clientX, e.clientY);
8013
- core.setRange(r.startContainer, r.startOffset, r.endContainer, r.endOffset);
8201
+ r = core._wd.caretRangeFromPoint(e.clientX, e.clientY);
8014
8202
  } else {
8015
- const r = core.getRange();
8016
- core.setRange(r.startContainer, r.startOffset, r.endContainer, r.endOffset);
8203
+ r = core.getRange();
8204
+ }
8205
+ if (r) {
8206
+ range.startContainer = r.startContainer;
8207
+ range.startOffset = r.startOffset;
8208
+ range.endContainer = r.endContainer;
8209
+ range.endOffset = r.endOffset;
8210
+ }
8211
+
8212
+ if (range.startContainer === range.endContainer) {
8213
+ const component = util.getParentElement(range.startContainer, util.isComponent);
8214
+ if (component) {
8215
+ range.startContainer = component;
8216
+ range.startOffset = 0;
8217
+ range.endContainer = component;
8218
+ range.endOffset = 0;
8219
+ }
8017
8220
  }
8221
+ core.setRange(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
8018
8222
  },
8019
8223
 
8020
8224
  _dataTransferAction: function (type, e, data) {
8021
8225
  let plainText, cleanData;
8022
8226
  if (util.isIE) {
8023
8227
  plainText = data.getData('Text');
8024
-
8228
+
8025
8229
  const range = core.getRange();
8026
8230
  const tempDiv = util.createElement('DIV');
8027
8231
  const tempRange = {
@@ -8033,7 +8237,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8033
8237
 
8034
8238
  tempDiv.setAttribute('contenteditable', true);
8035
8239
  tempDiv.style.cssText = 'position:absolute; top:0; left:0; width:1px; height:1px; overflow:hidden;';
8036
-
8240
+
8037
8241
  context.element.relative.appendChild(tempDiv);
8038
8242
  tempDiv.focus();
8039
8243
 
@@ -8117,7 +8321,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8117
8321
  if (core.isDisabled || core.isReadOnly) return false;
8118
8322
  const component = util.getParentElement(e.target, util.isComponent);
8119
8323
  const lineBreakerStyle = core._lineBreaker.style;
8120
-
8324
+
8121
8325
  if (component && !core.currentControllerName) {
8122
8326
  const ctxEl = context.element;
8123
8327
  let scrollTop = 0;
@@ -8157,13 +8361,20 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8157
8361
  }
8158
8362
  },
8159
8363
 
8364
+ _enterPrevent(e) {
8365
+ e.preventDefault();
8366
+ if (!util.isMobile) return;
8367
+
8368
+ core.__focusTemp.focus();
8369
+ },
8370
+
8160
8371
  _onMouseDown_lineBreak: function (e) {
8161
8372
  e.preventDefault();
8162
8373
  },
8163
8374
 
8164
8375
  _onLineBreak: function (e) {
8165
8376
  e.preventDefault();
8166
-
8377
+
8167
8378
  const component = core._variable._lineBreakComp;
8168
8379
  const dir = !this ? core._variable._lineBreakDir : this;
8169
8380
  const isList = util.isListCell(component.parentNode);
@@ -8222,7 +8433,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8222
8433
  /** Events are registered mobile. */
8223
8434
  eventWysiwyg.addEventListener('touchstart', event.onMouseDown_wysiwyg, {passive: true, useCapture: false});
8224
8435
  eventWysiwyg.addEventListener('touchend', event.onClick_wysiwyg, {passive: true, useCapture: false});
8225
-
8436
+
8226
8437
  /** code view area auto line */
8227
8438
  if (options.height === 'auto' && !options.codeMirrorEditor) {
8228
8439
  context.element.code.addEventListener('keydown', event._codeViewAutoHeight, false);
@@ -8238,13 +8449,13 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8238
8449
  util.addClass(context.element.resizingBar, 'se-resizing-none');
8239
8450
  }
8240
8451
  }
8241
-
8452
+
8242
8453
  /** set response toolbar */
8243
8454
  event._setResponsiveToolbar();
8244
8455
 
8245
8456
  /** responsive toolbar observer */
8246
8457
  if (util.isResizeObserverSupported) this._toolbarObserver = new _w.ResizeObserver(core.resetResponsiveToolbar);
8247
-
8458
+
8248
8459
  /** window event */
8249
8460
  _w.addEventListener('resize', event.onResize_window, false);
8250
8461
  if (options.stickyToolbar > -1) {
@@ -8276,7 +8487,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8276
8487
  context.element.lineBreaker_t.removeEventListener('mousedown', event._lineBreakerBind.t);
8277
8488
  context.element.lineBreaker_b.removeEventListener('mousedown', event._lineBreakerBind.b);
8278
8489
  event._lineBreakerBind = null;
8279
-
8490
+
8280
8491
  eventWysiwyg.removeEventListener('touchstart', event.onMouseDown_wysiwyg, {passive: true, useCapture: false});
8281
8492
  eventWysiwyg.removeEventListener('touchend', event.onClick_wysiwyg, {passive: true, useCapture: false});
8282
8493
  eventWysiwyg.removeEventListener('focus', event.onFocus_wysiwyg);
@@ -8285,11 +8496,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8285
8496
  context.element.code.removeEventListener('keydown', event._codeViewAutoHeight);
8286
8497
  context.element.code.removeEventListener('keyup', event._codeViewAutoHeight);
8287
8498
  context.element.code.removeEventListener('paste', event._codeViewAutoHeight);
8288
-
8499
+
8289
8500
  if (context.element.resizingBar) {
8290
8501
  context.element.resizingBar.removeEventListener('mousedown', event.onMouseDown_resizingBar);
8291
8502
  }
8292
-
8503
+
8293
8504
  if (event._resizeObserver) {
8294
8505
  event._resizeObserver.unobserve(context.element.wysiwygFrame);
8295
8506
  event._resizeObserver = null;
@@ -8347,7 +8558,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8347
8558
  onCopy: null,
8348
8559
  onCut: null,
8349
8560
  onFocus: null,
8350
-
8561
+
8351
8562
  /**
8352
8563
  * @description Event functions
8353
8564
  * @param {Object} e Event Object
@@ -8553,15 +8764,15 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8553
8764
  * @param {Object} core Core object
8554
8765
  */
8555
8766
  onImageUpload: null,
8556
- /**
8557
- * @description Called when the video(iframe, video) is is uploaded, updated, deleted
8558
- * -- arguments is same "onImageUpload" --
8559
- */
8767
+ /**
8768
+ * @description Called when the video(iframe, video) is is uploaded, updated, deleted
8769
+ * -- arguments is same "onImageUpload" --
8770
+ */
8560
8771
  onVideoUpload: null,
8561
- /**
8562
- * @description Called when the audio is is uploaded, updated, deleted
8563
- * -- arguments is same "onImageUpload" --
8564
- */
8772
+ /**
8773
+ * @description Called when the audio is is uploaded, updated, deleted
8774
+ * -- arguments is same "onImageUpload" --
8775
+ */
8565
8776
  onAudioUpload: null,
8566
8777
 
8567
8778
  /**
@@ -8605,7 +8816,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8605
8816
  core.submenuOff();
8606
8817
  core.containerOff();
8607
8818
  core.moreLayerOff();
8608
-
8819
+
8609
8820
  const newToolbar = _Constructor._createToolBar(_d, buttonList, core.plugins, options);
8610
8821
  _responsiveButtons = newToolbar.responsiveButtons;
8611
8822
  event._setResponsiveToolbar();
@@ -8634,7 +8845,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8634
8845
  setOptions: function (_options) {
8635
8846
  event._removeEvent();
8636
8847
  core._resetComponents();
8637
-
8848
+
8638
8849
  util.removeClass(core._styleCommandMap.showBlocks, 'active');
8639
8850
  util.removeClass(core._styleCommandMap.codeView, 'active');
8640
8851
  core._variable.isCodeView = false;
@@ -8798,7 +9009,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8798
9009
  getImagesInfo: function () {
8799
9010
  return context.image ? context.image._infoList : [];
8800
9011
  },
8801
-
9012
+
8802
9013
  /**
8803
9014
  * @description Gets uploaded files(plugin using fileManager) information list.
8804
9015
  * image: [img], video: [video, iframe], audio: [audio]
@@ -8888,12 +9099,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8888
9099
  } else {
8889
9100
  let afterNode = null;
8890
9101
  if (util.isFormatElement(html) || util.isMedia(html)) {
8891
- afterNode = util.getFormatElement(core.getSelectionNode(), null);
9102
+ afterNode = util.getFormatElement(core.getSelectionNode(), null);
8892
9103
  }
8893
9104
  core.insertNode(html, afterNode, checkCharCount);
8894
9105
  }
8895
9106
  }
8896
-
9107
+
8897
9108
  core.effectNode = null;
8898
9109
  core.focus();
8899
9110
 
@@ -8915,7 +9126,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8915
9126
  */
8916
9127
  appendContents: function (contents) {
8917
9128
  const convertValue = core.convertContentsForEditor(contents);
8918
-
9129
+
8919
9130
  if (!core._variable.isCodeView) {
8920
9131
  const temp = util.createElement('DIV');
8921
9132
  temp.innerHTML = convertValue;
@@ -8924,7 +9135,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8924
9135
  const children = temp.children;
8925
9136
  for (let i = 0, len = children.length; i < len; i++) {
8926
9137
  if (children[i]) {
8927
- wysiwyg.appendChild(children[i]);
9138
+ wysiwyg.appendChild(children[i]);
8928
9139
  }
8929
9140
  }
8930
9141
  } else {
@@ -8941,7 +9152,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8941
9152
  */
8942
9153
  readOnly: function (value) {
8943
9154
  core.isReadOnly = value;
8944
-
9155
+
8945
9156
  util.setDisabledButtons(!!value, core.resizingDisabledButtons);
8946
9157
 
8947
9158
  if (value) {
@@ -8973,7 +9184,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8973
9184
  /**
8974
9185
  * @description Provided for backward compatibility and will be removed in 3.0.0 version
8975
9186
  */
8976
- disabled: function () {
9187
+ disabled: function () {
8977
9188
  this.disable();
8978
9189
  },
8979
9190
 
@@ -8988,7 +9199,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8988
9199
  /**
8989
9200
  * @description Provided for backward compatibility and will be removed in 3.0.0 version
8990
9201
  */
8991
- enabled: function () {
9202
+ enabled: function () {
8992
9203
  this.enable();
8993
9204
  },
8994
9205
 
@@ -9023,7 +9234,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
9023
9234
 
9024
9235
  /** remove event listeners */
9025
9236
  event._removeEvent();
9026
-
9237
+
9027
9238
  /** remove element */
9028
9239
  util.removeItem(context.element.toolbar);
9029
9240
  util.removeItem(context.element.topArea);
@@ -9034,7 +9245,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
9034
9245
  for (let k in event) { if (util.hasOwn(event, k)) delete event[k]; }
9035
9246
  for (let k in context) { if (util.hasOwn(context, k)) delete context[k]; }
9036
9247
  for (let k in pluginCallButtons) { if (util.hasOwn(pluginCallButtons, k)) delete pluginCallButtons[k]; }
9037
-
9248
+
9038
9249
  /** remove user object */
9039
9250
  for (let k in this) { if (util.hasOwn(this, k)) delete this[k]; }
9040
9251
  },
@@ -9072,7 +9283,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
9072
9283
  /**
9073
9284
  * @description Provided for backward compatibility and will be removed in 3.0.0 version
9074
9285
  */
9075
- enabled: function () {
9286
+ enabled: function () {
9076
9287
  this.enable();
9077
9288
  },
9078
9289
 
@@ -9108,12 +9319,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
9108
9319
  /**
9109
9320
  * @description Wysiwyg methods
9110
9321
  */
9111
- wysiwyg: {
9322
+ wysiwyg: {
9112
9323
  /**
9113
9324
  * @description Disable the wysiwyg area
9114
9325
  */
9115
9326
  disable: function () {
9116
- /** off menus */
9327
+ /** off menus */
9117
9328
  core.controllersOff();
9118
9329
  if (core.modalForm) core.plugins.dialog.close.call(core);
9119
9330
 
@@ -9140,7 +9351,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
9140
9351
  context.element.code.removeAttribute('disabled');
9141
9352
  }
9142
9353
  },
9143
- }
9354
+ }
9144
9355
  };
9145
9356
 
9146
9357
  /************ Core init ************/