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/README.md +11 -0
- package/dist/suneditor.min.js +2 -2
- package/package.json +1 -1
- package/src/lib/constructor.js +2 -0
- package/src/lib/core.js +69 -35
- package/src/lib/util.js +4 -3
- package/src/options.d.ts +12 -0
- package/src/plugins/dialog/image.js +2 -1
- package/src/plugins/fileBrowser/imageGallery.js +2 -1
- package/src/plugins/modules/fileBrowser.js +5 -1
- package/src/plugins/submenu/list.js +1 -1
- package/src/plugins/dialog/mention.d.ts +0 -5
- package/src/plugins/dialog/mention.js +0 -242
package/package.json
CHANGED
package/src/lib/constructor.js
CHANGED
|
@@ -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. ("
|
|
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
|
-
|
|
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 - "
|
|
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 === '
|
|
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
|
-
|
|
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
|
|
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
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
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 ? '
|
|
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
|
-
|
|
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 =
|
|
7397
|
+
r.so = tabText.length;
|
|
7366
7398
|
}
|
|
7367
7399
|
if (!lc) {
|
|
7368
7400
|
r.ec = tabText;
|
|
7369
|
-
r.eo =
|
|
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
|
|
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
|
|
7715
|
-
core.setRange(nbsp
|
|
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
|
|
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) ||
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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,
|