suneditor 2.47.0 → 2.47.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "suneditor",
3
- "version": "2.47.0",
3
+ "version": "2.47.2",
4
4
  "description": "Vanilla javascript based WYSIWYG web editor, with no dependencies",
5
5
  "author": "JiHong.Lee",
6
6
  "license": "MIT",
@@ -416,6 +416,7 @@ export default {
416
416
  options.plugins = plugins;
417
417
  /** Values */
418
418
  options.strictMode = options.strictMode !== false;
419
+ options.strictHTMLValidation = options.strictHTMLValidation !== false;
419
420
  options.lang = options.lang || _defaultLang;
420
421
  options.value = typeof options.value === 'string' ? options.value : null;
421
422
  options.allowedClassNames = new util._w.RegExp((options.allowedClassNames && typeof options.allowedClassNames === 'string' ? options.allowedClassNames + '|' : '') + '^__se__|se-|katex');
@@ -542,6 +543,7 @@ export default {
542
543
  options.imageMultipleFile = !!options.imageMultipleFile;
543
544
  options.imageAccept = (typeof options.imageAccept !== 'string' || options.imageAccept.trim() === "*") ? 'image/*' : options.imageAccept.trim() || 'image/*';
544
545
  /** Image - image gallery */
546
+ options.imageGalleryData = options.imageGalleryData || null;
545
547
  options.imageGalleryUrl = typeof options.imageGalleryUrl === 'string' ? options.imageGalleryUrl : null;
546
548
  options.imageGalleryHeader = options.imageGalleryHeader || null;
547
549
  /** Video */
package/src/lib/core.js CHANGED
@@ -1270,6 +1270,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1270
1270
  const range = this.getRange();
1271
1271
  if (this._selectionVoid(range)) return false;
1272
1272
 
1273
+ const collapsed = range.collapsed;
1273
1274
  let startCon = range.startContainer;
1274
1275
  let startOff = range.startOffset;
1275
1276
  let endCon = range.endContainer;
@@ -1294,7 +1295,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1294
1295
  while (endCon && endCon.nodeType === 1 && endCon.lastChild) {
1295
1296
  endCon = endCon.lastChild;
1296
1297
  }
1297
- endOff = endCon.textContent.length;
1298
+ endOff = collapsed ? 0 : endCon.textContent.length;
1298
1299
  }
1299
1300
 
1300
1301
  // startContainer
@@ -1474,18 +1475,19 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1474
1475
  * @description Determine if this offset is the edge offset of container
1475
1476
  * @param {Node} container The node of the selection object. (range.startContainer..)
1476
1477
  * @param {Number} offset The offset of the selection object. (core.getRange().startOffset...)
1477
- * @param {String|undefined} dir Select check point - Both edge, Front edge or End edge. ("front": Front edge, "end": End edge, undefined: Both edge)
1478
+ * @param {String|undefined} dir Select check point - Both edge, Front edge or End edge. ("start": Front edge, "end": End edge, undefined: Both edge)
1478
1479
  * @returns {Boolean}
1479
1480
  */
1480
1481
  isEdgePoint: function (container, offset, dir) {
1481
- return (dir !== 'end' && offset === 0) || ((!dir || dir !== 'front') && !container.nodeValue && offset === 1) || ((!dir || dir === 'end') && !!container.nodeValue && offset === container.nodeValue.length);
1482
+ if (container.nodeType === 1 && !container.textContent.length) return true;
1483
+ return (dir !== 'end' && offset === 0) || ((!dir || dir !== 'start') && !container.nodeValue && offset === 1) || ((!dir || dir === 'end') && !!container.nodeValue && offset === container.nodeValue.length);
1482
1484
  },
1483
1485
 
1484
1486
  /**
1485
1487
  * @description Check if the container and offset values are the edges of the format tag
1486
1488
  * @param {Node} container The node of the selection object. (range.startContainer..)
1487
1489
  * @param {Number} offset The offset of the selection object. (core.getRange().startOffset...)
1488
- * @param {String} dir Select check point - "front": Front edge, "end": End edge, undefined: Both edge.
1490
+ * @param {String} dir Select check point - "start": Front edge, "end": End edge, undefined: Both edge.
1489
1491
  * @returns {Array|null}
1490
1492
  * @private
1491
1493
  */
@@ -1493,7 +1495,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
1493
1495
  if (!this.isEdgePoint(node, offset, dir)) return false;
1494
1496
 
1495
1497
  const result = [];
1496
- dir = dir === 'front' ? 'previousSibling' : 'nextSibling';
1498
+ dir = dir === 'start' ? 'previousSibling' : 'nextSibling';
1497
1499
  while (node && !util.isFormatElement(node) && !util.isWysiwygDiv(node)) {
1498
1500
  if (!node[dir] || (util.isBreak(node[dir]) && !node[dir][dir])) {
1499
1501
  if (node.nodeType === 1) result.push(node.cloneNode(false));
@@ -5478,12 +5480,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5478
5480
  * @returns {String}
5479
5481
  */
5480
5482
  cleanHTML: function (html, whitelist, blacklist) {
5481
- if (!options.strictMode) return html;
5483
+ if (!options.strictMode) return util.htmlCompress(html);
5482
5484
 
5483
5485
  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, '');
5484
5486
  const dom = _d.createRange().createContextualFragment(html);
5485
5487
  try {
5486
- util._consistencyCheckOfHTML(dom, this._htmlCheckWhitelistRegExp, this._htmlCheckBlacklistRegExp, this._classNameFilter);
5488
+ util._consistencyCheckOfHTML(dom, this._htmlCheckWhitelistRegExp, this._htmlCheckBlacklistRegExp, this._classNameFilter, options.strictHTMLValidation);
5487
5489
  } catch (error) {
5488
5490
  console.warn('[SUNEDITOR.cleanHTML.consistencyCheck.fail] ' + error);
5489
5491
  }
@@ -5536,12 +5538,13 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5536
5538
  * @returns {String}
5537
5539
  */
5538
5540
  convertContentsForEditor: function (contents) {
5539
- if (!options.strictMode) return contents;
5541
+ if (!options.strictMode) return util.htmlCompress(contents);
5542
+
5540
5543
  contents = this._deleteDisallowedTags(this._parser.parseFromString(util.htmlCompress(contents), 'text/html').body.innerHTML).replace(/(<[a-zA-Z0-9\-]+)[^>]*(?=>)/g, this._cleanTags.bind(this, true));
5541
5544
  const dom = _d.createRange().createContextualFragment(contents);
5542
5545
 
5543
5546
  try {
5544
- util._consistencyCheckOfHTML(dom, this._htmlCheckWhitelistRegExp, this._htmlCheckBlacklistRegExp, this._classNameFilter);
5547
+ util._consistencyCheckOfHTML(dom, this._htmlCheckWhitelistRegExp, this._htmlCheckBlacklistRegExp, this._classNameFilter, options.strictHTMLValidation);
5545
5548
  } catch (error) {
5546
5549
  console.warn('[SUNEDITOR.convertContentsForEditor.consistencyCheck.fail] ' + error);
5547
5550
  }
@@ -6235,6 +6238,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6235
6238
  this.execCommand('formatBlock', false, (formatName || options.defaultTag));
6236
6239
  this.removeRange();
6237
6240
  this._editorRange();
6241
+ this.effectNode = null;
6242
+ return;
6238
6243
  }
6239
6244
 
6240
6245
  if (format) {
@@ -6248,7 +6253,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6248
6253
  }
6249
6254
 
6250
6255
  this.effectNode = null;
6251
- this.nativeFocus();
6256
+
6257
+ if (startCon) {
6258
+ this.setRange(startCon, 1, startCon, 1);
6259
+ } else {
6260
+ this.nativeFocus();
6261
+ }
6252
6262
  },
6253
6263
 
6254
6264
  /**
@@ -6532,7 +6542,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6532
6542
  }
6533
6543
  },
6534
6544
 
6535
- addGlobalEvent(type, listener, useCapture) {
6545
+ addGlobalEvent: function (type, listener, useCapture) {
6536
6546
  if (options.iframe) {
6537
6547
  core._ww.addEventListener(type, listener, useCapture);
6538
6548
  }
@@ -6544,7 +6554,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6544
6554
  };
6545
6555
  },
6546
6556
 
6547
- removeGlobalEvent(type, listener, useCapture) {
6557
+ removeGlobalEvent: function (type, listener, useCapture) {
6548
6558
  if (!type) return;
6549
6559
 
6550
6560
  if (typeof type === 'object') {
@@ -6588,7 +6598,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6588
6598
 
6589
6599
  event.removeGlobalEvent(event.__selectionSyncEvent);
6590
6600
  event.__selectionSyncEvent = event.addGlobalEvent('mouseup', function() {
6591
- core._editorRange();
6601
+ if (core) {
6602
+ core._editorRange();
6603
+ }
6592
6604
  event.removeGlobalEvent(event.__selectionSyncEvent);
6593
6605
  });
6594
6606
 
@@ -6670,7 +6682,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6670
6682
  const rangeEl = util.getRangeFormatElement(selectionNode, null);
6671
6683
 
6672
6684
  let selectionNodeDeepestFirstChild = selectionNode;
6673
- while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
6685
+ while (selectionNodeDeepestFirstChild && selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
6674
6686
 
6675
6687
  const selectedComponentInfo = core.getFileComponent(selectionNodeDeepestFirstChild);
6676
6688
  if (selectedComponentInfo) {
@@ -6716,10 +6728,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6716
6728
  },
6717
6729
 
6718
6730
  _toggleToolbarBalloon: function () {
6719
- core._editorRange();
6720
- const range = core.getRange();
6721
- if (core._bindControllersOff || (!core._isBalloonAlways && range.collapsed)) event._hideToolbar();
6722
- else event._showToolbarBalloon(range);
6731
+ if (core) {
6732
+ core._editorRange();
6733
+ const range = core.getRange();
6734
+ if (core._bindControllersOff || (!core._isBalloonAlways && range.collapsed)) event._hideToolbar();
6735
+ else event._showToolbarBalloon(range);
6736
+ }
6723
6737
  },
6724
6738
 
6725
6739
  _showToolbarBalloon: function (rangeObj) {
@@ -6896,6 +6910,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6896
6910
  return false;
6897
6911
  }
6898
6912
 
6913
+ const range = core.getRange();
6914
+ const selectionNode = core.getSelectionNode();
6915
+ const formatEl = util.getFormatElement(selectionNode, null);
6916
+ if (!formatEl && range.collapsed && !util.isComponent(selectionNode) && !util.isList(selectionNode)) {
6917
+ const rangeEl = util.getRangeFormatElement(formatEl, null);
6918
+ core._setDefaultFormat(util.isRangeFormatElement(rangeEl) ? 'DIV' : options.defaultTag);
6919
+ }
6920
+
6899
6921
  core._editorRange();
6900
6922
 
6901
6923
  const data = (e.data === null ? '' : e.data === undefined ? ' ' : e.data) || '';
@@ -6924,7 +6946,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6924
6946
  return siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false';
6925
6947
  } else {
6926
6948
  siblingNode = event._isUneditableNode_getSibling(container, siblingKey, container);
6927
- return core.isEdgePoint(container, offset, isFront ? 'front' : 'end') && (siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false');
6949
+ return core.isEdgePoint(container, offset, isFront ? 'start' : 'end') && (siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false');
6928
6950
  }
6929
6951
  },
6930
6952
 
@@ -6978,6 +7000,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6978
7000
  }
6979
7001
 
6980
7002
  /** default key action */
7003
+ if (keyCode === 13 && util.isFormatElement(core.getRange().startContainer)) {
7004
+ core._resetRangeToTextNode();
7005
+ selectionNode = core.getSelectionNode();
7006
+ }
7007
+
6981
7008
  const range = core.getRange();
6982
7009
  const selectRange = !range.collapsed || range.startContainer !== range.endContainer;
6983
7010
  const fileComponentName = core._fileManager.pluginRegExp.test(core.currentControllerName) ? core.currentControllerName : '';
@@ -7204,6 +7231,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7204
7231
  break;
7205
7232
  }
7206
7233
 
7234
+ if (!selectRange && core._isEdgeFormat(range.endContainer, range.endOffset, 'end') && !formatEl.nextSibling) {
7235
+ e.preventDefault();
7236
+ e.stopPropagation();
7237
+ return;
7238
+ }
7239
+
7207
7240
  // tag[contenteditable="false"]
7208
7241
  if (event._isUneditableNode(range, false)) {
7209
7242
  e.preventDefault();
@@ -7358,15 +7391,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7358
7391
  if (!shift) {
7359
7392
  const tabText = util.createTextNode(new _w.Array(core._variable.tabSize + 1).join('\u00A0'));
7360
7393
  if (lines.length === 1) {
7361
- const textRange = core.insertNode(tabText, null, true);
7362
- if (!textRange) return false;
7394
+ if (!core.insertNode(tabText, null, true)) return false;
7363
7395
  if (!fc) {
7364
7396
  r.sc = tabText;
7365
- r.so = textRange.endOffset;
7397
+ r.so = tabText.length;
7366
7398
  }
7367
7399
  if (!lc) {
7368
7400
  r.ec = tabText;
7369
- r.eo = textRange.endOffset;
7401
+ r.eo = tabText.length;
7370
7402
  }
7371
7403
  } else {
7372
7404
  const len = lines.length - 1;
@@ -7596,7 +7628,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7596
7628
  const isMultiLine = util.getFormatElement(range.startContainer, null) !== util.getFormatElement(range.endContainer, null);
7597
7629
  const newFormat = formatEl.cloneNode(false);
7598
7630
  newFormat.innerHTML = '<br>';
7599
- const r = core.removeNode();
7631
+ const commonCon = range.commonAncestorContainer;
7632
+ const r = commonCon === range.startContainer && commonCon === range.endContainer && util.onlyZeroWidthSpace(commonCon) ? range : core.removeNode();
7600
7633
  newEl = util.getFormatElement(r.container, null);
7601
7634
  if (!newEl) {
7602
7635
  if (util.isWysiwygDiv(r.container)) {
@@ -7711,8 +7744,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7711
7744
  e.preventDefault();
7712
7745
  e.stopPropagation();
7713
7746
  const nbsp = core.insertNode(util.createTextNode('\u00a0'));
7714
- if (nbsp && nbsp.container) {
7715
- core.setRange(nbsp.container, nbsp.endOffset, nbsp.container, nbsp.endOffset);
7747
+ if (nbsp) {
7748
+ core.setRange(nbsp, nbsp.length, nbsp, nbsp.length);
7716
7749
  return;
7717
7750
  }
7718
7751
  }
@@ -7724,7 +7757,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7724
7757
  }
7725
7758
 
7726
7759
  if (event._directionKeyCode.test(keyCode)) {
7727
- core._editorRange();
7760
+ _w.setTimeout(core._editorRange.bind(core), 0);
7728
7761
  event._applyTagEffects();
7729
7762
  }
7730
7763
  },
@@ -7734,7 +7767,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7734
7767
 
7735
7768
  let selectionNode = core.getSelectionNode();
7736
7769
 
7737
- const selectNode = function (node, offset = 0) {
7770
+ const selectNode = function (node, offset) {
7771
+ if (!offset) offset = 0;
7738
7772
  e.preventDefault();
7739
7773
  e.stopPropagation();
7740
7774
 
@@ -7757,12 +7791,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7757
7791
  let currentCellFirstNode = currentCell;
7758
7792
  let currentCellLastNode = currentCell;
7759
7793
  if (currentCell) {
7760
- while (currentCellFirstNode.firstChild) currentCellFirstNode = currentCellFirstNode.firstChild;
7761
- while (currentCellLastNode.lastChild) currentCellLastNode = currentCellLastNode.lastChild;
7794
+ while (currentCellFirstNode && currentCellFirstNode.firstChild) currentCellFirstNode = currentCellFirstNode.firstChild;
7795
+ while (currentCellLastNode && currentCellLastNode.lastChild) currentCellLastNode = currentCellLastNode.lastChild;
7762
7796
  }
7763
7797
 
7764
7798
  let selectionNodeDeepestFirstChild = selectionNode;
7765
- while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
7799
+ while (selectionNodeDeepestFirstChild && selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
7766
7800
  const isCellFirstNode = (selectionNodeDeepestFirstChild === currentCellFirstNode);
7767
7801
  const isCellLastNode = (selectionNodeDeepestFirstChild === currentCellLastNode);
7768
7802
 
@@ -7773,14 +7807,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7773
7807
  if (previousRow) siblingToSet = previousRow.children[currentCell.cellIndex];
7774
7808
  else siblingToSet = util.getPreviousDeepestNode(table, core.context.element.wysiwyg);
7775
7809
 
7776
- while (siblingToSet.lastChild) siblingToSet = siblingToSet.lastChild;
7810
+ while (siblingToSet && siblingToSet.lastChild) siblingToSet = siblingToSet.lastChild;
7777
7811
  if (siblingToSet) offset = siblingToSet.textContent.length;
7778
7812
  } else if (e.keyCode === 40 && isCellLastNode) { // DOWN
7779
7813
  const nextRow = currentRow && currentRow.nextElementSibling;
7780
7814
  if (nextRow) siblingToSet = nextRow.children[currentCell.cellIndex];
7781
7815
  else siblingToSet = util.getNextDeepestNode(table, core.context.element.wysiwyg);
7782
7816
 
7783
- while (siblingToSet.firstChild) siblingToSet = siblingToSet.firstChild;
7817
+ while (siblingToSet && siblingToSet.firstChild) siblingToSet = siblingToSet.firstChild;
7784
7818
  }
7785
7819
 
7786
7820
  if (siblingToSet) {
@@ -7831,7 +7865,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7831
7865
  }
7832
7866
 
7833
7867
  let selectionNodeDeepestFirstChild = selectionNode;
7834
- while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
7868
+ while (selectionNodeDeepestFirstChild && selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
7835
7869
 
7836
7870
  const selectedComponentInfo = core.getFileComponent(selectionNodeDeepestFirstChild);
7837
7871
  if (!(e.keyCode === 16 || e.shiftKey) && selectedComponentInfo) core.selectComponent(selectedComponentInfo.target, selectedComponentInfo.pluginName);
@@ -8353,7 +8387,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
8353
8387
  }
8354
8388
  },
8355
8389
 
8356
- _enterPrevent(e) {
8390
+ _enterPrevent: function (e) {
8357
8391
  e.preventDefault();
8358
8392
  if (!util.isMobile) return;
8359
8393
 
package/src/lib/util.js CHANGED
@@ -28,7 +28,7 @@ const util = {
28
28
  this.isOSX_IOS = /(Mac|iPhone|iPod|iPad)/.test(navigator.platform);
29
29
  this.isChromium = !!window.chrome;
30
30
  this.isResizeObserverSupported = (typeof ResizeObserver === 'function');
31
- this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
31
+ this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || ((navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0) && 'ontouchstart' in window);
32
32
  },
33
33
 
34
34
  _allowedEmptyNodeList: '.se-component, pre, blockquote, hr, li, table, img, iframe, video, audio, canvas',
@@ -1931,9 +1931,10 @@ const util = {
1931
1931
  * @param {RegExp} htmlCheckWhitelistRegExp Editor tags whitelist (core._htmlCheckWhitelistRegExp)
1932
1932
  * @param {RegExp} htmlCheckBlacklistRegExp Editor tags blacklist (core._htmlCheckBlacklistRegExp)
1933
1933
  * @param {Function} classNameFilter Class name filter function
1934
+ * @param {Function} strictHTMLValidation Enforces strict HTML validation based on the editor`s policy
1934
1935
  * @private
1935
1936
  */
1936
- _consistencyCheckOfHTML: function (documentFragment, htmlCheckWhitelistRegExp, htmlCheckBlacklistRegExp, classNameFilter) {
1937
+ _consistencyCheckOfHTML: function (documentFragment, htmlCheckWhitelistRegExp, htmlCheckBlacklistRegExp, classNameFilter, strictHTMLValidation) {
1937
1938
  /**
1938
1939
  * It is can use ".children(util.getListChildren)" to exclude text nodes, but "documentFragment.children" is not supported in IE.
1939
1940
  * So check the node type and exclude the text no (current.nodeType !== 1)
@@ -1982,7 +1983,7 @@ const util = {
1982
1983
  else current.removeAttribute('class');
1983
1984
  }
1984
1985
 
1985
- const result = current.parentNode !== documentFragment && nrtag &&
1986
+ const result = strictHTMLValidation && current.parentNode !== documentFragment && nrtag &&
1986
1987
  ((this.isListCell(current) && !this.isList(current.parentNode)) ||
1987
1988
  ((this.isFormatElement(current) || this.isComponent(current)) && !this.isRangeFormatElement(current.parentNode) && !this.getParentElement(current, this.isComponent)));
1988
1989
 
package/src/options.d.ts CHANGED
@@ -3,6 +3,14 @@ import { Plugin } from './plugins/Plugin';
3
3
 
4
4
  export interface SunEditorOptions {
5
5
  plugins?: Plugin[] | Record<string, Plugin>;
6
+ /**
7
+ * Option to disable clean mode, which checks the styles, classes, etc. of the editor content
8
+ */
9
+ strictMode?: boolean;
10
+ /**
11
+ * Enforces strict HTML validation based on the editor`s policy. Applies to methods like setContents to ensure content compliance when enabled.
12
+ */
13
+ strictHTMLValidation?: boolean;
6
14
  /**
7
15
  * Values
8
16
  * ======
@@ -355,6 +363,10 @@ export interface SunEditorOptions {
355
363
  * Image - image gallery
356
364
  * =====
357
365
  */
366
+ /**
367
+ * Direct JSON data without making server requests.
368
+ */
369
+ imageGalleryData?: Array;
358
370
  /**
359
371
  * The url of the image gallery, if you use the image gallery
360
372
  */
@@ -684,7 +684,7 @@ export default {
684
684
  imagePlugin.setAlign.call(this, align, oImg, cover, container);
685
685
 
686
686
  oImg.onload = imagePlugin._image_create_onload.bind(this, oImg, contextImage.svgDefaultSize, container);
687
- if (this.insertComponent(container, true, true, true)) this.plugins.fileManager.setInfo.call(this, 'image', oImg, this.functions.onImageUpload, file, true);
687
+ if (this.insertComponent(container, true, true, !this.options.mediaAutoSelect)) this.plugins.fileManager.setInfo.call(this, 'image', oImg, this.functions.onImageUpload, file, true);
688
688
  this.context.resizing._resize_plugin = '';
689
689
  },
690
690
 
@@ -697,6 +697,7 @@ export default {
697
697
  const line = this.appendFormatTag(container, null);
698
698
  if (line) this.setRange(line, 0, line, 0);
699
699
  }
700
+ this.history.push(false);
700
701
  },
701
702
 
702
703
  update_image: function (init, openController, notHistoryPush) {
@@ -21,7 +21,8 @@ export default {
21
21
  const context = core.context;
22
22
  context.imageGallery = {
23
23
  title: core.lang.toolbar.imageGallery, // @Required @Override fileBrowser - File browser window title.
24
- url: core.options.imageGalleryUrl, // @Required @Override fileBrowser - File server url.
24
+ directData: core.options.imageGalleryData, // @option @Override fileBrowser - Direct JSON data without making server requests.
25
+ url: core.options.imageGalleryUrl, // @option @Override fileBrowser - File server url.
25
26
  header: core.options.imageGalleryHeader, // @Required @Override fileBrowser - File server http header.
26
27
  listClass: 'se-image-list', // @Required @Override fileBrowser - Class name of list div.
27
28
  itemTemplateHandler: this.drawItems, // @Required @Override fileBrowser - Function that defines the HTML of an file item.
@@ -162,7 +162,11 @@
162
162
  fileBrowserContext.titleArea.textContent = pluginContext.title;
163
163
  fileBrowserContext.area.style.display = 'block';
164
164
 
165
- this.plugins.fileBrowser._drawFileList.call(this, this.context[pluginName].url, this.context[pluginName].header);
165
+ if (this.context[pluginName].directData) {
166
+ this.plugins.fileBrowser._drawListItem.call(this, this.context[pluginName].directData, true);
167
+ } else {
168
+ this.plugins.fileBrowser._drawFileList.call(this, this.context[pluginName].url, this.context[pluginName].header);
169
+ }
166
170
  },
167
171
 
168
172
  _bindClose: null,
@@ -286,7 +286,7 @@ export default {
286
286
  }
287
287
 
288
288
  this.effectNode = null;
289
- return !isCollapsed ? originRange : afterRange;
289
+ return !isCollapsed ? originRange : afterRange || originRange;
290
290
  },
291
291
 
292
292
  _detachNested: function (cells) {
@@ -1,5 +0,0 @@
1
- import { DialogPlugin } from '../DialogPlugin';
2
-
3
- declare const mention: DialogPlugin;
4
-
5
- export default mention;