suneditor 2.41.2 → 2.43.0
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 +116 -28
- 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 +27 -7
- package/src/assets/defaultIcons.js +2 -0
- package/src/lang/Lang.d.ts +3 -1
- package/src/lang/ckb.js +2 -0
- package/src/lang/da.js +2 -0
- package/src/lang/de.js +2 -0
- package/src/lang/en.js +2 -0
- package/src/lang/es.js +2 -0
- package/src/lang/fr.js +10 -8
- package/src/lang/he.js +2 -0
- package/src/lang/it.js +2 -0
- package/src/lang/ja.js +2 -0
- package/src/lang/ko.js +2 -0
- package/src/lang/lv.js +2 -0
- package/src/lang/nl.js +2 -0
- package/src/lang/pl.js +2 -0
- package/src/lang/pt_br.js +2 -0
- package/src/lang/ro.js +2 -0
- package/src/lang/ru.js +2 -0
- package/src/lang/se.js +2 -0
- package/src/lang/ua.js +2 -0
- package/src/lang/zh_cn.js +3 -1
- package/src/lib/constructor.js +68 -16
- package/src/lib/context.js +5 -1
- package/src/lib/core.d.ts +88 -12
- package/src/lib/core.js +789 -212
- package/src/lib/util.d.ts +24 -1
- package/src/lib/util.js +105 -18
- package/src/options.d.ts +79 -9
- package/src/plugins/dialog/audio.js +5 -5
- package/src/plugins/dialog/image.js +30 -20
- package/src/plugins/dialog/link.js +1 -0
- package/src/plugins/dialog/video.js +16 -15
- package/src/plugins/fileBrowser/imageGallery.js +2 -3
- package/src/plugins/modules/_anchor.js +24 -15
- package/src/plugins/modules/component.d.ts +1 -1
- package/src/plugins/modules/fileBrowser.js +6 -1
- package/src/plugins/modules/fileManager.js +1 -3
- package/src/plugins/modules/resizing.js +11 -6
- package/src/plugins/submenu/align.js +32 -27
- package/src/plugins/submenu/font.js +1 -1
- package/src/plugins/submenu/fontSize.js +1 -1
- package/src/plugins/submenu/horizontalRule.js +19 -25
- package/src/plugins/submenu/list.js +13 -5
- package/src/plugins/submenu/template.js +5 -2
package/src/lib/util.d.ts
CHANGED
|
@@ -263,6 +263,14 @@ declare interface util {
|
|
|
263
263
|
*/
|
|
264
264
|
getArrayItem(array: any[] | HTMLCollection | NodeList, validation: Function | null, multi: boolean): any[] | Node | null;
|
|
265
265
|
|
|
266
|
+
/**
|
|
267
|
+
* @description Check if an array contains an element
|
|
268
|
+
* @param {Array|HTMLCollection|NodeList} array element array
|
|
269
|
+
* @param {Node} element The element to find index
|
|
270
|
+
* @returns {Boolean}
|
|
271
|
+
*/
|
|
272
|
+
arrayIncludes(array: any[] | HTMLCollection | NodeList, element: Node): boolean;
|
|
273
|
+
|
|
266
274
|
/**
|
|
267
275
|
* @description Get the index of the argument value in the element array
|
|
268
276
|
* @param array element array
|
|
@@ -534,14 +542,21 @@ declare interface util {
|
|
|
534
542
|
*/
|
|
535
543
|
toggleClass(element: Element, className: string): boolean | undefined;
|
|
536
544
|
|
|
545
|
+
/**
|
|
546
|
+
* @description Checks if element can't be easily enabled
|
|
547
|
+
* @param {Element} element Element to check for
|
|
548
|
+
*/
|
|
549
|
+
isImportantDisabled(element: Element): boolean;
|
|
550
|
+
|
|
537
551
|
/**
|
|
538
552
|
* @description In the predefined code view mode, the buttons except the executable button are changed to the 'disabled' state.
|
|
539
553
|
* core.codeViewDisabledButtons (An array of buttons whose class name is not "se-code-view-enabled")
|
|
540
554
|
* core.resizingDisabledButtons (An array of buttons whose class name is not "se-resizing-enabled")
|
|
541
555
|
* @param disabled Disabled value
|
|
542
556
|
* @param buttonList Button array
|
|
557
|
+
* @param important If priveleged mode should be used (Necessary to switch importantDisabled buttons)
|
|
543
558
|
*/
|
|
544
|
-
setDisabledButtons(disabled: boolean, buttonList: Element[] | HTMLCollection | NodeList): void;
|
|
559
|
+
setDisabledButtons(disabled: boolean, buttonList: Element[] | HTMLCollection | NodeList, important: Boolean): void;
|
|
545
560
|
|
|
546
561
|
/**
|
|
547
562
|
* @description Delete argumenu value element
|
|
@@ -624,6 +639,14 @@ declare interface util {
|
|
|
624
639
|
* @returns
|
|
625
640
|
*/
|
|
626
641
|
createTagsWhitelist(list: string): RegExp;
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* @description Create blacklist RegExp object.
|
|
645
|
+
* Return RegExp format: new RegExp("<\\/?\\b(?:" + list + ")\\b[^>^<]*+>", "gi")
|
|
646
|
+
* @param list Tags list ("br|p|div|pre...")
|
|
647
|
+
* @returns
|
|
648
|
+
*/
|
|
649
|
+
createTagsBlacklist(list: string): RegExp;
|
|
627
650
|
}
|
|
628
651
|
|
|
629
652
|
export default util;
|
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) return false;
|
|
64
67
|
if (typeof text !== 'string') text = text.textContent;
|
|
65
68
|
return text === '' || this.onlyZeroWidthRegExp.test(text);
|
|
66
69
|
},
|
|
@@ -92,6 +95,29 @@ const util = {
|
|
|
92
95
|
}
|
|
93
96
|
},
|
|
94
97
|
|
|
98
|
+
/**
|
|
99
|
+
* @description Object.values
|
|
100
|
+
* @param {Object} 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
|
+
*/
|
|
113
|
+
camelToKebabCase: function (param) {
|
|
114
|
+
if (typeof param === 'string') {
|
|
115
|
+
return param.replace(/[A-Z]/g, function (letter) { return "-" + letter.toLowerCase(); });
|
|
116
|
+
} else {
|
|
117
|
+
return param.map(function(str) { return util.camelToKebabCase(str); });
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
|
|
95
121
|
/**
|
|
96
122
|
* @description Create Element node
|
|
97
123
|
* @param {String} elementName Element name
|
|
@@ -551,6 +577,21 @@ const util = {
|
|
|
551
577
|
return !multi ? null : arr;
|
|
552
578
|
},
|
|
553
579
|
|
|
580
|
+
/**
|
|
581
|
+
* @description Check if an array contains an element
|
|
582
|
+
* @param {Array|HTMLCollection|NodeList} array element array
|
|
583
|
+
* @param {Node} element The element to check for
|
|
584
|
+
* @returns {Boolean}
|
|
585
|
+
*/
|
|
586
|
+
arrayIncludes: function(array, element) {
|
|
587
|
+
for (let i = 0; i < array.length; i++) {
|
|
588
|
+
if (array[i] === element) {
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return false;
|
|
593
|
+
},
|
|
594
|
+
|
|
554
595
|
/**
|
|
555
596
|
* @description Get the index of the argument value in the element array
|
|
556
597
|
* @param {Array|HTMLCollection|NodeList} array element array
|
|
@@ -1173,16 +1214,33 @@ const util = {
|
|
|
1173
1214
|
return result;
|
|
1174
1215
|
},
|
|
1175
1216
|
|
|
1217
|
+
/**
|
|
1218
|
+
* @description Checks if element can't be easily enabled
|
|
1219
|
+
* @param {Element} element Element to check for
|
|
1220
|
+
*/
|
|
1221
|
+
isImportantDisabled: function (element) {
|
|
1222
|
+
return element.hasAttribute('data-important-disabled');
|
|
1223
|
+
},
|
|
1224
|
+
|
|
1176
1225
|
/**
|
|
1177
1226
|
* @description In the predefined code view mode, the buttons except the executable button are changed to the 'disabled' state.
|
|
1178
1227
|
* core.codeViewDisabledButtons (An array of buttons whose class name is not "se-code-view-enabled")
|
|
1179
1228
|
* core.resizingDisabledButtons (An array of buttons whose class name is not "se-resizing-enabled")
|
|
1180
1229
|
* @param {Boolean} disabled Disabled value
|
|
1181
1230
|
* @param {Array|HTMLCollection|NodeList} buttonList Button array
|
|
1231
|
+
* @param {Boolean} important If priveleged mode should be used (Necessary to switch importantDisabled buttons)
|
|
1182
1232
|
*/
|
|
1183
|
-
setDisabledButtons: function (disabled, buttonList) {
|
|
1233
|
+
setDisabledButtons: function (disabled, buttonList, important) {
|
|
1184
1234
|
for (let i = 0, len = buttonList.length; i < len; i++) {
|
|
1185
|
-
buttonList[i]
|
|
1235
|
+
let button = buttonList[i];
|
|
1236
|
+
if (important || !this.isImportantDisabled(button)) button.disabled = disabled;
|
|
1237
|
+
if (important) {
|
|
1238
|
+
if (disabled) {
|
|
1239
|
+
button.setAttribute('data-important-disabled', '');
|
|
1240
|
+
} else {
|
|
1241
|
+
button.removeAttribute('data-important-disabled');
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1186
1244
|
}
|
|
1187
1245
|
},
|
|
1188
1246
|
|
|
@@ -1594,7 +1652,7 @@ const util = {
|
|
|
1594
1652
|
*/
|
|
1595
1653
|
htmlRemoveWhiteSpace: function (html) {
|
|
1596
1654
|
if (!html) return '';
|
|
1597
|
-
return html.trim().replace(/<\/?(?!strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code|summary)[^>^<]+>\s+(?=<)/ig, function (m) { return m.
|
|
1655
|
+
return html.trim().replace(/<\/?(?!strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code|summary)[^>^<]+>\s+(?=<)/ig, function (m) { return m.replace(/\n/g, '').replace(/\s+/, ' '); });
|
|
1598
1656
|
},
|
|
1599
1657
|
|
|
1600
1658
|
/**
|
|
@@ -1671,17 +1729,28 @@ const util = {
|
|
|
1671
1729
|
* @returns {RegExp}
|
|
1672
1730
|
*/
|
|
1673
1731
|
createTagsWhitelist: function (list) {
|
|
1674
|
-
return new RegExp('<\\/?\\b(?!\\b' + list.replace(/\|/g, '\\b|\\b') + '\\b)[^>]*>', 'gi');
|
|
1732
|
+
return new RegExp('<\\/?\\b(?!\\b' + (list || '').replace(/\|/g, '\\b|\\b') + '\\b)[^>]*>', 'gi');
|
|
1733
|
+
},
|
|
1734
|
+
|
|
1735
|
+
/**
|
|
1736
|
+
* @description Create blacklist RegExp object.
|
|
1737
|
+
* Return RegExp format: new RegExp("<\\/?\\b(?:" + list + ")\\b[^>^<]*+>", "gi")
|
|
1738
|
+
* @param {String} list Tags list ("br|p|div|pre...")
|
|
1739
|
+
* @returns {RegExp}
|
|
1740
|
+
*/
|
|
1741
|
+
createTagsBlacklist: function (list) {
|
|
1742
|
+
return new RegExp('<\\/?\\b(?:\\b' + (list || '^').replace(/\|/g, '\\b|\\b') + '\\b)[^>]*>', 'gi');
|
|
1675
1743
|
},
|
|
1676
1744
|
|
|
1677
1745
|
/**
|
|
1678
1746
|
* @description Fix tags that do not fit the editor format.
|
|
1679
1747
|
* @param {Element} documentFragment Document fragment "DOCUMENT_FRAGMENT_NODE" (nodeType === 11)
|
|
1680
1748
|
* @param {RegExp} htmlCheckWhitelistRegExp Editor tags whitelist (core._htmlCheckWhitelistRegExp)
|
|
1749
|
+
* @param {RegExp} htmlCheckBlacklistRegExp Editor tags blacklist (core._htmlCheckBlacklistRegExp)
|
|
1681
1750
|
* @param {Boolean} lowLevelCheck Row level check
|
|
1682
1751
|
* @private
|
|
1683
1752
|
*/
|
|
1684
|
-
_consistencyCheckOfHTML: function (documentFragment, htmlCheckWhitelistRegExp, lowLevelCheck) {
|
|
1753
|
+
_consistencyCheckOfHTML: function (documentFragment, htmlCheckWhitelistRegExp, htmlCheckBlacklistRegExp, lowLevelCheck) {
|
|
1685
1754
|
/**
|
|
1686
1755
|
* It is can use ".children(util.getListChildren)" to exclude text nodes, but "documentFragment.children" is not supported in IE.
|
|
1687
1756
|
* So check the node type and exclude the text no (current.nodeType !== 1)
|
|
@@ -1690,17 +1759,20 @@ const util = {
|
|
|
1690
1759
|
|
|
1691
1760
|
// wrong position
|
|
1692
1761
|
const wrongTags = this.getListChildNodes(documentFragment, function (current) {
|
|
1693
|
-
if (current.nodeType !== 1)
|
|
1762
|
+
if (current.nodeType !== 1) {
|
|
1763
|
+
if (this.isList(current.parentNode)) removeTags.push(current);
|
|
1764
|
+
return false;
|
|
1765
|
+
}
|
|
1694
1766
|
|
|
1695
1767
|
// white list
|
|
1696
|
-
if (!htmlCheckWhitelistRegExp.test(current.nodeName) && current.childNodes.length === 0 && this.isNotCheckingNode(current)) {
|
|
1768
|
+
if (htmlCheckBlacklistRegExp.test(current.nodeName) || (!htmlCheckWhitelistRegExp.test(current.nodeName) && current.childNodes.length === 0 && this.isNotCheckingNode(current))) {
|
|
1697
1769
|
removeTags.push(current);
|
|
1698
1770
|
return false;
|
|
1699
1771
|
}
|
|
1700
1772
|
|
|
1701
1773
|
const nrtag = !this.getParentElement(current, this.isNotCheckingNode);
|
|
1702
1774
|
// empty tags
|
|
1703
|
-
if ((!this.isTable(current) && !this.isListCell(current)) && (this.isFormatElement(current) || this.isRangeFormatElement(current) || this.isTextStyleElement(current)) && current.childNodes.length === 0 && nrtag) {
|
|
1775
|
+
if ((!this.isTable(current) && !this.isListCell(current) && !this.isAnchor(current)) && (this.isFormatElement(current) || this.isRangeFormatElement(current) || this.isTextStyleElement(current)) && current.childNodes.length === 0 && nrtag) {
|
|
1704
1776
|
emptyTags.push(current);
|
|
1705
1777
|
return false;
|
|
1706
1778
|
}
|
|
@@ -1736,8 +1808,17 @@ const util = {
|
|
|
1736
1808
|
t = wrongTags[i];
|
|
1737
1809
|
p = t.parentNode;
|
|
1738
1810
|
if (!p || !p.parentNode) continue;
|
|
1739
|
-
|
|
1740
|
-
|
|
1811
|
+
|
|
1812
|
+
if (this.getParentElement(t, this.isListCell)) {
|
|
1813
|
+
const cellChildren = t.childNodes;
|
|
1814
|
+
for (let j = cellChildren.length - 1; len >= 0; j--) {
|
|
1815
|
+
p.insertBefore(t, cellChildren[j]);
|
|
1816
|
+
}
|
|
1817
|
+
checkTags.push(t);
|
|
1818
|
+
} else {
|
|
1819
|
+
p.parentNode.insertBefore(t, p);
|
|
1820
|
+
checkTags.push(p);
|
|
1821
|
+
}
|
|
1741
1822
|
}
|
|
1742
1823
|
|
|
1743
1824
|
for (let i = 0, len = checkTags.length, t; i < len; i++) {
|
|
@@ -1753,17 +1834,23 @@ const util = {
|
|
|
1753
1834
|
|
|
1754
1835
|
for (let i = 0, len = wrongList.length, t, tp, children, p; i < len; i++) {
|
|
1755
1836
|
t = wrongList[i];
|
|
1837
|
+
p = t.parentNode;
|
|
1838
|
+
if (!p) continue;
|
|
1756
1839
|
|
|
1757
1840
|
tp = this.createElement('LI');
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1841
|
+
|
|
1842
|
+
if (this.isFormatElement(t)) {
|
|
1843
|
+
children = t.childNodes;
|
|
1844
|
+
while (children[0]) {
|
|
1845
|
+
tp.appendChild(children[0]);
|
|
1846
|
+
}
|
|
1847
|
+
p.insertBefore(tp, t);
|
|
1848
|
+
this.removeItem(t);
|
|
1849
|
+
} else {
|
|
1850
|
+
t = t.nextSibling;
|
|
1851
|
+
tp.appendChild(wrongList[i]);
|
|
1852
|
+
p.insertBefore(tp, t);
|
|
1761
1853
|
}
|
|
1762
|
-
|
|
1763
|
-
p = t.parentNode;
|
|
1764
|
-
if (!p) continue;
|
|
1765
|
-
p.insertBefore(tp, t);
|
|
1766
|
-
this.removeItem(t);
|
|
1767
1854
|
}
|
|
1768
1855
|
|
|
1769
1856
|
for (let i = 0, len = withoutFormatCells.length, t, f; i < len; i++) {
|
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
|
* ======
|
|
@@ -31,15 +35,15 @@ export interface SunEditorOptions {
|
|
|
31
35
|
/**
|
|
32
36
|
* Add tags to the default tags whitelist of editor.
|
|
33
37
|
*/
|
|
34
|
-
addTagsWhitelist?: string;
|
|
35
|
-
/**
|
|
36
|
-
* Whitelist of tags when pasting.
|
|
37
|
-
*/
|
|
38
|
-
pasteTagsWhitelist?: string;
|
|
38
|
+
addTagsWhitelist?: string | '*';
|
|
39
39
|
/**
|
|
40
40
|
* Blacklist of the editor default tags.
|
|
41
41
|
*/
|
|
42
42
|
tagsBlacklist?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Whitelist of tags when pasting.
|
|
45
|
+
*/
|
|
46
|
+
pasteTagsWhitelist?: string | '*';
|
|
43
47
|
/**
|
|
44
48
|
* Blacklist of tags when pasting.
|
|
45
49
|
*/
|
|
@@ -47,7 +51,11 @@ export interface SunEditorOptions {
|
|
|
47
51
|
/**
|
|
48
52
|
* Add attributes whitelist of tags that should be kept undeleted from the editor.
|
|
49
53
|
*/
|
|
50
|
-
attributesWhitelist?: Record<string, string>;
|
|
54
|
+
attributesWhitelist?: Record<string, string | '*'>;
|
|
55
|
+
/**
|
|
56
|
+
* Add attribute blacklist of tags that should be deleted in editor.
|
|
57
|
+
*/
|
|
58
|
+
attributesBlacklist?: Record<string, string | '*'>;
|
|
51
59
|
/**
|
|
52
60
|
* Layout
|
|
53
61
|
* ======
|
|
@@ -60,6 +68,13 @@ export interface SunEditorOptions {
|
|
|
60
68
|
* If true, the editor is set to RTL(Right To Left) mode.
|
|
61
69
|
*/
|
|
62
70
|
rtl?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Deletes other attributes except for the property set at the time of line break.
|
|
73
|
+
* If there is no value, no all attribute is deleted.
|
|
74
|
+
* @example 'class|style': Attributes other than "class" and "style" are deleted at line break.
|
|
75
|
+
* '*': All attributes are deleted at line break.
|
|
76
|
+
*/
|
|
77
|
+
lineAttrReset?: string;
|
|
63
78
|
/**
|
|
64
79
|
* Button List
|
|
65
80
|
*/
|
|
@@ -91,6 +106,10 @@ export interface SunEditorOptions {
|
|
|
91
106
|
* Allows the usage of HTML, HEAD, BODY tags and DOCTYPE declaration
|
|
92
107
|
*/
|
|
93
108
|
fullPage?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Attributes of the iframe.
|
|
111
|
+
*/
|
|
112
|
+
iframeAttributes?: Record<string, string>;
|
|
94
113
|
/**
|
|
95
114
|
* Name of the CSS file(s) to apply inside the iframe.
|
|
96
115
|
*/
|
|
@@ -147,6 +166,16 @@ export interface SunEditorOptions {
|
|
|
147
166
|
* Displays the current node structure to resizingBar
|
|
148
167
|
*/
|
|
149
168
|
showPathLabel?: boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Enable/disable resize function of bottom resizing bar.
|
|
171
|
+
*/
|
|
172
|
+
resizeEnable?: boolean;
|
|
173
|
+
/**
|
|
174
|
+
* A custom HTML selector placing the resizing bar inside.
|
|
175
|
+
The class name of the element must be 'sun-editor'.
|
|
176
|
+
Element or querySelector argument.
|
|
177
|
+
*/
|
|
178
|
+
resizingBarContainer?: HTMLElement | string;
|
|
150
179
|
/**
|
|
151
180
|
* Character count
|
|
152
181
|
* ===============
|
|
@@ -196,8 +225,19 @@ export interface SunEditorOptions {
|
|
|
196
225
|
*/
|
|
197
226
|
maxHeight?: string;
|
|
198
227
|
/**
|
|
199
|
-
* Editing area
|
|
228
|
+
* Editing area
|
|
229
|
+
* ===================
|
|
200
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
|
+
*/
|
|
201
241
|
defaultStyle?: string;
|
|
202
242
|
/**
|
|
203
243
|
* Defining menu items
|
|
@@ -212,9 +252,13 @@ export interface SunEditorOptions {
|
|
|
212
252
|
*/
|
|
213
253
|
fontSize?: number[];
|
|
214
254
|
/**
|
|
215
|
-
*
|
|
255
|
+
* The font size unit
|
|
216
256
|
*/
|
|
217
257
|
fontSizeUnit?: string;
|
|
258
|
+
/**
|
|
259
|
+
* A list of drop-down options for the 'align' plugin.
|
|
260
|
+
*/
|
|
261
|
+
alignItems?: ('left' | 'center' | 'right' | 'justify')[];
|
|
218
262
|
/**
|
|
219
263
|
* Change default formatBlock array
|
|
220
264
|
*/
|
|
@@ -247,6 +291,10 @@ export interface SunEditorOptions {
|
|
|
247
291
|
* Choose whether the image height input is visible.
|
|
248
292
|
*/
|
|
249
293
|
imageHeightShow?: boolean;
|
|
294
|
+
/**
|
|
295
|
+
* Choose whether the image align radio buttons are visible.
|
|
296
|
+
*/
|
|
297
|
+
imageAlignShow?: boolean;
|
|
250
298
|
/**
|
|
251
299
|
* The default width size of the image frame
|
|
252
300
|
*/
|
|
@@ -296,7 +344,7 @@ export interface SunEditorOptions {
|
|
|
296
344
|
imageMultipleFile?: boolean;
|
|
297
345
|
/**
|
|
298
346
|
* Define the "accept" attribute of the input.
|
|
299
|
-
*
|
|
347
|
+
* @example "*" or ".jpg, .png .."
|
|
300
348
|
*/
|
|
301
349
|
imageAccept?: string;
|
|
302
350
|
/**
|
|
@@ -323,6 +371,10 @@ export interface SunEditorOptions {
|
|
|
323
371
|
* Choose whether the video height input is visible.
|
|
324
372
|
*/
|
|
325
373
|
videoHeightShow?: boolean;
|
|
374
|
+
/**
|
|
375
|
+
* Choose whether the video align radio buttons are visible.
|
|
376
|
+
*/
|
|
377
|
+
videoAlignShow?: boolean;
|
|
326
378
|
/**
|
|
327
379
|
* Choose whether the video ratio options is visible.
|
|
328
380
|
*/
|
|
@@ -455,6 +507,10 @@ export interface SunEditorOptions {
|
|
|
455
507
|
* Link
|
|
456
508
|
* =====
|
|
457
509
|
*/
|
|
510
|
+
/**
|
|
511
|
+
* Default checked value of the "Open in new window" checkbox.
|
|
512
|
+
*/
|
|
513
|
+
linkTargetNewWindow?: boolean;
|
|
458
514
|
/**
|
|
459
515
|
* Protocol for the links (if link has been added without any protocol this one will be used).
|
|
460
516
|
*/
|
|
@@ -467,6 +523,20 @@ export interface SunEditorOptions {
|
|
|
467
523
|
* Defines default "rel" attribute list of anchor tag.
|
|
468
524
|
*/
|
|
469
525
|
linkRelDefault?: {default?: string; check_new_window?: string; check_bookmark?: string;};
|
|
526
|
+
/**
|
|
527
|
+
* If true, disables the automatic prefixing of the host URL to the value of the link. default: false {Boolean}
|
|
528
|
+
*/
|
|
529
|
+
linkNoPrefix?: boolean;
|
|
530
|
+
/*
|
|
531
|
+
* HR
|
|
532
|
+
* =====
|
|
533
|
+
*/
|
|
534
|
+
/**
|
|
535
|
+
* Defines the hr items.
|
|
536
|
+
* "class" or "style" must be specified.
|
|
537
|
+
* @example [{name: "solid", class: "__se__xxx", style: "border-style: outset;"}]
|
|
538
|
+
*/
|
|
539
|
+
hrItems?: { name: string; class?: string; style?: string }[];
|
|
470
540
|
/**
|
|
471
541
|
* Key actions
|
|
472
542
|
* =====
|
|
@@ -454,10 +454,8 @@ export default {
|
|
|
454
454
|
this.plugins.audio._setTagAttrs.call(this, element);
|
|
455
455
|
|
|
456
456
|
// find component element
|
|
457
|
-
const existElement = this.util.
|
|
458
|
-
this.util.
|
|
459
|
-
return this.isWysiwygDiv(current.parentNode);
|
|
460
|
-
}.bind(this.util));
|
|
457
|
+
const existElement = (this.util.isRangeFormatElement(element.parentNode) || this.util.isWysiwygDiv(element.parentNode)) ?
|
|
458
|
+
element : this.util.getFormatElement(element) || element;
|
|
461
459
|
|
|
462
460
|
// clone element
|
|
463
461
|
const prevElement = element;
|
|
@@ -466,7 +464,9 @@ export default {
|
|
|
466
464
|
const container = this.plugins.component.set_container.call(this, cover, 'se-audio-container');
|
|
467
465
|
|
|
468
466
|
try {
|
|
469
|
-
if (this.util.
|
|
467
|
+
if (this.util.isListCell(existElement) || this.util.isFormatElement(existElement)) {
|
|
468
|
+
prevElement.parentNode.replaceChild(container, prevElement);
|
|
469
|
+
} else if (this.util.isFormatElement(existElement) && existElement.childNodes.length > 0) {
|
|
470
470
|
existElement.parentNode.insertBefore(container, existElement);
|
|
471
471
|
this.util.removeItem(prevElement);
|
|
472
472
|
// clean format tag
|
|
@@ -53,6 +53,7 @@ export default {
|
|
|
53
53
|
_resizing: options.imageResizing,
|
|
54
54
|
_resizeDotHide: !options.imageHeightShow,
|
|
55
55
|
_rotation: options.imageRotation,
|
|
56
|
+
_alignHide: !options.imageAlignShow,
|
|
56
57
|
_onlyPercentage: options.imageSizeOnlyPercentage,
|
|
57
58
|
_ratio: false,
|
|
58
59
|
_ratioX: 1,
|
|
@@ -203,7 +204,7 @@ export default {
|
|
|
203
204
|
core.context.anchor.forms.innerHTML +
|
|
204
205
|
'</div>' +
|
|
205
206
|
'<div class="se-dialog-footer">' +
|
|
206
|
-
'<div>' +
|
|
207
|
+
'<div' + (option.imageAlignShow ? '' : ' style="display: none"') + '>' +
|
|
207
208
|
'<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="none" checked>' + lang.dialogBox.basic + '</label>' +
|
|
208
209
|
'<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="left">' + lang.dialogBox.left + '</label>' +
|
|
209
210
|
'<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="center">' + lang.dialogBox.center + '</label>' +
|
|
@@ -375,7 +376,7 @@ export default {
|
|
|
375
376
|
imagePlugin.submitAction.call(this, this.context.image.imgInputFile.files);
|
|
376
377
|
} else if (contextImage.imgUrlFile && contextImage._v_src._linkValue.length > 0) {
|
|
377
378
|
this.showLoading();
|
|
378
|
-
imagePlugin.onRender_imgUrl.call(this);
|
|
379
|
+
imagePlugin.onRender_imgUrl.call(this, contextImage._v_src._linkValue);
|
|
379
380
|
}
|
|
380
381
|
} catch (error) {
|
|
381
382
|
this.closeLoading();
|
|
@@ -427,6 +428,7 @@ export default {
|
|
|
427
428
|
inputHeight: contextImage.inputY.value,
|
|
428
429
|
align: contextImage._align,
|
|
429
430
|
isUpdate: this.context.dialog.updateModal,
|
|
431
|
+
alt: contextImage._altText,
|
|
430
432
|
element: contextImage._element
|
|
431
433
|
};
|
|
432
434
|
|
|
@@ -479,7 +481,7 @@ export default {
|
|
|
479
481
|
}
|
|
480
482
|
this.plugins.fileManager.upload.call(this, imageUploadUrl, this.options.imageUploadHeader, formData, this.plugins.image.callBack_imgUpload.bind(this, info), this.functions.onImageUploadError);
|
|
481
483
|
} else { // base64
|
|
482
|
-
this.plugins.image.setup_reader.call(this, files, info.anchor, info.inputWidth, info.inputHeight, info.align, filesLen, info.isUpdate);
|
|
484
|
+
this.plugins.image.setup_reader.call(this, files, info.anchor, info.inputWidth, info.inputHeight, info.align, info.alt, filesLen, info.isUpdate);
|
|
483
485
|
}
|
|
484
486
|
},
|
|
485
487
|
|
|
@@ -505,14 +507,14 @@ export default {
|
|
|
505
507
|
this.plugins.image.update_src.call(this, fileList[i].url, info.element, file);
|
|
506
508
|
break;
|
|
507
509
|
} else {
|
|
508
|
-
this.plugins.image.create_image.call(this, fileList[i].url, info.anchor, info.inputWidth, info.inputHeight, info.align, file);
|
|
510
|
+
this.plugins.image.create_image.call(this, fileList[i].url, info.anchor, info.inputWidth, info.inputHeight, info.align, file, info.alt);
|
|
509
511
|
}
|
|
510
512
|
}
|
|
511
513
|
|
|
512
514
|
this.closeLoading();
|
|
513
515
|
},
|
|
514
516
|
|
|
515
|
-
setup_reader: function (files, anchor, width, height, align, filesLen, isUpdate) {
|
|
517
|
+
setup_reader: function (files, anchor, width, height, align, alt, filesLen, isUpdate) {
|
|
516
518
|
try {
|
|
517
519
|
this.context.image.base64RenderIndex = filesLen;
|
|
518
520
|
const wFileReader = this._w.FileReader;
|
|
@@ -528,7 +530,7 @@ export default {
|
|
|
528
530
|
filesStack[index] = { result: reader.result, file: file };
|
|
529
531
|
|
|
530
532
|
if (--this.context.image.base64RenderIndex === 0) {
|
|
531
|
-
this.plugins.image.onRender_imgBase64.call(this, update, filesStack, updateElement, anchor, width, height, align);
|
|
533
|
+
this.plugins.image.onRender_imgBase64.call(this, update, filesStack, updateElement, anchor, width, height, align, alt);
|
|
532
534
|
this.closeLoading();
|
|
533
535
|
}
|
|
534
536
|
}.bind(this, reader, isUpdate, this.context.image._element, file, i);
|
|
@@ -541,7 +543,7 @@ export default {
|
|
|
541
543
|
}
|
|
542
544
|
},
|
|
543
545
|
|
|
544
|
-
onRender_imgBase64: function (update, filesStack, updateElement, anchor, width, height, align) {
|
|
546
|
+
onRender_imgBase64: function (update, filesStack, updateElement, anchor, width, height, align, alt) {
|
|
545
547
|
const updateMethod = this.plugins.image.update_src;
|
|
546
548
|
const createMethod = this.plugins.image.create_image;
|
|
547
549
|
|
|
@@ -551,19 +553,20 @@ export default {
|
|
|
551
553
|
this.context.image._element.setAttribute('data-file-size', filesStack[i].file.size);
|
|
552
554
|
updateMethod.call(this, filesStack[i].result, updateElement, filesStack[i].file);
|
|
553
555
|
} else {
|
|
554
|
-
createMethod.call(this, filesStack[i].result, anchor, width, height, align, filesStack[i].file);
|
|
556
|
+
createMethod.call(this, filesStack[i].result, anchor, width, height, align, filesStack[i].file, alt);
|
|
555
557
|
}
|
|
556
558
|
}
|
|
557
559
|
},
|
|
558
560
|
|
|
559
|
-
onRender_imgUrl: function () {
|
|
561
|
+
onRender_imgUrl: function (url) {
|
|
562
|
+
if (!url) url = this.context.image._v_src._linkValue;
|
|
563
|
+
if (!url) return false;
|
|
560
564
|
const contextImage = this.context.image;
|
|
561
|
-
if (contextImage._v_src._linkValue.length === 0) return false;
|
|
562
565
|
|
|
563
566
|
try {
|
|
564
|
-
const file = {name:
|
|
565
|
-
if (this.context.dialog.updateModal) this.plugins.image.update_src.call(this,
|
|
566
|
-
else this.plugins.image.create_image.call(this,
|
|
567
|
+
const file = {name: url.split('/').pop(), size: 0};
|
|
568
|
+
if (this.context.dialog.updateModal) this.plugins.image.update_src.call(this, url, contextImage._element, file);
|
|
569
|
+
else this.plugins.image.create_image.call(this, url, this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true), contextImage.inputX.value, contextImage.inputY.value, contextImage._align, file, contextImage._altText);
|
|
567
570
|
} catch (e) {
|
|
568
571
|
throw Error('[SUNEDITOR.image.URLRendering.fail] cause : "' + e.message + '"');
|
|
569
572
|
} finally {
|
|
@@ -637,14 +640,14 @@ export default {
|
|
|
637
640
|
this.plugins.fileManager.resetInfo.call(this, 'image', this.functions.onImageUpload);
|
|
638
641
|
},
|
|
639
642
|
|
|
640
|
-
create_image: function (src, anchor, width, height, align, file) {
|
|
643
|
+
create_image: function (src, anchor, width, height, align, file, alt) {
|
|
641
644
|
const imagePlugin = this.plugins.image;
|
|
642
645
|
const contextImage = this.context.image;
|
|
643
646
|
this.context.resizing._resize_plugin = 'image';
|
|
644
647
|
|
|
645
648
|
let oImg = this.util.createElement('IMG');
|
|
646
649
|
oImg.src = src;
|
|
647
|
-
oImg.alt =
|
|
650
|
+
oImg.alt = alt;
|
|
648
651
|
oImg.setAttribute('data-rotate', '0');
|
|
649
652
|
anchor = imagePlugin.onRender_link.call(this, oImg, anchor);
|
|
650
653
|
|
|
@@ -746,8 +749,13 @@ export default {
|
|
|
746
749
|
// link
|
|
747
750
|
const anchor = this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true);
|
|
748
751
|
if (anchor) {
|
|
749
|
-
|
|
750
|
-
|
|
752
|
+
if (contextImage._linkElement !== anchor) {
|
|
753
|
+
contextImage._linkElement = anchor.cloneNode(false);
|
|
754
|
+
cover.insertBefore(this.plugins.image.onRender_link.call(this, imageEl, contextImage._linkElement), contextImage._caption);
|
|
755
|
+
this.util.removeItem(anchor);
|
|
756
|
+
} else {
|
|
757
|
+
contextImage._linkElement.setAttribute('data-image-link', 'image');
|
|
758
|
+
}
|
|
751
759
|
} else if (contextImage._linkElement !== null) {
|
|
752
760
|
const imageElement = imageEl;
|
|
753
761
|
imageElement.setAttribute('data-image-link', '');
|
|
@@ -755,7 +763,7 @@ export default {
|
|
|
755
763
|
const newEl = imageElement.cloneNode(true);
|
|
756
764
|
cover.removeChild(contextImage._linkElement);
|
|
757
765
|
cover.insertBefore(newEl, contextImage._caption);
|
|
758
|
-
imageEl = newEl;
|
|
766
|
+
contextImage._element = imageEl = newEl;
|
|
759
767
|
}
|
|
760
768
|
}
|
|
761
769
|
|
|
@@ -764,7 +772,9 @@ export default {
|
|
|
764
772
|
contextImage._element :
|
|
765
773
|
/^A$/i.test(contextImage._element.parentNode.nodeName) ? contextImage._element.parentNode : this.util.getFormatElement(contextImage._element) || contextImage._element;
|
|
766
774
|
|
|
767
|
-
if (this.util.
|
|
775
|
+
if (this.util.isListCell(existElement) || this.util.isFormatElement(existElement)) {
|
|
776
|
+
contextImage._element.parentNode.replaceChild(container, contextImage._element);
|
|
777
|
+
} else if (this.util.isFormatElement(existElement) && existElement.childNodes.length > 0) {
|
|
768
778
|
existElement.parentNode.insertBefore(container, existElement);
|
|
769
779
|
this.util.removeItem(contextImage._element);
|
|
770
780
|
// clean format tag
|
|
@@ -875,7 +885,7 @@ export default {
|
|
|
875
885
|
contextImage._v_src._linkValue = contextImage.previewSrc.textContent = contextImage.imgUrlFile.value = contextImage._element.src;
|
|
876
886
|
}
|
|
877
887
|
contextImage._altText = contextImage.altText.value = contextImage._element.alt;
|
|
878
|
-
contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="' + contextImage._align + '"]').checked = true;
|
|
888
|
+
(contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="' + contextImage._align + '"]') || contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="none"]')).checked = true;
|
|
879
889
|
contextImage._align = contextImage.modal.querySelector('input[name="suneditor_image_radio"]:checked').value;
|
|
880
890
|
contextImage._captionChecked = contextImage.captionCheckEl.checked = !!contextImage._caption;
|
|
881
891
|
|
|
@@ -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();
|