suneditor 2.42.0 → 2.43.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/dist/css/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +2 -2
- package/package.json +4 -4
- package/src/assets/css/suneditor-contents.css +1 -1
- package/src/assets/css/suneditor.css +2 -1
- package/src/lang/zh_cn.js +1 -1
- package/src/lib/constructor.js +18 -5
- package/src/lib/context.js +1 -0
- package/src/lib/core.d.ts +10 -1
- package/src/lib/core.js +242 -68
- package/src/lib/util.d.ts +13 -0
- package/src/lib/util.js +31 -1
- package/src/options.d.ts +16 -1
- package/src/plugins/dialog/link.js +1 -0
- package/src/plugins/dialog/video.js +3 -2
- package/src/plugins/modules/_anchor.js +19 -12
- package/src/plugins/submenu/fontSize.js +1 -1
- package/src/plugins/submenu/list.js +13 -5
- package/src/plugins/submenu/template.js +5 -2
package/src/lib/util.js
CHANGED
|
@@ -16,6 +16,7 @@ const util = {
|
|
|
16
16
|
isIE: null,
|
|
17
17
|
isIE_Edge: null,
|
|
18
18
|
isOSX_IOS: null,
|
|
19
|
+
isChromium: null,
|
|
19
20
|
_propertiesInit: function () {
|
|
20
21
|
if (this._d) return;
|
|
21
22
|
this._d = document;
|
|
@@ -23,6 +24,7 @@ const util = {
|
|
|
23
24
|
this.isIE = navigator.userAgent.indexOf('Trident') > -1;
|
|
24
25
|
this.isIE_Edge = (navigator.userAgent.indexOf('Trident') > -1) || (navigator.appVersion.indexOf('Edge') > -1);
|
|
25
26
|
this.isOSX_IOS = /(Mac|iPhone|iPod|iPad)/.test(navigator.platform);
|
|
27
|
+
this.isChromium = !!window.chrome;
|
|
26
28
|
},
|
|
27
29
|
|
|
28
30
|
_allowedEmptyNodeList: '.se-component, pre, blockquote, hr, li, table, img, iframe, video, audio, canvas',
|
|
@@ -61,6 +63,7 @@ const util = {
|
|
|
61
63
|
* @returns {Boolean}
|
|
62
64
|
*/
|
|
63
65
|
onlyZeroWidthSpace: function (text) {
|
|
66
|
+
if (text === null || text === undefined) return false;
|
|
64
67
|
if (typeof text !== 'string') text = text.textContent;
|
|
65
68
|
return text === '' || this.onlyZeroWidthRegExp.test(text);
|
|
66
69
|
},
|
|
@@ -92,6 +95,30 @@ const util = {
|
|
|
92
95
|
}
|
|
93
96
|
},
|
|
94
97
|
|
|
98
|
+
/**
|
|
99
|
+
* @description Object.values
|
|
100
|
+
* @param {Object|null} obj Object parameter.
|
|
101
|
+
* @returns {Array}
|
|
102
|
+
*/
|
|
103
|
+
getValues: function (obj) {
|
|
104
|
+
return !obj ? [] : this._w.Object.keys(obj).map(function (i) {
|
|
105
|
+
return obj[i];
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @description Convert the CamelCase To the KebabCase.
|
|
111
|
+
* @param {String|Array} param [Camel string]
|
|
112
|
+
* @returns {String|Array}
|
|
113
|
+
*/
|
|
114
|
+
camelToKebabCase: function (param) {
|
|
115
|
+
if (typeof param === 'string') {
|
|
116
|
+
return param.replace(/[A-Z]/g, function (letter) { return "-" + letter.toLowerCase(); });
|
|
117
|
+
} else {
|
|
118
|
+
return param.map(function(str) { return util.camelToKebabCase(str); });
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
95
122
|
/**
|
|
96
123
|
* @description Create Element node
|
|
97
124
|
* @param {String} elementName Element name
|
|
@@ -1733,7 +1760,10 @@ const util = {
|
|
|
1733
1760
|
|
|
1734
1761
|
// wrong position
|
|
1735
1762
|
const wrongTags = this.getListChildNodes(documentFragment, function (current) {
|
|
1736
|
-
if (current.nodeType !== 1)
|
|
1763
|
+
if (current.nodeType !== 1) {
|
|
1764
|
+
if (this.isList(current.parentNode)) removeTags.push(current);
|
|
1765
|
+
return false;
|
|
1766
|
+
}
|
|
1737
1767
|
|
|
1738
1768
|
// white list
|
|
1739
1769
|
if (htmlCheckBlacklistRegExp.test(current.nodeName) || (!htmlCheckWhitelistRegExp.test(current.nodeName) && current.childNodes.length === 0 && this.isNotCheckingNode(current))) {
|
package/src/options.d.ts
CHANGED
|
@@ -24,6 +24,10 @@ export interface SunEditorOptions {
|
|
|
24
24
|
* If not, the value of the "target textarea".
|
|
25
25
|
*/
|
|
26
26
|
value?: string;
|
|
27
|
+
/**
|
|
28
|
+
* When recording the history stack, this is the delay time (miliseconds) since the last input. default: 400
|
|
29
|
+
*/
|
|
30
|
+
historyStackDelayTime?: number;
|
|
27
31
|
/**
|
|
28
32
|
* Whitelist
|
|
29
33
|
* ======
|
|
@@ -221,8 +225,19 @@ export interface SunEditorOptions {
|
|
|
221
225
|
*/
|
|
222
226
|
maxHeight?: string;
|
|
223
227
|
/**
|
|
224
|
-
* Editing area
|
|
228
|
+
* Editing area
|
|
229
|
+
* ===================
|
|
225
230
|
*/
|
|
231
|
+
/**
|
|
232
|
+
* Add a "class" to the editing area[.sun-editor-editable]
|
|
233
|
+
*/
|
|
234
|
+
className?: string;
|
|
235
|
+
/**
|
|
236
|
+
* You can define the style of the editing area[.sun-editor-editable].
|
|
237
|
+
* It affects the entire editing area.
|
|
238
|
+
* ('z-index', 'position' and 'width' properties apply to the top div.)
|
|
239
|
+
* @example 'font-family: cursive; font-size: 10px;'
|
|
240
|
+
*/
|
|
226
241
|
defaultStyle?: string;
|
|
227
242
|
/**
|
|
228
243
|
* Defining menu items
|
|
@@ -118,6 +118,7 @@ export default {
|
|
|
118
118
|
|
|
119
119
|
try {
|
|
120
120
|
const oA = this.plugins.anchor.createAnchor.call(this, this.context.anchor.caller.link, false);
|
|
121
|
+
if (oA === null) return;
|
|
121
122
|
|
|
122
123
|
if (!this.context.dialog.updateModal) {
|
|
123
124
|
const selectedFormats = this.getSelectedElements();
|
|
@@ -817,12 +817,13 @@ export default {
|
|
|
817
817
|
|
|
818
818
|
if (!onlyH) w = this.util.getNumber(w, 0);
|
|
819
819
|
if (!onlyW) h = this.util.isNumber(h) ? h + contextVideo.sizeUnit : !h ? '' : h;
|
|
820
|
+
w ? w + contextVideo.sizeUnit : '';
|
|
820
821
|
|
|
821
|
-
if (!onlyH) contextVideo._element.style.width = w
|
|
822
|
+
if (!onlyH) contextVideo._element.style.width = w;
|
|
822
823
|
if (!onlyW) contextVideo._cover.style.paddingBottom = contextVideo._cover.style.height = h;
|
|
823
824
|
|
|
824
825
|
if (!onlyH && !/%$/.test(w)) {
|
|
825
|
-
contextVideo._cover.style.width =
|
|
826
|
+
contextVideo._cover.style.width = w;
|
|
826
827
|
contextVideo._container.style.width = '';
|
|
827
828
|
}
|
|
828
829
|
|
|
@@ -119,25 +119,32 @@ export default {
|
|
|
119
119
|
},
|
|
120
120
|
|
|
121
121
|
on: function (contextAnchor, update) {
|
|
122
|
+
const anchorPlugin = this.plugins.anchor;
|
|
123
|
+
|
|
122
124
|
if (!update) {
|
|
123
|
-
|
|
125
|
+
anchorPlugin.init.call(this, contextAnchor);
|
|
124
126
|
contextAnchor.anchorText.value = this.getSelection().toString().trim();
|
|
125
127
|
contextAnchor.newWindowCheck.checked = this.options.linkTargetNewWindow;
|
|
126
128
|
} else if (contextAnchor.linkAnchor) {
|
|
127
129
|
this.context.dialog.updateModal = true;
|
|
128
130
|
const href = this.options.linkNoPrefix ? contextAnchor.linkAnchor.href.replace(contextAnchor.linkAnchor.origin + '/', '') : contextAnchor.linkAnchor.href;
|
|
129
|
-
contextAnchor.linkValue = contextAnchor.preview.textContent = contextAnchor.urlInput.value =
|
|
131
|
+
contextAnchor.linkValue = contextAnchor.preview.textContent = contextAnchor.urlInput.value = anchorPlugin.selfPathBookmark.call(this, href) ? href.substr(href.lastIndexOf('#')) : href;
|
|
130
132
|
contextAnchor.anchorText.value = contextAnchor.linkAnchor.textContent || contextAnchor.linkAnchor.getAttribute('alt');
|
|
131
133
|
contextAnchor.newWindowCheck.checked = (/_blank/i.test(contextAnchor.linkAnchor.target) ? true : false);
|
|
132
134
|
contextAnchor.downloadCheck.checked = contextAnchor.linkAnchor.download;
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
this.context.anchor.callerContext = contextAnchor;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
anchorPlugin.setRel.call(this, contextAnchor, (update && contextAnchor.linkAnchor) ? contextAnchor.linkAnchor.rel : contextAnchor.defaultRel);
|
|
139
|
+
anchorPlugin.setLinkPreview.call(this, contextAnchor, contextAnchor.linkValue);
|
|
138
140
|
this.plugins.selectMenu.on.call(this, contextAnchor.callerName, this.plugins.anchor.setHeaderBookmark);
|
|
139
141
|
},
|
|
140
142
|
|
|
143
|
+
selfPathBookmark: function(path) {
|
|
144
|
+
const href = this._w.location.href.replace(/\/$/, '');
|
|
145
|
+
return path.indexOf('#') === 0 || (path.indexOf(href) === 0 && path.indexOf('#') === (href.indexOf("#") === -1 ? href.length : href.substr(0, href.indexOf("#")).length));
|
|
146
|
+
},
|
|
147
|
+
|
|
141
148
|
_closeRelMenu: null,
|
|
142
149
|
toggleRelList: function (contextAnchor, show) {
|
|
143
150
|
if (!show) {
|
|
@@ -278,13 +285,13 @@ export default {
|
|
|
278
285
|
const value = e.target.value.trim();
|
|
279
286
|
this.plugins.anchor.setLinkPreview.call(this, contextAnchor, value);
|
|
280
287
|
|
|
281
|
-
if (
|
|
288
|
+
if (this.plugins.anchor.selfPathBookmark.call(this, value)) this.plugins.anchor.createHeaderList.call(this, contextAnchor, this.context.selectMenu.callerContext, value);
|
|
282
289
|
else this.plugins.selectMenu.close.call(this, this.context.selectMenu.callerContext);
|
|
283
290
|
},
|
|
284
291
|
|
|
285
292
|
onFocusUrlInput: function (contextAnchor, contextLink) {
|
|
286
293
|
const value = contextAnchor.urlInput.value;
|
|
287
|
-
if (
|
|
294
|
+
if (this.plugins.anchor.selfPathBookmark.call(this, value)) this.plugins.anchor.createHeaderList.call(this, contextAnchor, contextLink, value);
|
|
288
295
|
},
|
|
289
296
|
|
|
290
297
|
onBlurUrlInput: function (contextList) {
|
|
@@ -297,9 +304,9 @@ export default {
|
|
|
297
304
|
const noPrefix = this.options.linkNoPrefix;
|
|
298
305
|
const reservedProtocol = /^(mailto\:|tel\:|sms\:|https*\:\/\/|#)/.test(value);
|
|
299
306
|
const sameProtocol = !protocol ? false : this._w.RegExp('^' + value.substr(0, protocol.length)).test(protocol);
|
|
300
|
-
context.linkValue = preview.textContent = !value ? '' : noPrefix ? value : (protocol && !reservedProtocol && !sameProtocol) ? protocol + value : reservedProtocol ? value : /^www\./.test(value) ? 'http://' + value : this.context.anchor.host + (/^\//.test(value) ? '' : '/') + value;
|
|
307
|
+
value = context.linkValue = preview.textContent = !value ? '' : noPrefix ? value : (protocol && !reservedProtocol && !sameProtocol) ? protocol + value : reservedProtocol ? value : /^www\./.test(value) ? 'http://' + value : this.context.anchor.host + (/^\//.test(value) ? '' : '/') + value;
|
|
301
308
|
|
|
302
|
-
if (
|
|
309
|
+
if (this.plugins.anchor.selfPathBookmark.call(this, value)) {
|
|
303
310
|
context.bookmark.style.display = 'block';
|
|
304
311
|
this.util.addClass(context.bookmarkButton, 'active');
|
|
305
312
|
} else {
|
|
@@ -307,7 +314,7 @@ export default {
|
|
|
307
314
|
this.util.removeClass(context.bookmarkButton, 'active');
|
|
308
315
|
}
|
|
309
316
|
|
|
310
|
-
if (
|
|
317
|
+
if (!this.plugins.anchor.selfPathBookmark.call(this, value) && context.downloadCheck.checked) {
|
|
311
318
|
context.download.style.display = 'block';
|
|
312
319
|
} else {
|
|
313
320
|
context.download.style.display = 'none';
|
|
@@ -323,7 +330,7 @@ export default {
|
|
|
323
330
|
|
|
324
331
|
updateAnchor: function (anchor, url, alt, contextAnchor, notText) {
|
|
325
332
|
// download
|
|
326
|
-
if (
|
|
333
|
+
if (!this.plugins.anchor.selfPathBookmark.call(this, url) && contextAnchor.downloadCheck.checked) {
|
|
327
334
|
anchor.setAttribute('download', alt || url);
|
|
328
335
|
} else {
|
|
329
336
|
anchor.removeAttribute('download');
|
|
@@ -356,7 +363,7 @@ export default {
|
|
|
356
363
|
const anchorText = anchor.value.length === 0 ? url : anchor.value;
|
|
357
364
|
|
|
358
365
|
const oA = contextAnchor.linkAnchor || this.util.createElement('A');
|
|
359
|
-
this.plugins.anchor.updateAnchor(oA, url, anchorText, contextAnchor, notText);
|
|
366
|
+
this.plugins.anchor.updateAnchor.call(this, oA, url, anchorText, contextAnchor, notText);
|
|
360
367
|
|
|
361
368
|
contextAnchor.linkValue = contextAnchor.preview.textContent = contextAnchor.urlInput.value = contextAnchor.anchorText.value = '';
|
|
362
369
|
|
|
@@ -365,7 +372,7 @@ export default {
|
|
|
365
372
|
|
|
366
373
|
onClick_bookmarkButton: function (contextAnchor) {
|
|
367
374
|
let url = contextAnchor.urlInput.value;
|
|
368
|
-
if (
|
|
375
|
+
if (this.plugins.anchor.selfPathBookmark.call(this, url)) {
|
|
369
376
|
url = url.substr(1);
|
|
370
377
|
contextAnchor.bookmark.style.display = 'none';
|
|
371
378
|
this.util.removeClass(contextAnchor.bookmarkButton, 'active');
|
|
@@ -61,7 +61,7 @@ export default {
|
|
|
61
61
|
*/
|
|
62
62
|
active: function (element) {
|
|
63
63
|
if (!element) {
|
|
64
|
-
this.util.changeTxt(this.context.fontSize.targetText, this.hasFocus ? this.wwComputedStyle.fontSize : this.lang.toolbar.fontSize);
|
|
64
|
+
this.util.changeTxt(this.context.fontSize.targetText, this.hasFocus ? (this.options.__defaultFontSize || this.wwComputedStyle.fontSize) : this.lang.toolbar.fontSize);
|
|
65
65
|
} else if (element.style && element.style.fontSize.length > 0) {
|
|
66
66
|
this.util.changeTxt(this.context.fontSize.targetText, element.style.fontSize);
|
|
67
67
|
return true;
|
|
@@ -65,11 +65,7 @@ export default {
|
|
|
65
65
|
const icon = button.firstElementChild;
|
|
66
66
|
const util = this.util;
|
|
67
67
|
|
|
68
|
-
if (
|
|
69
|
-
button.removeAttribute('data-focus');
|
|
70
|
-
util.changeElement(icon, this.context.list.icons.number);
|
|
71
|
-
util.removeClass(button, 'active');
|
|
72
|
-
} else if (util.isList(element)) {
|
|
68
|
+
if (util.isList(element)) {
|
|
73
69
|
const nodeName = element.nodeName;
|
|
74
70
|
button.setAttribute('data-focus', nodeName);
|
|
75
71
|
util.addClass(button, 'active');
|
|
@@ -80,6 +76,10 @@ export default {
|
|
|
80
76
|
}
|
|
81
77
|
|
|
82
78
|
return true;
|
|
79
|
+
} else {
|
|
80
|
+
button.removeAttribute('data-focus');
|
|
81
|
+
util.changeElement(icon, this.context.list.icons.number);
|
|
82
|
+
util.removeClass(button, 'active');
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
return false;
|
|
@@ -234,6 +234,14 @@ export default {
|
|
|
234
234
|
|
|
235
235
|
newCell = util.createElement('LI');
|
|
236
236
|
util.copyFormatAttributes(newCell, fTag);
|
|
237
|
+
|
|
238
|
+
if (i === 0 && originRange.sc === fTag) {
|
|
239
|
+
originRange.sc = newCell;
|
|
240
|
+
}
|
|
241
|
+
if (i === len - 1 && originRange.ec === fTag) {
|
|
242
|
+
originRange.ec = newCell;
|
|
243
|
+
}
|
|
244
|
+
|
|
237
245
|
if (util.isComponent(fTag)) {
|
|
238
246
|
const isHR = /^HR$/i.test(fTag.nodeName);
|
|
239
247
|
if (!isHR) newCell.innerHTML = '<br>';
|
|
@@ -12,7 +12,9 @@ export default {
|
|
|
12
12
|
display: 'submenu',
|
|
13
13
|
add: function (core, targetElement) {
|
|
14
14
|
const context = core.context;
|
|
15
|
-
context.template = {
|
|
15
|
+
context.template = {
|
|
16
|
+
selectedIndex: -1
|
|
17
|
+
};
|
|
16
18
|
|
|
17
19
|
/** set submenu */
|
|
18
20
|
let templateDiv = this.setSubmenu(core);
|
|
@@ -55,7 +57,8 @@ export default {
|
|
|
55
57
|
e.preventDefault();
|
|
56
58
|
e.stopPropagation();
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
this.context.template.selectedIndex = e.target.getAttribute('data-value') * 1;
|
|
61
|
+
const temp = this.options.templates[this.context.template.selectedIndex];
|
|
59
62
|
|
|
60
63
|
if (temp.html) {
|
|
61
64
|
this.setContents(temp.html);
|