suneditor 2.47.0 → 2.47.1
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 -32
- package/src/lib/util.js +1 -1
- 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 === true;
|
|
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));
|
|
@@ -5541,7 +5543,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5541
5543
|
const dom = _d.createRange().createContextualFragment(contents);
|
|
5542
5544
|
|
|
5543
5545
|
try {
|
|
5544
|
-
|
|
5546
|
+
if (this.options.strictHTMLValidation) {
|
|
5547
|
+
util._consistencyCheckOfHTML(dom, this._htmlCheckWhitelistRegExp, this._htmlCheckBlacklistRegExp, this._classNameFilter);
|
|
5548
|
+
} else {
|
|
5549
|
+
util._consistencyCheckOfHTML(dom, this._htmlCheckWhitelistRegExp, false);
|
|
5550
|
+
}
|
|
5545
5551
|
} catch (error) {
|
|
5546
5552
|
console.warn('[SUNEDITOR.convertContentsForEditor.consistencyCheck.fail] ' + error);
|
|
5547
5553
|
}
|
|
@@ -6235,6 +6241,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6235
6241
|
this.execCommand('formatBlock', false, (formatName || options.defaultTag));
|
|
6236
6242
|
this.removeRange();
|
|
6237
6243
|
this._editorRange();
|
|
6244
|
+
this.effectNode = null;
|
|
6245
|
+
return;
|
|
6238
6246
|
}
|
|
6239
6247
|
|
|
6240
6248
|
if (format) {
|
|
@@ -6248,7 +6256,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6248
6256
|
}
|
|
6249
6257
|
|
|
6250
6258
|
this.effectNode = null;
|
|
6251
|
-
|
|
6259
|
+
|
|
6260
|
+
if (startCon) {
|
|
6261
|
+
this.setRange(startCon, 1, startCon, 1);
|
|
6262
|
+
} else {
|
|
6263
|
+
this.nativeFocus();
|
|
6264
|
+
}
|
|
6252
6265
|
},
|
|
6253
6266
|
|
|
6254
6267
|
/**
|
|
@@ -6532,7 +6545,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6532
6545
|
}
|
|
6533
6546
|
},
|
|
6534
6547
|
|
|
6535
|
-
addGlobalEvent(type, listener, useCapture) {
|
|
6548
|
+
addGlobalEvent: function (type, listener, useCapture) {
|
|
6536
6549
|
if (options.iframe) {
|
|
6537
6550
|
core._ww.addEventListener(type, listener, useCapture);
|
|
6538
6551
|
}
|
|
@@ -6544,7 +6557,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6544
6557
|
};
|
|
6545
6558
|
},
|
|
6546
6559
|
|
|
6547
|
-
removeGlobalEvent(type, listener, useCapture) {
|
|
6560
|
+
removeGlobalEvent: function (type, listener, useCapture) {
|
|
6548
6561
|
if (!type) return;
|
|
6549
6562
|
|
|
6550
6563
|
if (typeof type === 'object') {
|
|
@@ -6588,7 +6601,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6588
6601
|
|
|
6589
6602
|
event.removeGlobalEvent(event.__selectionSyncEvent);
|
|
6590
6603
|
event.__selectionSyncEvent = event.addGlobalEvent('mouseup', function() {
|
|
6591
|
-
core
|
|
6604
|
+
if (core) {
|
|
6605
|
+
core._editorRange();
|
|
6606
|
+
}
|
|
6592
6607
|
event.removeGlobalEvent(event.__selectionSyncEvent);
|
|
6593
6608
|
});
|
|
6594
6609
|
|
|
@@ -6670,7 +6685,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6670
6685
|
const rangeEl = util.getRangeFormatElement(selectionNode, null);
|
|
6671
6686
|
|
|
6672
6687
|
let selectionNodeDeepestFirstChild = selectionNode;
|
|
6673
|
-
while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
6688
|
+
while (selectionNodeDeepestFirstChild && selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
6674
6689
|
|
|
6675
6690
|
const selectedComponentInfo = core.getFileComponent(selectionNodeDeepestFirstChild);
|
|
6676
6691
|
if (selectedComponentInfo) {
|
|
@@ -6716,10 +6731,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6716
6731
|
},
|
|
6717
6732
|
|
|
6718
6733
|
_toggleToolbarBalloon: function () {
|
|
6719
|
-
core
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6734
|
+
if (core) {
|
|
6735
|
+
core._editorRange();
|
|
6736
|
+
const range = core.getRange();
|
|
6737
|
+
if (core._bindControllersOff || (!core._isBalloonAlways && range.collapsed)) event._hideToolbar();
|
|
6738
|
+
else event._showToolbarBalloon(range);
|
|
6739
|
+
}
|
|
6723
6740
|
},
|
|
6724
6741
|
|
|
6725
6742
|
_showToolbarBalloon: function (rangeObj) {
|
|
@@ -6896,6 +6913,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6896
6913
|
return false;
|
|
6897
6914
|
}
|
|
6898
6915
|
|
|
6916
|
+
const range = core.getRange();
|
|
6917
|
+
const selectionNode = core.getSelectionNode();
|
|
6918
|
+
const formatEl = util.getFormatElement(selectionNode, null);
|
|
6919
|
+
if (!formatEl && range.collapsed && !util.isComponent(selectionNode) && !util.isList(selectionNode)) {
|
|
6920
|
+
const rangeEl = util.getRangeFormatElement(formatEl, null);
|
|
6921
|
+
core._setDefaultFormat(util.isRangeFormatElement(rangeEl) ? 'DIV' : options.defaultTag);
|
|
6922
|
+
}
|
|
6923
|
+
|
|
6899
6924
|
core._editorRange();
|
|
6900
6925
|
|
|
6901
6926
|
const data = (e.data === null ? '' : e.data === undefined ? ' ' : e.data) || '';
|
|
@@ -6924,7 +6949,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6924
6949
|
return siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false';
|
|
6925
6950
|
} else {
|
|
6926
6951
|
siblingNode = event._isUneditableNode_getSibling(container, siblingKey, container);
|
|
6927
|
-
return core.isEdgePoint(container, offset, isFront ? '
|
|
6952
|
+
return core.isEdgePoint(container, offset, isFront ? 'start' : 'end') && (siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false');
|
|
6928
6953
|
}
|
|
6929
6954
|
},
|
|
6930
6955
|
|
|
@@ -6978,6 +7003,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6978
7003
|
}
|
|
6979
7004
|
|
|
6980
7005
|
/** default key action */
|
|
7006
|
+
if (keyCode === 13 && util.isFormatElement(core.getRange().startContainer)) {
|
|
7007
|
+
core._resetRangeToTextNode();
|
|
7008
|
+
selectionNode = core.getSelectionNode();
|
|
7009
|
+
}
|
|
7010
|
+
|
|
6981
7011
|
const range = core.getRange();
|
|
6982
7012
|
const selectRange = !range.collapsed || range.startContainer !== range.endContainer;
|
|
6983
7013
|
const fileComponentName = core._fileManager.pluginRegExp.test(core.currentControllerName) ? core.currentControllerName : '';
|
|
@@ -7204,6 +7234,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7204
7234
|
break;
|
|
7205
7235
|
}
|
|
7206
7236
|
|
|
7237
|
+
if (!selectRange && core._isEdgeFormat(range.endContainer, range.endOffset, 'end') && !formatEl.nextSibling) {
|
|
7238
|
+
e.preventDefault();
|
|
7239
|
+
e.stopPropagation();
|
|
7240
|
+
return;
|
|
7241
|
+
}
|
|
7242
|
+
|
|
7207
7243
|
// tag[contenteditable="false"]
|
|
7208
7244
|
if (event._isUneditableNode(range, false)) {
|
|
7209
7245
|
e.preventDefault();
|
|
@@ -7358,15 +7394,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7358
7394
|
if (!shift) {
|
|
7359
7395
|
const tabText = util.createTextNode(new _w.Array(core._variable.tabSize + 1).join('\u00A0'));
|
|
7360
7396
|
if (lines.length === 1) {
|
|
7361
|
-
|
|
7362
|
-
if (!textRange) return false;
|
|
7397
|
+
if (!core.insertNode(tabText, null, true)) return false;
|
|
7363
7398
|
if (!fc) {
|
|
7364
7399
|
r.sc = tabText;
|
|
7365
|
-
r.so =
|
|
7400
|
+
r.so = tabText.length;
|
|
7366
7401
|
}
|
|
7367
7402
|
if (!lc) {
|
|
7368
7403
|
r.ec = tabText;
|
|
7369
|
-
r.eo =
|
|
7404
|
+
r.eo = tabText.length;
|
|
7370
7405
|
}
|
|
7371
7406
|
} else {
|
|
7372
7407
|
const len = lines.length - 1;
|
|
@@ -7596,7 +7631,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7596
7631
|
const isMultiLine = util.getFormatElement(range.startContainer, null) !== util.getFormatElement(range.endContainer, null);
|
|
7597
7632
|
const newFormat = formatEl.cloneNode(false);
|
|
7598
7633
|
newFormat.innerHTML = '<br>';
|
|
7599
|
-
const
|
|
7634
|
+
const commonCon = range.commonAncestorContainer;
|
|
7635
|
+
const r = commonCon === range.startContainer && commonCon === range.endContainer && util.onlyZeroWidthSpace(commonCon) ? range : core.removeNode();
|
|
7600
7636
|
newEl = util.getFormatElement(r.container, null);
|
|
7601
7637
|
if (!newEl) {
|
|
7602
7638
|
if (util.isWysiwygDiv(r.container)) {
|
|
@@ -7711,8 +7747,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7711
7747
|
e.preventDefault();
|
|
7712
7748
|
e.stopPropagation();
|
|
7713
7749
|
const nbsp = core.insertNode(util.createTextNode('\u00a0'));
|
|
7714
|
-
if (nbsp
|
|
7715
|
-
core.setRange(nbsp
|
|
7750
|
+
if (nbsp) {
|
|
7751
|
+
core.setRange(nbsp, nbsp.length, nbsp, nbsp.length);
|
|
7716
7752
|
return;
|
|
7717
7753
|
}
|
|
7718
7754
|
}
|
|
@@ -7724,7 +7760,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7724
7760
|
}
|
|
7725
7761
|
|
|
7726
7762
|
if (event._directionKeyCode.test(keyCode)) {
|
|
7727
|
-
core._editorRange();
|
|
7763
|
+
_w.setTimeout(core._editorRange.bind(core), 0);
|
|
7728
7764
|
event._applyTagEffects();
|
|
7729
7765
|
}
|
|
7730
7766
|
},
|
|
@@ -7734,7 +7770,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7734
7770
|
|
|
7735
7771
|
let selectionNode = core.getSelectionNode();
|
|
7736
7772
|
|
|
7737
|
-
const selectNode = function (node, offset
|
|
7773
|
+
const selectNode = function (node, offset) {
|
|
7774
|
+
if (!offset) offset = 0;
|
|
7738
7775
|
e.preventDefault();
|
|
7739
7776
|
e.stopPropagation();
|
|
7740
7777
|
|
|
@@ -7757,12 +7794,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7757
7794
|
let currentCellFirstNode = currentCell;
|
|
7758
7795
|
let currentCellLastNode = currentCell;
|
|
7759
7796
|
if (currentCell) {
|
|
7760
|
-
while (currentCellFirstNode.firstChild) currentCellFirstNode = currentCellFirstNode.firstChild;
|
|
7761
|
-
while (currentCellLastNode.lastChild) currentCellLastNode = currentCellLastNode.lastChild;
|
|
7797
|
+
while (currentCellFirstNode && currentCellFirstNode.firstChild) currentCellFirstNode = currentCellFirstNode.firstChild;
|
|
7798
|
+
while (currentCellLastNode && currentCellLastNode.lastChild) currentCellLastNode = currentCellLastNode.lastChild;
|
|
7762
7799
|
}
|
|
7763
7800
|
|
|
7764
7801
|
let selectionNodeDeepestFirstChild = selectionNode;
|
|
7765
|
-
while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
7802
|
+
while (selectionNodeDeepestFirstChild && selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
7766
7803
|
const isCellFirstNode = (selectionNodeDeepestFirstChild === currentCellFirstNode);
|
|
7767
7804
|
const isCellLastNode = (selectionNodeDeepestFirstChild === currentCellLastNode);
|
|
7768
7805
|
|
|
@@ -7773,14 +7810,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7773
7810
|
if (previousRow) siblingToSet = previousRow.children[currentCell.cellIndex];
|
|
7774
7811
|
else siblingToSet = util.getPreviousDeepestNode(table, core.context.element.wysiwyg);
|
|
7775
7812
|
|
|
7776
|
-
while (siblingToSet.lastChild) siblingToSet = siblingToSet.lastChild;
|
|
7813
|
+
while (siblingToSet && siblingToSet.lastChild) siblingToSet = siblingToSet.lastChild;
|
|
7777
7814
|
if (siblingToSet) offset = siblingToSet.textContent.length;
|
|
7778
7815
|
} else if (e.keyCode === 40 && isCellLastNode) { // DOWN
|
|
7779
7816
|
const nextRow = currentRow && currentRow.nextElementSibling;
|
|
7780
7817
|
if (nextRow) siblingToSet = nextRow.children[currentCell.cellIndex];
|
|
7781
7818
|
else siblingToSet = util.getNextDeepestNode(table, core.context.element.wysiwyg);
|
|
7782
7819
|
|
|
7783
|
-
while (siblingToSet.firstChild) siblingToSet = siblingToSet.firstChild;
|
|
7820
|
+
while (siblingToSet && siblingToSet.firstChild) siblingToSet = siblingToSet.firstChild;
|
|
7784
7821
|
}
|
|
7785
7822
|
|
|
7786
7823
|
if (siblingToSet) {
|
|
@@ -7831,7 +7868,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7831
7868
|
}
|
|
7832
7869
|
|
|
7833
7870
|
let selectionNodeDeepestFirstChild = selectionNode;
|
|
7834
|
-
while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
7871
|
+
while (selectionNodeDeepestFirstChild && selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
7835
7872
|
|
|
7836
7873
|
const selectedComponentInfo = core.getFileComponent(selectionNodeDeepestFirstChild);
|
|
7837
7874
|
if (!(e.keyCode === 16 || e.shiftKey) && selectedComponentInfo) core.selectComponent(selectedComponentInfo.target, selectedComponentInfo.pluginName);
|
|
@@ -8353,7 +8390,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
8353
8390
|
}
|
|
8354
8391
|
},
|
|
8355
8392
|
|
|
8356
|
-
_enterPrevent(e) {
|
|
8393
|
+
_enterPrevent: function (e) {
|
|
8357
8394
|
e.preventDefault();
|
|
8358
8395
|
if (!util.isMobile) return;
|
|
8359
8396
|
|
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',
|
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,
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* wysiwyg web editor
|
|
3
|
-
*
|
|
4
|
-
* suneditor.js
|
|
5
|
-
* Copyright 2017 JiHong Lee.
|
|
6
|
-
* MIT license.
|
|
7
|
-
*/
|
|
8
|
-
"use strict";
|
|
9
|
-
|
|
10
|
-
import dialog from "../modules/dialog";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
function insertAt(parent, child, index) {
|
|
14
|
-
if (!index) index = 0;
|
|
15
|
-
if (index >= parent.children.length) {
|
|
16
|
-
parent.appendChild(child);
|
|
17
|
-
} else {
|
|
18
|
-
parent.insertBefore(child, parent.children[index]);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default {
|
|
23
|
-
name: "mention",
|
|
24
|
-
display: "dialog",
|
|
25
|
-
|
|
26
|
-
renderItem: function(item) {
|
|
27
|
-
return `<span>${item}</span>`;
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
getItems: function(term) {
|
|
31
|
-
return Promise.resolve(
|
|
32
|
-
["overwite", "the", "mention", "plugin", "getItems", "method"].filter(
|
|
33
|
-
(w) => w.includes(term.toLowerCase())
|
|
34
|
-
)
|
|
35
|
-
);
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
renderList: function(term) {
|
|
39
|
-
const { mention } = this.context;
|
|
40
|
-
let promise = Promise.resolve();
|
|
41
|
-
if (mention.term !== term) {
|
|
42
|
-
mention.focussed = 0;
|
|
43
|
-
mention.term = term;
|
|
44
|
-
promise = mention.getItems(term).then((items) => {
|
|
45
|
-
mention._items = items;
|
|
46
|
-
|
|
47
|
-
Object.keys(mention._itemElements).forEach((id) => {
|
|
48
|
-
if (!items.find((i) => mention.getId(i) === id)) {
|
|
49
|
-
const child = mention._itemElements[id];
|
|
50
|
-
child.parentNode.removeChild(child);
|
|
51
|
-
delete mention._itemElements[id];
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
items.forEach((item, idx) => {
|
|
56
|
-
const id = mention.getId(item);
|
|
57
|
-
if (!mention._itemElements[id]) {
|
|
58
|
-
const el = this.util.createElement("LI");
|
|
59
|
-
el.setAttribute("data-mention", id);
|
|
60
|
-
this.util.addClass(el, 'se-mention-item');
|
|
61
|
-
el.innerHTML = mention.renderItem(item);
|
|
62
|
-
el.addEventListener("click", () => {
|
|
63
|
-
mention._addMention(item);
|
|
64
|
-
});
|
|
65
|
-
insertAt(mention._list, el, idx);
|
|
66
|
-
mention._itemElements[id] = el;
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
promise.then(() => {
|
|
73
|
-
const current = mention._list.querySelectorAll(".se-mention-item")[
|
|
74
|
-
mention.focussed
|
|
75
|
-
];
|
|
76
|
-
if (current && !this.util.hasClass(current, "se-mention-active")) {
|
|
77
|
-
const prev = mention._list.querySelector(".se-mention-active");
|
|
78
|
-
if (prev) this.util.removeClass(prev, "se-mention-active");
|
|
79
|
-
this.util.addClass(current, "se-mention-active");
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
},
|
|
83
|
-
|
|
84
|
-
setDialog: function(core) {
|
|
85
|
-
const mention_dialog = core.util.createElement("DIV");
|
|
86
|
-
const lang = core.lang;
|
|
87
|
-
mention_dialog.className = "se-dialog-content";
|
|
88
|
-
mention_dialog.style.display = "none";
|
|
89
|
-
const html = `
|
|
90
|
-
<form class="se-dialog-form">
|
|
91
|
-
<div class="se-dialog-header">
|
|
92
|
-
<button type="button" data-command="close" class="se-btn se-dialog-close" title="${lang.dialogBox.close}" aria-label="${lang.dialogBox.close}">
|
|
93
|
-
${core.icons.cancel}
|
|
94
|
-
</button>
|
|
95
|
-
<span class="se-modal-title">${lang.dialogBox.mentionBox.title}</span>
|
|
96
|
-
</div>
|
|
97
|
-
<div class="se-dialog-body">
|
|
98
|
-
<input class="se-input-form se-mention-search" type="text" placeholder="${lang.dialogBox.browser.search}" />
|
|
99
|
-
<ul class="se-mention-list">
|
|
100
|
-
</ul>
|
|
101
|
-
</div>
|
|
102
|
-
</form>
|
|
103
|
-
`;
|
|
104
|
-
mention_dialog.innerHTML = html;
|
|
105
|
-
return mention_dialog;
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
getId(mention) {
|
|
109
|
-
return mention;
|
|
110
|
-
},
|
|
111
|
-
|
|
112
|
-
getValue(mention) {
|
|
113
|
-
return `@${mention}`;
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
getLinkHref(/*mention*/) {
|
|
117
|
-
return "";
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
open: function() {
|
|
121
|
-
const { mention } = this.context;
|
|
122
|
-
this.plugins.dialog.open.call(
|
|
123
|
-
this,
|
|
124
|
-
"mention",
|
|
125
|
-
"mention" === this.currentControllerName
|
|
126
|
-
);
|
|
127
|
-
mention._search.focus();
|
|
128
|
-
mention.renderList("");
|
|
129
|
-
},
|
|
130
|
-
|
|
131
|
-
on: function(update) {
|
|
132
|
-
if (update) return;
|
|
133
|
-
this.plugins.mention.init.call(this);
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
init: function() {
|
|
137
|
-
const { mention } = this.context;
|
|
138
|
-
mention._search.value = "";
|
|
139
|
-
mention.focussed = 0;
|
|
140
|
-
mention._items = [];
|
|
141
|
-
mention._itemElements = {};
|
|
142
|
-
mention._list.innerHTML = "";
|
|
143
|
-
delete mention.term;
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
onKeyPress: function(e) {
|
|
147
|
-
const { mention } = this.context;
|
|
148
|
-
switch (e.key) {
|
|
149
|
-
case "ArrowDown":
|
|
150
|
-
mention.focussed += 1;
|
|
151
|
-
e.preventDefault();
|
|
152
|
-
e.stopPropagation();
|
|
153
|
-
break;
|
|
154
|
-
|
|
155
|
-
case "ArrowUp":
|
|
156
|
-
if (mention.focussed > 0) {
|
|
157
|
-
mention.focussed -= 1;
|
|
158
|
-
}
|
|
159
|
-
e.preventDefault();
|
|
160
|
-
e.stopPropagation();
|
|
161
|
-
break;
|
|
162
|
-
|
|
163
|
-
case "Enter":
|
|
164
|
-
mention._addMention();
|
|
165
|
-
e.preventDefault();
|
|
166
|
-
e.stopPropagation();
|
|
167
|
-
break;
|
|
168
|
-
|
|
169
|
-
default:
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
|
|
173
|
-
onKeyUp: function(e) {
|
|
174
|
-
const { mention } = this.context;
|
|
175
|
-
mention.renderList(e.target.value);
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
getMentions: function(core) {
|
|
179
|
-
const { mentions, getId } = core.context.mention;
|
|
180
|
-
return mentions.filter((mention) => {
|
|
181
|
-
const id = getId(mention);
|
|
182
|
-
return core.context.element.wysiwyg.querySelector(
|
|
183
|
-
`[data-mention="${id}"]`
|
|
184
|
-
);
|
|
185
|
-
});
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
_addMention: function(item) {
|
|
189
|
-
const { mention } = this.context;
|
|
190
|
-
const new_mention = item || mention._items[mention.focussed];
|
|
191
|
-
if (new_mention) {
|
|
192
|
-
if (
|
|
193
|
-
!mention.mentions.find(
|
|
194
|
-
(m) => mention.getId(m) === mention.getId(new_mention)
|
|
195
|
-
)
|
|
196
|
-
) {
|
|
197
|
-
mention.mentions.push(new_mention);
|
|
198
|
-
}
|
|
199
|
-
const el = this.util.createElement("A");
|
|
200
|
-
el.href = mention.getLinkHref(new_mention);
|
|
201
|
-
el.target = "_blank";
|
|
202
|
-
el.innerHTML = mention.getValue(new_mention);
|
|
203
|
-
el.setAttribute("data-mention", mention.getId(new_mention));
|
|
204
|
-
this.insertNode(el, null, false);
|
|
205
|
-
const spacer = this.util.createElement("SPAN");
|
|
206
|
-
spacer.innerHTML = " ";
|
|
207
|
-
this.insertNode(spacer, el, false);
|
|
208
|
-
}
|
|
209
|
-
this.plugins.dialog.close.call(this);
|
|
210
|
-
},
|
|
211
|
-
add: function(core) {
|
|
212
|
-
core.addModule([dialog]);
|
|
213
|
-
this.title = core.lang.toolbar.mention;
|
|
214
|
-
const _dialog = this.setDialog(core);
|
|
215
|
-
core.getMentions = this.getMentions(core);
|
|
216
|
-
|
|
217
|
-
const _search = _dialog.querySelector(".se-mention-search");
|
|
218
|
-
_search.addEventListener("keyup", this.onKeyUp.bind(core));
|
|
219
|
-
_search.addEventListener("keydown", this.onKeyPress.bind(core));
|
|
220
|
-
const _list = _dialog.querySelector(".se-mention-list");
|
|
221
|
-
|
|
222
|
-
core.context.mention = {
|
|
223
|
-
_addMention: this._addMention.bind(core),
|
|
224
|
-
_itemElements: {},
|
|
225
|
-
_items: [],
|
|
226
|
-
_list,
|
|
227
|
-
_search,
|
|
228
|
-
focussed: 0,
|
|
229
|
-
getId: this.getId.bind(core),
|
|
230
|
-
getItems: this.getItems,
|
|
231
|
-
getLinkHref: this.getLinkHref.bind(core),
|
|
232
|
-
getValue: this.getValue.bind(core),
|
|
233
|
-
mentions: [],
|
|
234
|
-
modal: _dialog,
|
|
235
|
-
open: this.open.bind(core),
|
|
236
|
-
renderItem: this.renderItem,
|
|
237
|
-
renderList: this.renderList.bind(core),
|
|
238
|
-
};
|
|
239
|
-
core.context.dialog.modal.appendChild(_dialog);
|
|
240
|
-
},
|
|
241
|
-
action: function() {},
|
|
242
|
-
};
|