suneditor 2.46.3 → 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 +22 -0
- package/README_V3_TEMP.md +630 -0
- package/dist/css/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +2 -2
- package/package.json +1 -1
- package/src/assets/css/suneditor.css +2 -2
- package/src/lib/constructor.js +4 -1
- package/src/lib/core.d.ts +1 -0
- package/src/lib/core.js +91 -64
- 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/dialog/math.js +5 -0
- package/src/plugins/dialog/video.js +10 -0
- 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
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
.sun-editor .se-toolbar .se-arrow.se-arrow-down::after {border-top-color:#fafafa;}
|
|
98
98
|
|
|
99
99
|
/** --- container */
|
|
100
|
-
.sun-editor .se-container {position:relative; width:
|
|
100
|
+
.sun-editor .se-container {position:relative; width:auto; height:auto;}
|
|
101
101
|
|
|
102
102
|
/** button */
|
|
103
103
|
.sun-editor button {color:#000;}
|
|
@@ -563,4 +563,4 @@
|
|
|
563
563
|
|
|
564
564
|
/** animation */
|
|
565
565
|
@keyframes blinker { 50% {opacity:0;} }
|
|
566
|
-
@keyframes spinner { to {transform:rotate(361deg);} }
|
|
566
|
+
@keyframes spinner { to {transform:rotate(361deg);} }
|
package/src/lib/constructor.js
CHANGED
|
@@ -87,7 +87,7 @@ export default {
|
|
|
87
87
|
/// focus temp
|
|
88
88
|
const focusTemp = doc.createElement('INPUT');
|
|
89
89
|
focusTemp.tabIndex = -1;
|
|
90
|
-
focusTemp.style.cssText = 'position:
|
|
90
|
+
focusTemp.style.cssText = 'position: fixed !important; top: -10000px !important; display: block !important; width: 0 !important; height: 0 !important; margin: 0 !important; padding: 0 !important;';
|
|
91
91
|
|
|
92
92
|
// toolbar container
|
|
93
93
|
const toolbarContainer = options.toolbarContainer;
|
|
@@ -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 */
|
|
@@ -557,6 +559,7 @@ export default {
|
|
|
557
559
|
options.videoRatio = (util.getNumber(options.videoRatio, 4) || 0.5625);
|
|
558
560
|
options.videoRatioList = !options.videoRatioList ? null : options.videoRatioList;
|
|
559
561
|
options.youtubeQuery = (options.youtubeQuery || '').replace('?', '');
|
|
562
|
+
options.vimeoQuery = (options.vimeoQuery || '').replace('?', '');
|
|
560
563
|
options.videoFileInput = !!options.videoFileInput;
|
|
561
564
|
options.videoUrlInput = (options.videoUrlInput === undefined || !options.videoFileInput) ? true : options.videoUrlInput;
|
|
562
565
|
options.videoUploadHeader = options.videoUploadHeader || null;
|
package/src/lib/core.d.ts
CHANGED
|
@@ -693,6 +693,7 @@ export default class SunEditor {
|
|
|
693
693
|
onPaste: (e: Event, cleanData: string, maxCharCount: number, core: Core) => boolean | string;
|
|
694
694
|
onCopy: (e: Event, clipboardData: any, core: Core) => boolean;
|
|
695
695
|
onCut: (e: Event, clipboardData: any, core: Core) => boolean;
|
|
696
|
+
onPasteMath: (e: Event, core: Core) => void;
|
|
696
697
|
|
|
697
698
|
/**
|
|
698
699
|
* @description Called just after the save was executed.
|
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));
|
|
@@ -1756,6 +1758,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
1756
1758
|
return null;
|
|
1757
1759
|
}
|
|
1758
1760
|
|
|
1761
|
+
let fNode = null;
|
|
1759
1762
|
let range = this.getRange();
|
|
1760
1763
|
let line = util.isListCell(range.commonAncestorContainer) ? range.commonAncestorContainer : util.getFormatElement(this.getSelectionNode(), null);
|
|
1761
1764
|
let insertListCell = util.isListCell(line) && (util.isListCell(oNode) || util.isList(oNode));
|
|
@@ -1958,9 +1961,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
1958
1961
|
}
|
|
1959
1962
|
|
|
1960
1963
|
if (util.isWysiwygDiv(parentNode) && (oNode.nodeType === 3 || util.isBreak(oNode))) {
|
|
1961
|
-
const
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
+
const fomatNode = util.createElement(options.defaultTag);
|
|
1965
|
+
fomatNode.appendChild(oNode);
|
|
1966
|
+
fNode = oNode;
|
|
1967
|
+
oNode = fomatNode;
|
|
1964
1968
|
}
|
|
1965
1969
|
}
|
|
1966
1970
|
|
|
@@ -2018,6 +2022,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
2018
2022
|
parentNode.appendChild(oNode);
|
|
2019
2023
|
console.warn('[SUNEDITOR.insertNode.warn] ' + error);
|
|
2020
2024
|
} finally {
|
|
2025
|
+
if (fNode) oNode = fNode;
|
|
2026
|
+
|
|
2021
2027
|
const dupleNodes = parentNode.querySelectorAll('[data-se-duple]');
|
|
2022
2028
|
if (dupleNodes.length > 0) {
|
|
2023
2029
|
for (let i = 0, len = dupleNodes.length, d, c, ch, parent; i < len; i++) {
|
|
@@ -2049,30 +2055,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
2049
2055
|
if (!util.isComponent(oNode)) {
|
|
2050
2056
|
let offset = 1;
|
|
2051
2057
|
if (oNode.nodeType === 3) {
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
const previousText = (!previous || previous.nodeType === 1 || util.onlyZeroWidthSpace(previous)) ? '' : previous.textContent;
|
|
2055
|
-
const nextText = (!next || next.nodeType === 1 || util.onlyZeroWidthSpace(next)) ? '' : next.textContent;
|
|
2056
|
-
|
|
2057
|
-
if (previous && previousText.length > 0) {
|
|
2058
|
-
oNode.textContent = previousText + oNode.textContent;
|
|
2059
|
-
util.removeItem(previous);
|
|
2060
|
-
}
|
|
2061
|
-
|
|
2062
|
-
if (next && next.length > 0) {
|
|
2063
|
-
oNode.textContent += nextText;
|
|
2064
|
-
util.removeItem(next);
|
|
2065
|
-
}
|
|
2066
|
-
|
|
2067
|
-
const newRange = {
|
|
2068
|
-
container: oNode,
|
|
2069
|
-
startOffset: previousText.length,
|
|
2070
|
-
endOffset: oNode.textContent.length - nextText.length
|
|
2071
|
-
};
|
|
2072
|
-
|
|
2073
|
-
this.setRange(oNode, newRange.startOffset, oNode, newRange.endOffset);
|
|
2074
|
-
|
|
2075
|
-
return newRange;
|
|
2058
|
+
offset = oNode.textContent.length;
|
|
2059
|
+
this.setRange(oNode, offset, oNode, offset);
|
|
2076
2060
|
} else if (!util.isBreak(oNode) && !util.isListCell(oNode) && util.isFormatElement(parentNode)) {
|
|
2077
2061
|
let zeroWidth = null;
|
|
2078
2062
|
if (!oNode.previousSibling || util.isBreak(oNode.previousSibling)) {
|
|
@@ -2094,9 +2078,6 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
2094
2078
|
this.setRange(oNode, offset, oNode, offset);
|
|
2095
2079
|
}
|
|
2096
2080
|
|
|
2097
|
-
// history stack
|
|
2098
|
-
this.history.push(true);
|
|
2099
|
-
|
|
2100
2081
|
return oNode;
|
|
2101
2082
|
}
|
|
2102
2083
|
},
|
|
@@ -5320,7 +5301,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5320
5301
|
r = style[i].match(/([a-zA-Z0-9-]+)(:)([^"']+)/);
|
|
5321
5302
|
if (r && !/inherit|initial|revert|unset/i.test(r[3])) {
|
|
5322
5303
|
const k = util.kebabToCamelCase(r[1].trim());
|
|
5323
|
-
const v = this.wwComputedStyle[k].replace(/"/g, '');
|
|
5304
|
+
const v = this.wwComputedStyle[k] ? this.wwComputedStyle[k].replace(/"/g, '') : '';
|
|
5324
5305
|
const c = r[3].trim();
|
|
5325
5306
|
switch (k) {
|
|
5326
5307
|
case 'fontFamily':
|
|
@@ -5562,7 +5543,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5562
5543
|
const dom = _d.createRange().createContextualFragment(contents);
|
|
5563
5544
|
|
|
5564
5545
|
try {
|
|
5565
|
-
|
|
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
|
+
}
|
|
5566
5551
|
} catch (error) {
|
|
5567
5552
|
console.warn('[SUNEDITOR.convertContentsForEditor.consistencyCheck.fail] ' + error);
|
|
5568
5553
|
}
|
|
@@ -5943,7 +5928,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5943
5928
|
// set whitelist
|
|
5944
5929
|
const getRegList = function (str, str2) { return !str ? '^' : (str === '*' ? '[a-z-]+' : (!str2 ? str : (str + '|' + str2))); };
|
|
5945
5930
|
// tags
|
|
5946
|
-
const
|
|
5931
|
+
const videoAttr = '|controls|autoplay|loop|muted|poster|preload|playsinline';
|
|
5932
|
+
const iframeAttr = '|allowfullscreen|sandbox|loading|allow|referrerpolicy|frameborder|scrolling';
|
|
5933
|
+
const defaultAttr = 'contenteditable|colspan|rowspan|target|href|download|rel|src|alt|class|type|origin-size' + videoAttr + iframeAttr;
|
|
5947
5934
|
const dataAttr = 'data-format|data-size|data-file-size|data-file-name|data-origin|data-align|data-image-link|data-rotate|data-proportion|data-percentage|data-exp|data-font-size';
|
|
5948
5935
|
this._allowHTMLComments = options._editorTagsWhitelist.indexOf('//') > -1 || options._editorTagsWhitelist === '*';
|
|
5949
5936
|
// html check
|
|
@@ -6254,6 +6241,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6254
6241
|
this.execCommand('formatBlock', false, (formatName || options.defaultTag));
|
|
6255
6242
|
this.removeRange();
|
|
6256
6243
|
this._editorRange();
|
|
6244
|
+
this.effectNode = null;
|
|
6245
|
+
return;
|
|
6257
6246
|
}
|
|
6258
6247
|
|
|
6259
6248
|
if (format) {
|
|
@@ -6267,7 +6256,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6267
6256
|
}
|
|
6268
6257
|
|
|
6269
6258
|
this.effectNode = null;
|
|
6270
|
-
|
|
6259
|
+
|
|
6260
|
+
if (startCon) {
|
|
6261
|
+
this.setRange(startCon, 1, startCon, 1);
|
|
6262
|
+
} else {
|
|
6263
|
+
this.nativeFocus();
|
|
6264
|
+
}
|
|
6271
6265
|
},
|
|
6272
6266
|
|
|
6273
6267
|
/**
|
|
@@ -6445,6 +6439,10 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6445
6439
|
},
|
|
6446
6440
|
|
|
6447
6441
|
_applyTagEffects: function () {
|
|
6442
|
+
if (util.hasClass(context.element.wysiwyg, 'se-read-only')) {
|
|
6443
|
+
return false;
|
|
6444
|
+
}
|
|
6445
|
+
|
|
6448
6446
|
let selectionNode = core.getSelectionNode();
|
|
6449
6447
|
if (selectionNode === core.effectNode) return;
|
|
6450
6448
|
core.effectNode = selectionNode;
|
|
@@ -6547,7 +6545,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6547
6545
|
}
|
|
6548
6546
|
},
|
|
6549
6547
|
|
|
6550
|
-
addGlobalEvent(type, listener, useCapture) {
|
|
6548
|
+
addGlobalEvent: function (type, listener, useCapture) {
|
|
6551
6549
|
if (options.iframe) {
|
|
6552
6550
|
core._ww.addEventListener(type, listener, useCapture);
|
|
6553
6551
|
}
|
|
@@ -6559,7 +6557,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6559
6557
|
};
|
|
6560
6558
|
},
|
|
6561
6559
|
|
|
6562
|
-
removeGlobalEvent(type, listener, useCapture) {
|
|
6560
|
+
removeGlobalEvent: function (type, listener, useCapture) {
|
|
6563
6561
|
if (!type) return;
|
|
6564
6562
|
|
|
6565
6563
|
if (typeof type === 'object') {
|
|
@@ -6603,7 +6601,9 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6603
6601
|
|
|
6604
6602
|
event.removeGlobalEvent(event.__selectionSyncEvent);
|
|
6605
6603
|
event.__selectionSyncEvent = event.addGlobalEvent('mouseup', function() {
|
|
6606
|
-
core
|
|
6604
|
+
if (core) {
|
|
6605
|
+
core._editorRange();
|
|
6606
|
+
}
|
|
6607
6607
|
event.removeGlobalEvent(event.__selectionSyncEvent);
|
|
6608
6608
|
});
|
|
6609
6609
|
|
|
@@ -6626,6 +6626,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6626
6626
|
},
|
|
6627
6627
|
|
|
6628
6628
|
onClick_wysiwyg: function (e) {
|
|
6629
|
+
// if (util.hasClass(context.element.wysiwyg, 'se-read-only')) {
|
|
6630
|
+
// e.preventDefault();
|
|
6631
|
+
// return false;
|
|
6632
|
+
// }
|
|
6633
|
+
|
|
6629
6634
|
const targetElement = e.target;
|
|
6630
6635
|
|
|
6631
6636
|
if (core.isReadOnly) {
|
|
@@ -6680,7 +6685,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6680
6685
|
const rangeEl = util.getRangeFormatElement(selectionNode, null);
|
|
6681
6686
|
|
|
6682
6687
|
let selectionNodeDeepestFirstChild = selectionNode;
|
|
6683
|
-
while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
6688
|
+
while (selectionNodeDeepestFirstChild && selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
6684
6689
|
|
|
6685
6690
|
const selectedComponentInfo = core.getFileComponent(selectionNodeDeepestFirstChild);
|
|
6686
6691
|
if (selectedComponentInfo) {
|
|
@@ -6726,10 +6731,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6726
6731
|
},
|
|
6727
6732
|
|
|
6728
6733
|
_toggleToolbarBalloon: function () {
|
|
6729
|
-
core
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
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
|
+
}
|
|
6733
6740
|
},
|
|
6734
6741
|
|
|
6735
6742
|
_showToolbarBalloon: function (rangeObj) {
|
|
@@ -6906,6 +6913,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6906
6913
|
return false;
|
|
6907
6914
|
}
|
|
6908
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
|
+
|
|
6909
6924
|
core._editorRange();
|
|
6910
6925
|
|
|
6911
6926
|
const data = (e.data === null ? '' : e.data === undefined ? ' ' : e.data) || '';
|
|
@@ -6934,7 +6949,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6934
6949
|
return siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false';
|
|
6935
6950
|
} else {
|
|
6936
6951
|
siblingNode = event._isUneditableNode_getSibling(container, siblingKey, container);
|
|
6937
|
-
return core.isEdgePoint(container, offset, isFront ? '
|
|
6952
|
+
return core.isEdgePoint(container, offset, isFront ? 'start' : 'end') && (siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false');
|
|
6938
6953
|
}
|
|
6939
6954
|
},
|
|
6940
6955
|
|
|
@@ -6988,6 +7003,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
6988
7003
|
}
|
|
6989
7004
|
|
|
6990
7005
|
/** default key action */
|
|
7006
|
+
if (keyCode === 13 && util.isFormatElement(core.getRange().startContainer)) {
|
|
7007
|
+
core._resetRangeToTextNode();
|
|
7008
|
+
selectionNode = core.getSelectionNode();
|
|
7009
|
+
}
|
|
7010
|
+
|
|
6991
7011
|
const range = core.getRange();
|
|
6992
7012
|
const selectRange = !range.collapsed || range.startContainer !== range.endContainer;
|
|
6993
7013
|
const fileComponentName = core._fileManager.pluginRegExp.test(core.currentControllerName) ? core.currentControllerName : '';
|
|
@@ -7214,6 +7234,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7214
7234
|
break;
|
|
7215
7235
|
}
|
|
7216
7236
|
|
|
7237
|
+
if (!selectRange && core._isEdgeFormat(range.endContainer, range.endOffset, 'end') && !formatEl.nextSibling) {
|
|
7238
|
+
e.preventDefault();
|
|
7239
|
+
e.stopPropagation();
|
|
7240
|
+
return;
|
|
7241
|
+
}
|
|
7242
|
+
|
|
7217
7243
|
// tag[contenteditable="false"]
|
|
7218
7244
|
if (event._isUneditableNode(range, false)) {
|
|
7219
7245
|
e.preventDefault();
|
|
@@ -7368,15 +7394,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7368
7394
|
if (!shift) {
|
|
7369
7395
|
const tabText = util.createTextNode(new _w.Array(core._variable.tabSize + 1).join('\u00A0'));
|
|
7370
7396
|
if (lines.length === 1) {
|
|
7371
|
-
|
|
7372
|
-
if (!textRange) return false;
|
|
7397
|
+
if (!core.insertNode(tabText, null, true)) return false;
|
|
7373
7398
|
if (!fc) {
|
|
7374
7399
|
r.sc = tabText;
|
|
7375
|
-
r.so =
|
|
7400
|
+
r.so = tabText.length;
|
|
7376
7401
|
}
|
|
7377
7402
|
if (!lc) {
|
|
7378
7403
|
r.ec = tabText;
|
|
7379
|
-
r.eo =
|
|
7404
|
+
r.eo = tabText.length;
|
|
7380
7405
|
}
|
|
7381
7406
|
} else {
|
|
7382
7407
|
const len = lines.length - 1;
|
|
@@ -7606,7 +7631,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7606
7631
|
const isMultiLine = util.getFormatElement(range.startContainer, null) !== util.getFormatElement(range.endContainer, null);
|
|
7607
7632
|
const newFormat = formatEl.cloneNode(false);
|
|
7608
7633
|
newFormat.innerHTML = '<br>';
|
|
7609
|
-
const
|
|
7634
|
+
const commonCon = range.commonAncestorContainer;
|
|
7635
|
+
const r = commonCon === range.startContainer && commonCon === range.endContainer && util.onlyZeroWidthSpace(commonCon) ? range : core.removeNode();
|
|
7610
7636
|
newEl = util.getFormatElement(r.container, null);
|
|
7611
7637
|
if (!newEl) {
|
|
7612
7638
|
if (util.isWysiwygDiv(r.container)) {
|
|
@@ -7721,8 +7747,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7721
7747
|
e.preventDefault();
|
|
7722
7748
|
e.stopPropagation();
|
|
7723
7749
|
const nbsp = core.insertNode(util.createTextNode('\u00a0'));
|
|
7724
|
-
if (nbsp
|
|
7725
|
-
core.setRange(nbsp
|
|
7750
|
+
if (nbsp) {
|
|
7751
|
+
core.setRange(nbsp, nbsp.length, nbsp, nbsp.length);
|
|
7726
7752
|
return;
|
|
7727
7753
|
}
|
|
7728
7754
|
}
|
|
@@ -7734,7 +7760,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7734
7760
|
}
|
|
7735
7761
|
|
|
7736
7762
|
if (event._directionKeyCode.test(keyCode)) {
|
|
7737
|
-
core._editorRange();
|
|
7763
|
+
_w.setTimeout(core._editorRange.bind(core), 0);
|
|
7738
7764
|
event._applyTagEffects();
|
|
7739
7765
|
}
|
|
7740
7766
|
},
|
|
@@ -7744,7 +7770,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7744
7770
|
|
|
7745
7771
|
let selectionNode = core.getSelectionNode();
|
|
7746
7772
|
|
|
7747
|
-
const selectNode = function (node, offset
|
|
7773
|
+
const selectNode = function (node, offset) {
|
|
7774
|
+
if (!offset) offset = 0;
|
|
7748
7775
|
e.preventDefault();
|
|
7749
7776
|
e.stopPropagation();
|
|
7750
7777
|
|
|
@@ -7767,12 +7794,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7767
7794
|
let currentCellFirstNode = currentCell;
|
|
7768
7795
|
let currentCellLastNode = currentCell;
|
|
7769
7796
|
if (currentCell) {
|
|
7770
|
-
while (currentCellFirstNode.firstChild) currentCellFirstNode = currentCellFirstNode.firstChild;
|
|
7771
|
-
while (currentCellLastNode.lastChild) currentCellLastNode = currentCellLastNode.lastChild;
|
|
7797
|
+
while (currentCellFirstNode && currentCellFirstNode.firstChild) currentCellFirstNode = currentCellFirstNode.firstChild;
|
|
7798
|
+
while (currentCellLastNode && currentCellLastNode.lastChild) currentCellLastNode = currentCellLastNode.lastChild;
|
|
7772
7799
|
}
|
|
7773
7800
|
|
|
7774
7801
|
let selectionNodeDeepestFirstChild = selectionNode;
|
|
7775
|
-
while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
7802
|
+
while (selectionNodeDeepestFirstChild && selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
7776
7803
|
const isCellFirstNode = (selectionNodeDeepestFirstChild === currentCellFirstNode);
|
|
7777
7804
|
const isCellLastNode = (selectionNodeDeepestFirstChild === currentCellLastNode);
|
|
7778
7805
|
|
|
@@ -7783,14 +7810,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7783
7810
|
if (previousRow) siblingToSet = previousRow.children[currentCell.cellIndex];
|
|
7784
7811
|
else siblingToSet = util.getPreviousDeepestNode(table, core.context.element.wysiwyg);
|
|
7785
7812
|
|
|
7786
|
-
while (siblingToSet.lastChild) siblingToSet = siblingToSet.lastChild;
|
|
7813
|
+
while (siblingToSet && siblingToSet.lastChild) siblingToSet = siblingToSet.lastChild;
|
|
7787
7814
|
if (siblingToSet) offset = siblingToSet.textContent.length;
|
|
7788
7815
|
} else if (e.keyCode === 40 && isCellLastNode) { // DOWN
|
|
7789
7816
|
const nextRow = currentRow && currentRow.nextElementSibling;
|
|
7790
7817
|
if (nextRow) siblingToSet = nextRow.children[currentCell.cellIndex];
|
|
7791
7818
|
else siblingToSet = util.getNextDeepestNode(table, core.context.element.wysiwyg);
|
|
7792
7819
|
|
|
7793
|
-
while (siblingToSet.firstChild) siblingToSet = siblingToSet.firstChild;
|
|
7820
|
+
while (siblingToSet && siblingToSet.firstChild) siblingToSet = siblingToSet.firstChild;
|
|
7794
7821
|
}
|
|
7795
7822
|
|
|
7796
7823
|
if (siblingToSet) {
|
|
@@ -7841,7 +7868,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7841
7868
|
}
|
|
7842
7869
|
|
|
7843
7870
|
let selectionNodeDeepestFirstChild = selectionNode;
|
|
7844
|
-
while (selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
7871
|
+
while (selectionNodeDeepestFirstChild && selectionNodeDeepestFirstChild.firstChild) selectionNodeDeepestFirstChild = selectionNodeDeepestFirstChild.firstChild;
|
|
7845
7872
|
|
|
7846
7873
|
const selectedComponentInfo = core.getFileComponent(selectionNodeDeepestFirstChild);
|
|
7847
7874
|
if (!(e.keyCode === 16 || e.shiftKey) && selectedComponentInfo) core.selectComponent(selectedComponentInfo.target, selectedComponentInfo.pluginName);
|
|
@@ -8363,7 +8390,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
8363
8390
|
}
|
|
8364
8391
|
},
|
|
8365
8392
|
|
|
8366
|
-
_enterPrevent(e) {
|
|
8393
|
+
_enterPrevent: function (e) {
|
|
8367
8394
|
e.preventDefault();
|
|
8368
8395
|
if (!util.isMobile) return;
|
|
8369
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) {
|
|
@@ -25,6 +25,11 @@ export default {
|
|
|
25
25
|
context.math.focusElement = math_dialog.querySelector('.se-math-exp');
|
|
26
26
|
context.math.previewElement = math_dialog.querySelector('.se-math-preview');
|
|
27
27
|
context.math.fontSizeElement = math_dialog.querySelector('.se-math-size');
|
|
28
|
+
context.math.focusElement.addEventListener('paste', function (e) {
|
|
29
|
+
if (typeof core.functions.onPasteMath === 'function') {
|
|
30
|
+
core.functions.onPasteMath(e, core);
|
|
31
|
+
}
|
|
32
|
+
}, false);
|
|
28
33
|
context.math.focusElement.addEventListener(core.util.isIE ? 'textinput' : 'input', this._renderMathExp.bind(core, context.math), false);
|
|
29
34
|
context.math.fontSizeElement.addEventListener('change', function (e) { this.fontSize = e.target.value; }.bind(context.math.previewElement.style), false);
|
|
30
35
|
|
|
@@ -29,6 +29,7 @@ export default {
|
|
|
29
29
|
_align: 'none',
|
|
30
30
|
_floatClassRegExp: '__se__float\\-[a-z]+',
|
|
31
31
|
_youtubeQuery: options.youtubeQuery,
|
|
32
|
+
_vimeoQuery: options.vimeoQuery,
|
|
32
33
|
_videoRatio: (options.videoRatio * 100) + '%',
|
|
33
34
|
_defaultRatio: (options.videoRatio * 100) + '%',
|
|
34
35
|
_linkValue: '',
|
|
@@ -540,6 +541,15 @@ export default {
|
|
|
540
541
|
url = url.slice(0, -1);
|
|
541
542
|
}
|
|
542
543
|
url = 'https://player.vimeo.com/video/' + url.slice(url.lastIndexOf('/') + 1);
|
|
544
|
+
|
|
545
|
+
if (contextVideo._vimeoQuery.length > 0) {
|
|
546
|
+
if (/\?/.test(url)) {
|
|
547
|
+
const splitUrl = url.split('?');
|
|
548
|
+
url = splitUrl[0] + '?' + contextVideo._vimeoQuery + '&' + splitUrl[1];
|
|
549
|
+
} else {
|
|
550
|
+
url += '?' + contextVideo._vimeoQuery;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
543
553
|
}
|
|
544
554
|
|
|
545
555
|
this.plugins.video.create_video.call(this, this.plugins.video[(!/embed|iframe|player|\/e\/|\.php|\.html?/.test(url) && !/vimeo\.com/.test(url) ? "createVideoTag" : "createIframeTag")].call(this), url, contextVideo.inputX.value, contextVideo.inputY.value, contextVideo._align, null, this.context.dialog.updateModal);
|
|
@@ -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,
|