suneditor 2.43.6 → 2.43.9
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 +1 -0
- package/dist/suneditor.min.js +2 -2
- package/package.json +1 -1
- package/src/lib/constructor.js +16 -11
- package/src/lib/core.js +168 -63
- package/src/lib/util.d.ts +13 -0
- package/src/lib/util.js +44 -1
- package/src/plugins/dialog/audio.js +9 -5
- package/src/plugins/dialog/image.js +9 -5
- package/src/plugins/dialog/video.js +9 -5
- package/src/plugins/submenu/font.js +1 -12
package/package.json
CHANGED
package/src/lib/constructor.js
CHANGED
|
@@ -396,6 +396,16 @@ export default {
|
|
|
396
396
|
* @private
|
|
397
397
|
*/
|
|
398
398
|
_initOptions: function (element, options) {
|
|
399
|
+
const plugins = {};
|
|
400
|
+
if (options.plugins) {
|
|
401
|
+
const _plugins = options.plugins;
|
|
402
|
+
const pluginsValues = _plugins.length ? _plugins : Object.keys(_plugins).map(function(name) { return _plugins[name]; });
|
|
403
|
+
for (let i = 0, len = pluginsValues.length, p; i < len; i++) {
|
|
404
|
+
p = pluginsValues[i].default || pluginsValues[i];
|
|
405
|
+
plugins[p.name] = p;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
options.plugins = plugins;
|
|
399
409
|
/** Values */
|
|
400
410
|
options.lang = options.lang || _defaultLang;
|
|
401
411
|
options.value = typeof options.value === 'string' ? options.value : null;
|
|
@@ -450,6 +460,7 @@ export default {
|
|
|
450
460
|
options.toolbarWidth = options.toolbarWidth ? (util.isNumber(options.toolbarWidth) ? options.toolbarWidth + 'px' : options.toolbarWidth) : 'auto';
|
|
451
461
|
options.toolbarContainer = typeof options.toolbarContainer === 'string' ? document.querySelector(options.toolbarContainer) : options.toolbarContainer;
|
|
452
462
|
options.stickyToolbar = (/balloon/i.test(options.mode) || !!options.toolbarContainer) ? -1 : options.stickyToolbar === undefined ? 0 : (/^\d+/.test(options.stickyToolbar) ? util.getNumber(options.stickyToolbar, 0) : -1);
|
|
463
|
+
options.hideToolbar = !!options.hideToolbar;
|
|
453
464
|
options.fullScreenOffset = options.fullScreenOffset === undefined ? 0 : (/^\d+/.test(options.fullScreenOffset) ? util.getNumber(options.fullScreenOffset, 0) : 0);
|
|
454
465
|
options.fullPage = !!options.fullPage;
|
|
455
466
|
options.iframe = options.fullPage || !!options.iframe;
|
|
@@ -493,7 +504,7 @@ export default {
|
|
|
493
504
|
options.className = (typeof options.className === 'string' && options.className.length > 0) ? ' ' + options.className : '';
|
|
494
505
|
options.defaultStyle = typeof options.defaultStyle === 'string' ? options.defaultStyle : '';
|
|
495
506
|
/** Defining menu items */
|
|
496
|
-
options.font = !options.font ?
|
|
507
|
+
options.font = !options.font ? ['Arial', 'Comic Sans MS', 'Courier New', 'Impact', 'Georgia', 'tahoma', 'Trebuchet MS', 'Verdana'] : options.font;
|
|
497
508
|
options.fontSize = !options.fontSize ? null : options.fontSize;
|
|
498
509
|
options.formats = !options.formats ? null : options.formats;
|
|
499
510
|
options.colorList = !options.colorList ? null : options.colorList;
|
|
@@ -756,12 +767,12 @@ export default {
|
|
|
756
767
|
* @description Create editor HTML
|
|
757
768
|
* @param {Array} doc document object
|
|
758
769
|
* @param {Array} buttonList option.buttonList
|
|
759
|
-
* @param {
|
|
770
|
+
* @param {Object|null} plugins Plugins
|
|
760
771
|
* @param {Array} options options
|
|
761
772
|
* @returns {Object} { element: (Element) Toolbar element, plugins: (Array|null) Plugins Array, pluginCallButtons: (Object), responsiveButtons: (Array) }
|
|
762
773
|
* @private
|
|
763
774
|
*/
|
|
764
|
-
_createToolBar: function (doc, buttonList,
|
|
775
|
+
_createToolBar: function (doc, buttonList, plugins, options) {
|
|
765
776
|
const separator_vertical = doc.createElement('DIV');
|
|
766
777
|
separator_vertical.className = 'se-toolbar-separator-vertical';
|
|
767
778
|
|
|
@@ -778,14 +789,6 @@ export default {
|
|
|
778
789
|
const defaultButtonList = this._defaultButtons(options);
|
|
779
790
|
const pluginCallButtons = {};
|
|
780
791
|
const responsiveButtons = [];
|
|
781
|
-
const plugins = {};
|
|
782
|
-
if (_plugins) {
|
|
783
|
-
const pluginsValues = _plugins.length ? _plugins : Object.keys(_plugins).map(function(name) { return _plugins[name]; });
|
|
784
|
-
for (let i = 0, len = pluginsValues.length, p; i < len; i++) {
|
|
785
|
-
p = pluginsValues[i].default || pluginsValues[i];
|
|
786
|
-
plugins[p.name] = p;
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
792
|
|
|
790
793
|
let module = null;
|
|
791
794
|
let button = null;
|
|
@@ -926,6 +929,8 @@ export default {
|
|
|
926
929
|
tool_cover.className = 'se-toolbar-cover';
|
|
927
930
|
tool_bar.appendChild(tool_cover);
|
|
928
931
|
|
|
932
|
+
if (options.hideToolbar) tool_bar.style.display = 'none';
|
|
933
|
+
|
|
929
934
|
return {
|
|
930
935
|
'element': tool_bar,
|
|
931
936
|
'plugins': plugins,
|
package/src/lib/core.js
CHANGED
|
@@ -41,6 +41,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
41
41
|
_parser: new _w.DOMParser(),
|
|
42
42
|
_prevRtl: options.rtl,
|
|
43
43
|
_editorHeight: 0,
|
|
44
|
+
_editorHeightPadding: 0,
|
|
44
45
|
_listCamel: options.__listCommonStyle,
|
|
45
46
|
_listKebab: util.camelToKebabCase(options.__listCommonStyle),
|
|
46
47
|
|
|
@@ -282,6 +283,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
282
283
|
* @private
|
|
283
284
|
*/
|
|
284
285
|
_attributesWhitelistRegExp: null,
|
|
286
|
+
_attributesWhitelistRegExp_all_data: null,
|
|
285
287
|
|
|
286
288
|
/**
|
|
287
289
|
* @description Attributes blacklist used by the cleanHTML method
|
|
@@ -468,6 +470,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
468
470
|
*/
|
|
469
471
|
_styleCommandMap: null,
|
|
470
472
|
|
|
473
|
+
/**
|
|
474
|
+
* @private
|
|
475
|
+
*/
|
|
476
|
+
_cleanStyleRegExp: {
|
|
477
|
+
span: new _w.RegExp('\s*(font-family|font-size|color|background-color)\s*:[^;]+(?!;)*', 'ig'),
|
|
478
|
+
format: new _w.RegExp('\s*(text-align|margin-left|margin-right)\s*:[^;]+(?!;)*', 'ig')
|
|
479
|
+
},
|
|
480
|
+
|
|
471
481
|
/**
|
|
472
482
|
* @description Variables used internally in editor operation
|
|
473
483
|
* @property {Boolean} isCodeView State of code view
|
|
@@ -1500,7 +1510,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
1500
1510
|
|
|
1501
1511
|
const currentFormatEl = util.getFormatElement(this.getSelectionNode(), null);
|
|
1502
1512
|
let oFormat = null;
|
|
1503
|
-
if (util.isFreeFormatElement(currentFormatEl || element.parentNode)) {
|
|
1513
|
+
if (!util.isFormatElement(element) && util.isFreeFormatElement(currentFormatEl || element.parentNode)) {
|
|
1504
1514
|
oFormat = util.createElement('BR');
|
|
1505
1515
|
} else {
|
|
1506
1516
|
const oFormatName = formatNode ? (typeof formatNode === 'string' ? formatNode : formatNode.nodeName) : (util.isFormatElement(currentFormatEl) && !util.isRangeFormatElement(currentFormatEl) && !util.isFreeFormatElement(currentFormatEl)) ? currentFormatEl.nodeName : options.defaultTag;
|
|
@@ -1691,7 +1701,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
1691
1701
|
const isEdge = this.isEdgePoint(range.endContainer, range.endOffset, 'end');
|
|
1692
1702
|
const r = this.removeNode();
|
|
1693
1703
|
const container = r.container;
|
|
1694
|
-
const prevContainer = r.prevContainer;
|
|
1704
|
+
const prevContainer = (container === r.prevContainer && range.collapsed) ? null : r.prevContainer;
|
|
1695
1705
|
|
|
1696
1706
|
if (insertListCell && prevContainer) {
|
|
1697
1707
|
tempParentNode = prevContainer.nodeType === 3 ? prevContainer.parentNode : prevContainer;
|
|
@@ -1731,7 +1741,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
1731
1741
|
newCell.appendChild(line.lastElementChild);
|
|
1732
1742
|
}
|
|
1733
1743
|
if (newCell) {
|
|
1734
|
-
|
|
1744
|
+
line.parentNode.insertBefore(newCell, line.nextElementSibling);
|
|
1735
1745
|
tempAfterNode = afterNode = newCell;
|
|
1736
1746
|
}
|
|
1737
1747
|
}
|
|
@@ -5031,10 +5041,16 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5031
5041
|
// element
|
|
5032
5042
|
if (node.nodeType === 1) {
|
|
5033
5043
|
if (util._disallowedTags(node)) return '';
|
|
5044
|
+
|
|
5045
|
+
const ch = util.getListChildNodes(node, function(current) { return util.isSpanWithoutAttr(current); }) || [];
|
|
5046
|
+
for (let i = ch.length - 1; i >= 0; i--) {
|
|
5047
|
+
ch[i].outerHTML = ch[i].innerHTML;
|
|
5048
|
+
}
|
|
5049
|
+
|
|
5034
5050
|
if (!requireFormat || (util.isFormatElement(node) || util.isRangeFormatElement(node) || util.isComponent(node) || util.isMedia(node) || (util.isAnchor(node) && util.isMedia(node.firstElementChild)))) {
|
|
5035
|
-
return node.outerHTML;
|
|
5051
|
+
return util.isSpanWithoutAttr(node) ? node.innerHTML : node.outerHTML;
|
|
5036
5052
|
} else {
|
|
5037
|
-
return '<' + defaultTag + '>' + node.outerHTML + '</' + defaultTag + '>';
|
|
5053
|
+
return '<' + defaultTag + '>' + (util.isSpanWithoutAttr(node) ? node.innerHTML : node.outerHTML) + '</' + defaultTag + '>';
|
|
5038
5054
|
}
|
|
5039
5055
|
}
|
|
5040
5056
|
// text
|
|
@@ -5086,6 +5102,46 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5086
5102
|
.replace(this.editorTagsBlacklistRegExp, '');
|
|
5087
5103
|
},
|
|
5088
5104
|
|
|
5105
|
+
_cleanStyle: function (m, v, tagName) {
|
|
5106
|
+
const sv = m.match(/style\s*=\s*(?:"|')[^"']*(?:"|')/);
|
|
5107
|
+
if (sv) {
|
|
5108
|
+
if (!v) v = [];
|
|
5109
|
+
const style = sv[0].replace(/"/g, '').match(this._cleanStyleRegExp[tagName]);
|
|
5110
|
+
if (style) {
|
|
5111
|
+
const allowedStyle = [];
|
|
5112
|
+
for (let i = 0, len = style.length, r; i < len; i++) {
|
|
5113
|
+
r = style[i].match(/(.+)(:)([^:]+$)/);
|
|
5114
|
+
if (r && !/inherit|initial/i.test(r[3])) {
|
|
5115
|
+
const k = util.kebabToCamelCase(r[1].trim());
|
|
5116
|
+
const v = this.wwComputedStyle[k].replace(/"/g, '');
|
|
5117
|
+
const c = r[3].trim();
|
|
5118
|
+
switch (k) {
|
|
5119
|
+
case 'fontFamily':
|
|
5120
|
+
if (!options.plugins.font || options.font.indexOf(c) === -1) continue;
|
|
5121
|
+
break;
|
|
5122
|
+
case 'fontSize':
|
|
5123
|
+
if (!options.plugins.fontSize) continue;
|
|
5124
|
+
break;
|
|
5125
|
+
case 'color':
|
|
5126
|
+
if (!options.plugins.fontColor) continue;
|
|
5127
|
+
break;
|
|
5128
|
+
case 'backgroundColor':
|
|
5129
|
+
if (!options.plugins.hiliteColor) continue;
|
|
5130
|
+
break;
|
|
5131
|
+
}
|
|
5132
|
+
|
|
5133
|
+
if (v !== c) {
|
|
5134
|
+
allowedStyle.push(r[0]);
|
|
5135
|
+
}
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
if (allowedStyle.length > 0) v.push('style="' + allowedStyle.join(';') + '"');
|
|
5139
|
+
}
|
|
5140
|
+
}
|
|
5141
|
+
|
|
5142
|
+
return v;
|
|
5143
|
+
},
|
|
5144
|
+
|
|
5089
5145
|
/**
|
|
5090
5146
|
* @description Tag and tag attribute check RegExp function. (used by "cleanHTML" and "convertContentsForEditor")
|
|
5091
5147
|
* @param {Boolean} lowLevelCheck Row level check
|
|
@@ -5102,34 +5158,38 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5102
5158
|
|
|
5103
5159
|
// blacklist
|
|
5104
5160
|
const bAttr = this._attributesTagsBlacklist[tagName];
|
|
5161
|
+
m = m.replace(/\s(?:on[a-z]+)\s*=\s*(")[^"]*\1/ig, '');
|
|
5105
5162
|
if (bAttr) m = m.replace(bAttr, '');
|
|
5106
5163
|
else m = m.replace(this._attributesBlacklistRegExp, '');
|
|
5107
5164
|
|
|
5108
5165
|
// whitelist
|
|
5109
5166
|
const wAttr = this._attributesTagsWhitelist[tagName];
|
|
5110
5167
|
if (wAttr) v = m.match(wAttr);
|
|
5111
|
-
else v = m.match(this._attributesWhitelistRegExp);
|
|
5168
|
+
else v = m.match(lowLevelCheck ? this._attributesWhitelistRegExp : this._attributesWhitelistRegExp_all_data);
|
|
5112
5169
|
|
|
5113
|
-
//
|
|
5114
|
-
if (
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
if (
|
|
5118
|
-
|
|
5170
|
+
// attribute
|
|
5171
|
+
if (lowLevelCheck) {
|
|
5172
|
+
if (tagName === 'a') {
|
|
5173
|
+
const sv = m.match(/(?:(?:id|name)\s*=\s*(?:"|')[^"']*(?:"|'))/g);
|
|
5174
|
+
if (sv) {
|
|
5175
|
+
if (!v) v = [];
|
|
5176
|
+
v.push(sv[0]);
|
|
5177
|
+
}
|
|
5178
|
+
} else if (!v || !/style=/i.test(v.toString())) {
|
|
5179
|
+
if (tagName === 'span') {
|
|
5180
|
+
v = this._cleanStyle(m, v, 'span');
|
|
5181
|
+
} else if (/^(P|DIV|H[1-6]|PRE)$/i.test(tagName)) {
|
|
5182
|
+
v = this._cleanStyle(m, v, 'format');
|
|
5183
|
+
}
|
|
5119
5184
|
}
|
|
5120
|
-
}
|
|
5121
|
-
|
|
5122
|
-
// span
|
|
5123
|
-
if ((!lowLevelCheck || /<span/i.test(t)) && (!v || !/style=/i.test(v.toString()))) {
|
|
5185
|
+
} else {
|
|
5124
5186
|
const sv = m.match(/style\s*=\s*(?:"|')[^"']*(?:"|')/);
|
|
5125
|
-
if (sv)
|
|
5126
|
-
|
|
5127
|
-
v.push(sv[0]);
|
|
5128
|
-
}
|
|
5187
|
+
if (sv && !v) v = [sv[0]];
|
|
5188
|
+
else if (sv && !v.some(function (v) { return /^style/.test(v.trim()); })) v.push(sv[0]);
|
|
5129
5189
|
}
|
|
5130
5190
|
|
|
5131
5191
|
// img
|
|
5132
|
-
if (
|
|
5192
|
+
if (tagName === 'img') {
|
|
5133
5193
|
let w = '', h = '';
|
|
5134
5194
|
const sv = m.match(/style\s*=\s*(?:"|')[^"']*(?:"|')/);
|
|
5135
5195
|
if (!v) v = [];
|
|
@@ -5153,14 +5213,82 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5153
5213
|
|
|
5154
5214
|
if (v) {
|
|
5155
5215
|
for (let i = 0, len = v.length; i < len; i++) {
|
|
5156
|
-
if (lowLevelCheck && /^class="(?!(__se__|se-|katex))/.test(v[i])) continue;
|
|
5157
|
-
t += ' ' + (/^(?:href|src)\s*=\s*('|"|\s)*javascript\s*\:/i.test(v[i]) ? '' : v[i]);
|
|
5216
|
+
if (lowLevelCheck && /^class="(?!(__se__|se-|katex))/.test(v[i].trim())) continue;
|
|
5217
|
+
t += ' ' + (/^(?:href|src)\s*=\s*('|"|\s)*javascript\s*\:/i.test(v[i].trim()) ? '' : v[i]);
|
|
5158
5218
|
}
|
|
5159
5219
|
}
|
|
5160
5220
|
|
|
5161
5221
|
return t;
|
|
5162
5222
|
},
|
|
5163
5223
|
|
|
5224
|
+
/**
|
|
5225
|
+
* @description Determines if formatting is required and returns a domTree
|
|
5226
|
+
* @param {Element} dom documentFragment
|
|
5227
|
+
* @returns {Element}
|
|
5228
|
+
* @private
|
|
5229
|
+
*/
|
|
5230
|
+
_editFormat: function (dom) {
|
|
5231
|
+
let value = '', f;
|
|
5232
|
+
const tempTree = dom.childNodes;
|
|
5233
|
+
for (let i = 0, len = tempTree.length, n; i < len; i++) {
|
|
5234
|
+
n = tempTree[i];
|
|
5235
|
+
if (!util.isFormatElement(n) && !util.isRangeFormatElement(n) && !util.isComponent(n) && !/meta/i.test(n.nodeName)) {
|
|
5236
|
+
if (!f) f = util.createElement(options.defaultTag);
|
|
5237
|
+
f.appendChild(n);
|
|
5238
|
+
i--; len--;
|
|
5239
|
+
} else {
|
|
5240
|
+
if (f) {
|
|
5241
|
+
value += f.outerHTML;
|
|
5242
|
+
f = null;
|
|
5243
|
+
}
|
|
5244
|
+
value += n.outerHTML;
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
|
|
5248
|
+
if (f) value += f.outerHTML;
|
|
5249
|
+
|
|
5250
|
+
return _d.createRange().createContextualFragment(value);
|
|
5251
|
+
},
|
|
5252
|
+
|
|
5253
|
+
_convertListCell: function (domTree) {
|
|
5254
|
+
let html = '';
|
|
5255
|
+
|
|
5256
|
+
for (let i = 0, len = domTree.length, node; i < len; i++) {
|
|
5257
|
+
node = domTree[i];
|
|
5258
|
+
if (node.nodeType === 1) {
|
|
5259
|
+
if (util.isList(node)) {
|
|
5260
|
+
html += node.innerHTML;
|
|
5261
|
+
} else if (util.isListCell(node)) {
|
|
5262
|
+
html += node.outerHTML;
|
|
5263
|
+
} else if (util.isFormatElement(node)) {
|
|
5264
|
+
html += '<li>' +(node.innerHTML.trim() || '<br>') + '</li>';
|
|
5265
|
+
} else if (util.isRangeFormatElement(node) && !util.isTable(node)) {
|
|
5266
|
+
html += this._convertListCell(node);
|
|
5267
|
+
} else {
|
|
5268
|
+
html += '<li>' + node.outerHTML + '</li>';
|
|
5269
|
+
}
|
|
5270
|
+
} else {
|
|
5271
|
+
html += '<li>' + (node.textContent || '<br>') + '</li>';
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5274
|
+
|
|
5275
|
+
return html;
|
|
5276
|
+
},
|
|
5277
|
+
|
|
5278
|
+
_isFormatData: function (domTree) {
|
|
5279
|
+
let requireFormat = false;
|
|
5280
|
+
|
|
5281
|
+
for (let i = 0, len = domTree.length, t; i < len; i++) {
|
|
5282
|
+
t = domTree[i];
|
|
5283
|
+
if (t.nodeType === 1 && !util.isTextStyleElement(t) && !util.isBreak(t) && !util._disallowedTags(t)) {
|
|
5284
|
+
requireFormat = true;
|
|
5285
|
+
break;
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
|
|
5289
|
+
return requireFormat;
|
|
5290
|
+
},
|
|
5291
|
+
|
|
5164
5292
|
/**
|
|
5165
5293
|
* @description Gets the clean HTML code for editor
|
|
5166
5294
|
* @param {String} html HTML string
|
|
@@ -5194,16 +5322,12 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5194
5322
|
}
|
|
5195
5323
|
}
|
|
5196
5324
|
|
|
5197
|
-
|
|
5325
|
+
let domTree = dom.childNodes;
|
|
5198
5326
|
let cleanHTML = '';
|
|
5199
|
-
|
|
5327
|
+
const requireFormat = this._isFormatData(domTree);
|
|
5200
5328
|
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
if (t.nodeType === 1 && !util.isTextStyleElement(t) && !util.isBreak(t) && !util._disallowedTags(t)) {
|
|
5204
|
-
requireFormat = true;
|
|
5205
|
-
break;
|
|
5206
|
-
}
|
|
5329
|
+
if(requireFormat) {
|
|
5330
|
+
domTree = this._editFormat(dom).childNodes;
|
|
5207
5331
|
}
|
|
5208
5332
|
|
|
5209
5333
|
for (let i = 0, len = domTree.length; i < len; i++) {
|
|
@@ -5566,6 +5690,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5566
5690
|
this._charTypeHTML = options.charCounterType === 'byte-html';
|
|
5567
5691
|
this.wwComputedStyle = _w.getComputedStyle(context.element.wysiwyg);
|
|
5568
5692
|
this._editorHeight = context.element.wysiwygFrame.offsetHeight;
|
|
5693
|
+
this._editorHeightPadding = util.getNumber(this.wwComputedStyle.getPropertyValue('padding-top')) + util.getNumber(this.wwComputedStyle.getPropertyValue('padding-bottom'));
|
|
5569
5694
|
|
|
5570
5695
|
if (!options.iframe && typeof _w.ShadowRoot === 'function') {
|
|
5571
5696
|
let child = context.element.wysiwygFrame;
|
|
@@ -5593,7 +5718,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5593
5718
|
// set whitelist
|
|
5594
5719
|
const getRegList = function (str, str2) { return !str ? '^' : (str === '*' ? '[a-z-]+' : (!str2 ? str : (str + '|' + str2))); };
|
|
5595
5720
|
// tags
|
|
5596
|
-
const defaultAttr = 'contenteditable|colspan|rowspan|target|href|download|rel|src|alt|class|type|controls|
|
|
5721
|
+
const defaultAttr = 'contenteditable|colspan|rowspan|target|href|download|rel|src|alt|class|type|controls|origin-size';
|
|
5722
|
+
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';
|
|
5597
5723
|
this._allowHTMLComments = options._editorTagsWhitelist.indexOf('//') > -1 || options._editorTagsWhitelist === '*';
|
|
5598
5724
|
// html check
|
|
5599
5725
|
this._htmlCheckWhitelistRegExp = new wRegExp('^(' + getRegList(options._editorTagsWhitelist.replace('|//', ''), '') + ')$', 'i');
|
|
@@ -5620,7 +5746,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5620
5746
|
}
|
|
5621
5747
|
}
|
|
5622
5748
|
|
|
5623
|
-
this._attributesWhitelistRegExp = new wRegExp('\\s(?:' + (allAttr || defaultAttr) + ')' + regEndStr, 'ig');
|
|
5749
|
+
this._attributesWhitelistRegExp = new wRegExp('\\s(?:' + (allAttr || defaultAttr + '|' + dataAttr) + ')' + regEndStr, 'ig');
|
|
5750
|
+
this._attributesWhitelistRegExp_all_data = new wRegExp('\\s(?:' + ((allAttr || defaultAttr) + '|data-[a-z0-9\\-]+') + ')' + regEndStr, 'ig');
|
|
5624
5751
|
this._attributesTagsWhitelist = tagsAttr;
|
|
5625
5752
|
|
|
5626
5753
|
// blacklist
|
|
@@ -5799,7 +5926,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
5799
5926
|
},
|
|
5800
5927
|
|
|
5801
5928
|
__callResizeFunction: function (h, resizeObserverEntry) {
|
|
5802
|
-
h = h === -1 ? resizeObserverEntry.borderBoxSize[0].blockSize : h;
|
|
5929
|
+
h = h === -1 ? (resizeObserverEntry.borderBoxSize ? resizeObserverEntry.borderBoxSize[0].blockSize : (resizeObserverEntry.contentRect.height + this._editorHeightPadding)) : h;
|
|
5803
5930
|
if (this._editorHeight !== h) {
|
|
5804
5931
|
if (typeof functions.onResizeEditor === 'function') functions.onResizeEditor(h, this._editorHeight, core, resizeObserverEntry);
|
|
5805
5932
|
this._editorHeight = h;
|
|
@@ -7691,39 +7818,11 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
7691
7818
|
}
|
|
7692
7819
|
|
|
7693
7820
|
if (cleanData) {
|
|
7694
|
-
if (util.isListCell(util.getFormatElement(core.getSelectionNode(), null))) {
|
|
7695
|
-
const dom = (_d.createRange().createContextualFragment(cleanData));
|
|
7696
|
-
const domTree = dom.childNodes;
|
|
7697
|
-
if (domTree.length > 1 && domTree[0].nodeType === 1) cleanData = event._convertListCell(domTree);
|
|
7698
|
-
}
|
|
7699
7821
|
functions.insertHTML(cleanData, true, false);
|
|
7700
7822
|
return false;
|
|
7701
7823
|
}
|
|
7702
7824
|
},
|
|
7703
7825
|
|
|
7704
|
-
_convertListCell: function (domTree) {
|
|
7705
|
-
let html = '';
|
|
7706
|
-
|
|
7707
|
-
for (let i = 0, len = domTree.length, node; i < len; i++) {
|
|
7708
|
-
node = domTree[i];
|
|
7709
|
-
if (node.nodeType === 1) {
|
|
7710
|
-
if (util.isListCell(node) || util.isList(node)) {
|
|
7711
|
-
html += node.outerHTML;
|
|
7712
|
-
} else if (util.isFormatElement(node)) {
|
|
7713
|
-
html += '<li>' +(node.innerHTML.trim() || '<br>') + '</li>';
|
|
7714
|
-
} else if (util.isRangeFormatElement(node) && !util.isTable(node)) {
|
|
7715
|
-
html += event._convertListCell(node);
|
|
7716
|
-
} else {
|
|
7717
|
-
html += '<li>' + node.outerHTML + '</li>';
|
|
7718
|
-
}
|
|
7719
|
-
} else {
|
|
7720
|
-
html += '<li>' + (node.textContent || '<br>') + '</li>';
|
|
7721
|
-
}
|
|
7722
|
-
}
|
|
7723
|
-
|
|
7724
|
-
return html;
|
|
7725
|
-
},
|
|
7726
|
-
|
|
7727
7826
|
onMouseMove_wysiwyg: function (e) {
|
|
7728
7827
|
if (core.isDisabled || core.isReadOnly) return false;
|
|
7729
7828
|
const component = util.getParentElement(e.target, util.isComponent);
|
|
@@ -8439,10 +8538,16 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
|
|
|
8439
8538
|
*/
|
|
8440
8539
|
insertHTML: function (html, notCleaningData, checkCharCount, rangeSelection) {
|
|
8441
8540
|
if (!context.element.wysiwygFrame.contains(core.getSelection().focusNode)) core.focus();
|
|
8442
|
-
|
|
8541
|
+
|
|
8443
8542
|
if (typeof html === 'string') {
|
|
8444
8543
|
if (!notCleaningData) html = core.cleanHTML(html, null, null);
|
|
8445
8544
|
try {
|
|
8545
|
+
if (util.isListCell(util.getFormatElement(core.getSelectionNode(), null))) {
|
|
8546
|
+
const dom = _d.createRange().createContextualFragment(html);
|
|
8547
|
+
const domTree = dom.childNodes;
|
|
8548
|
+
if (core._isFormatData(domTree)) html = core._convertListCell(domTree);
|
|
8549
|
+
}
|
|
8550
|
+
|
|
8446
8551
|
const dom = _d.createRange().createContextualFragment(html);
|
|
8447
8552
|
const domTree = dom.childNodes;
|
|
8448
8553
|
|
package/src/lib/util.d.ts
CHANGED
|
@@ -42,6 +42,12 @@ declare interface util {
|
|
|
42
42
|
*/
|
|
43
43
|
camelToKebabCase(param: string | string[]): string | string[],
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* @description Convert the KebabCase To the CamelCase.
|
|
47
|
+
* @param {String|Array} param [KebabCase string]
|
|
48
|
+
*/
|
|
49
|
+
kebabToCamelCase(param: string | string[]): string | string[],
|
|
50
|
+
|
|
45
51
|
/**
|
|
46
52
|
* @description Create Element node
|
|
47
53
|
* @param elementName Element name
|
|
@@ -351,6 +357,13 @@ declare interface util {
|
|
|
351
357
|
*/
|
|
352
358
|
isEmptyLine(element: Element): boolean;
|
|
353
359
|
|
|
360
|
+
/**
|
|
361
|
+
* @description Check the span's attributes are empty.
|
|
362
|
+
* @param {Element} element Element node
|
|
363
|
+
* @returns {Boolean}
|
|
364
|
+
*/
|
|
365
|
+
isSpanWithoutAttr(element: Element|null): boolean;
|
|
366
|
+
|
|
354
367
|
/**
|
|
355
368
|
* @description Check the node is a list (ol, ul)
|
|
356
369
|
* @param node The element or element name to check
|
package/src/lib/util.js
CHANGED
|
@@ -119,6 +119,19 @@ const util = {
|
|
|
119
119
|
}
|
|
120
120
|
},
|
|
121
121
|
|
|
122
|
+
/**
|
|
123
|
+
* @description Convert the KebabCase To the CamelCase.
|
|
124
|
+
* @param {String|Array} param [KebabCase string]
|
|
125
|
+
* @returns {String|Array}
|
|
126
|
+
*/
|
|
127
|
+
kebabToCamelCase: function (param) {
|
|
128
|
+
if (typeof param === 'string') {
|
|
129
|
+
return param.replace(/-[a-zA-Z]/g, function (letter) { return letter.replace('-', '').toUpperCase(); });
|
|
130
|
+
} else {
|
|
131
|
+
return param.map(function(str) { return util.camelToKebabCase(str); });
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
|
|
122
135
|
/**
|
|
123
136
|
* @description Create Element node
|
|
124
137
|
* @param {String} elementName Element name
|
|
@@ -763,6 +776,15 @@ const util = {
|
|
|
763
776
|
return !element || !element.parentNode || (!element.querySelector('IMG, IFRAME, AUDIO, VIDEO, CANVAS, TABLE') && this.onlyZeroWidthSpace(element.textContent));
|
|
764
777
|
},
|
|
765
778
|
|
|
779
|
+
/**
|
|
780
|
+
* @description Check the span's attributes are empty.
|
|
781
|
+
* @param {Element|null} element Element node
|
|
782
|
+
* @returns {Boolean}
|
|
783
|
+
*/
|
|
784
|
+
isSpanWithoutAttr: function (element) {
|
|
785
|
+
return !!element && element.nodeType === 1 && /^SPAN$/i.test(element.nodeName) && !element.className && !element.style.cssText;
|
|
786
|
+
},
|
|
787
|
+
|
|
766
788
|
/**
|
|
767
789
|
* @description Check the node is a list (ol, ul)
|
|
768
790
|
* @param {Node|String} node The element or element name to check
|
|
@@ -1375,12 +1397,33 @@ const util = {
|
|
|
1375
1397
|
* @description Split all tags based on "baseNode"
|
|
1376
1398
|
* Returns the last element of the splited tag.
|
|
1377
1399
|
* @param {Node} baseNode Element or text node on which to base
|
|
1378
|
-
* @param {Number|null} offset Text offset of "baseNode" (Only valid when "baseNode" is a text node)
|
|
1400
|
+
* @param {Number|Node|null} offset Text offset of "baseNode" (Only valid when "baseNode" is a text node)
|
|
1379
1401
|
* @param {Number} depth The nesting depth of the element being split. (default: 0)
|
|
1380
1402
|
* @returns {Element}
|
|
1381
1403
|
*/
|
|
1382
1404
|
splitElement: function (baseNode, offset, depth) {
|
|
1383
1405
|
if (this.isWysiwygDiv(baseNode)) return baseNode;
|
|
1406
|
+
|
|
1407
|
+
if (!!offset && !this.isNumber(offset)) {
|
|
1408
|
+
const children = baseNode.childNodes;
|
|
1409
|
+
let index = this.getPositionIndex(offset);
|
|
1410
|
+
const prev = baseNode.cloneNode(false);
|
|
1411
|
+
const next = baseNode.cloneNode(false);
|
|
1412
|
+
for (let i = 0, len = children.length; i < len; i++) {
|
|
1413
|
+
if (i < index) prev.appendChild(children[i]);
|
|
1414
|
+
else if (i > index) next.appendChild(children[i]);
|
|
1415
|
+
else continue;
|
|
1416
|
+
i--;
|
|
1417
|
+
len--;
|
|
1418
|
+
index--;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
if (prev.childNodes.length > 0) baseNode.parentNode.insertBefore(prev, baseNode);
|
|
1422
|
+
if (next.childNodes.length > 0) baseNode.parentNode.insertBefore(next, baseNode.nextElementSibling);
|
|
1423
|
+
|
|
1424
|
+
return baseNode;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1384
1427
|
const bp = baseNode.parentNode;
|
|
1385
1428
|
let index = 0, newEl, children, temp;
|
|
1386
1429
|
let next = true;
|
|
@@ -454,7 +454,7 @@ export default {
|
|
|
454
454
|
this.plugins.audio._setTagAttrs.call(this, element);
|
|
455
455
|
|
|
456
456
|
// find component element
|
|
457
|
-
|
|
457
|
+
let existElement = (this.util.isRangeFormatElement(element.parentNode) || this.util.isWysiwygDiv(element.parentNode)) ?
|
|
458
458
|
element : this.util.getFormatElement(element) || element;
|
|
459
459
|
|
|
460
460
|
// clone element
|
|
@@ -464,12 +464,16 @@ export default {
|
|
|
464
464
|
const container = this.plugins.component.set_container.call(this, cover, 'se-audio-container');
|
|
465
465
|
|
|
466
466
|
try {
|
|
467
|
-
if (this.util.isListCell(existElement)
|
|
468
|
-
|
|
469
|
-
|
|
467
|
+
if (this.util.isListCell(existElement)) {
|
|
468
|
+
const refer = this.util.getParentElement(prevElement, function (current) { return current.parentNode === existElement; });
|
|
469
|
+
existElement.insertBefore(container, refer);
|
|
470
|
+
this.util.removeItem(prevElement);
|
|
471
|
+
this.util.removeEmptyNode(refer, null);
|
|
472
|
+
} else if (this.util.isFormatElement(existElement)) {
|
|
473
|
+
const refer = this.util.getParentElement(prevElement, function (current) { return current.parentNode === existElement; });
|
|
474
|
+
existElement = this.util.splitElement(existElement, refer);
|
|
470
475
|
existElement.parentNode.insertBefore(container, existElement);
|
|
471
476
|
this.util.removeItem(prevElement);
|
|
472
|
-
// clean format tag
|
|
473
477
|
this.util.removeEmptyNode(existElement, null);
|
|
474
478
|
if (existElement.children.length === 0) existElement.innerHTML = this.util.htmlRemoveWhiteSpace(existElement.innerHTML);
|
|
475
479
|
} else {
|
|
@@ -768,16 +768,20 @@ export default {
|
|
|
768
768
|
}
|
|
769
769
|
|
|
770
770
|
if (isNewContainer) {
|
|
771
|
-
|
|
771
|
+
let existElement = (this.util.isRangeFormatElement(contextImage._element.parentNode) || this.util.isWysiwygDiv(contextImage._element.parentNode)) ?
|
|
772
772
|
contextImage._element :
|
|
773
773
|
/^A$/i.test(contextImage._element.parentNode.nodeName) ? contextImage._element.parentNode : this.util.getFormatElement(contextImage._element) || contextImage._element;
|
|
774
774
|
|
|
775
|
-
if (this.util.isListCell(existElement)
|
|
776
|
-
|
|
777
|
-
|
|
775
|
+
if (this.util.isListCell(existElement)) {
|
|
776
|
+
const refer = this.util.getParentElement(contextImage._element, function (current) { return current.parentNode === existElement; });
|
|
777
|
+
existElement.insertBefore(container, refer);
|
|
778
|
+
this.util.removeItem(contextImage._element);
|
|
779
|
+
this.util.removeEmptyNode(refer, null);
|
|
780
|
+
} else if (this.util.isFormatElement(existElement)) {
|
|
781
|
+
const refer = this.util.getParentElement(contextImage._element, function (current) { return current.parentNode === existElement; });
|
|
782
|
+
existElement = this.util.splitElement(existElement, refer);
|
|
778
783
|
existElement.parentNode.insertBefore(container, existElement);
|
|
779
784
|
this.util.removeItem(contextImage._element);
|
|
780
|
-
// clean format tag
|
|
781
785
|
this.util.removeEmptyNode(existElement, null);
|
|
782
786
|
if (existElement.children.length === 0) existElement.innerHTML = this.util.htmlRemoveWhiteSpace(existElement.innerHTML);
|
|
783
787
|
} else {
|
|
@@ -645,7 +645,7 @@ export default {
|
|
|
645
645
|
if (/^video$/i.test(oFrame.nodeName)) this.plugins.video._setTagAttrs.call(this, oFrame);
|
|
646
646
|
else this.plugins.video._setIframeAttrs.call(this, oFrame);
|
|
647
647
|
|
|
648
|
-
|
|
648
|
+
let existElement = (this.util.isRangeFormatElement(oFrame.parentNode) || this.util.isWysiwygDiv(oFrame.parentNode)) ?
|
|
649
649
|
oFrame : this.util.getFormatElement(oFrame) || oFrame;
|
|
650
650
|
|
|
651
651
|
const prevFrame = oFrame;
|
|
@@ -671,12 +671,16 @@ export default {
|
|
|
671
671
|
if (format) contextVideo._align = format.style.textAlign || format.style.float;
|
|
672
672
|
this.plugins.video.setAlign.call(this, null, oFrame, cover, container);
|
|
673
673
|
|
|
674
|
-
if (this.util.isListCell(existElement)
|
|
675
|
-
|
|
676
|
-
|
|
674
|
+
if (this.util.isListCell(existElement)) {
|
|
675
|
+
const refer = this.util.getParentElement(prevFrame, function (current) { return current.parentNode === existElement; });
|
|
676
|
+
existElement.insertBefore(container, refer);
|
|
677
|
+
this.util.removeItem(prevFrame);
|
|
678
|
+
this.util.removeEmptyNode(refer, null);
|
|
679
|
+
} else if (this.util.isFormatElement(existElement)) {
|
|
680
|
+
const refer = this.util.getParentElement(prevFrame, function (current) { return current.parentNode === existElement; });
|
|
681
|
+
existElement = this.util.splitElement(existElement, refer);
|
|
677
682
|
existElement.parentNode.insertBefore(container, existElement);
|
|
678
683
|
this.util.removeItem(prevFrame);
|
|
679
|
-
// clean format tag
|
|
680
684
|
this.util.removeEmptyNode(existElement, null);
|
|
681
685
|
if (existElement.children.length === 0) existElement.innerHTML = this.util.htmlRemoveWhiteSpace(existElement.innerHTML);
|
|
682
686
|
} else {
|