suneditor 2.41.3 → 2.42.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 +107 -24
- 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 +25 -6
- 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 +2 -0
- package/src/lib/constructor.js +50 -11
- package/src/lib/context.js +4 -1
- package/src/lib/core.d.ts +86 -11
- package/src/lib/core.js +555 -147
- package/src/lib/util.d.ts +24 -1
- package/src/lib/util.js +64 -15
- package/src/options.d.ts +63 -8
- package/src/plugins/dialog/audio.js +5 -5
- package/src/plugins/dialog/image.js +30 -20
- package/src/plugins/dialog/video.js +13 -13
- package/src/plugins/fileBrowser/imageGallery.js +2 -3
- package/src/plugins/modules/_anchor.js +6 -4
- 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/horizontalRule.js +19 -25
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
|
@@ -551,6 +551,21 @@ const util = {
|
|
|
551
551
|
return !multi ? null : arr;
|
|
552
552
|
},
|
|
553
553
|
|
|
554
|
+
/**
|
|
555
|
+
* @description Check if an array contains an element
|
|
556
|
+
* @param {Array|HTMLCollection|NodeList} array element array
|
|
557
|
+
* @param {Node} element The element to check for
|
|
558
|
+
* @returns {Boolean}
|
|
559
|
+
*/
|
|
560
|
+
arrayIncludes: function(array, element) {
|
|
561
|
+
for (let i = 0; i < array.length; i++) {
|
|
562
|
+
if (array[i] === element) {
|
|
563
|
+
return true;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return false;
|
|
567
|
+
},
|
|
568
|
+
|
|
554
569
|
/**
|
|
555
570
|
* @description Get the index of the argument value in the element array
|
|
556
571
|
* @param {Array|HTMLCollection|NodeList} array element array
|
|
@@ -1173,16 +1188,33 @@ const util = {
|
|
|
1173
1188
|
return result;
|
|
1174
1189
|
},
|
|
1175
1190
|
|
|
1191
|
+
/**
|
|
1192
|
+
* @description Checks if element can't be easily enabled
|
|
1193
|
+
* @param {Element} element Element to check for
|
|
1194
|
+
*/
|
|
1195
|
+
isImportantDisabled: function (element) {
|
|
1196
|
+
return element.hasAttribute('data-important-disabled');
|
|
1197
|
+
},
|
|
1198
|
+
|
|
1176
1199
|
/**
|
|
1177
1200
|
* @description In the predefined code view mode, the buttons except the executable button are changed to the 'disabled' state.
|
|
1178
1201
|
* core.codeViewDisabledButtons (An array of buttons whose class name is not "se-code-view-enabled")
|
|
1179
1202
|
* core.resizingDisabledButtons (An array of buttons whose class name is not "se-resizing-enabled")
|
|
1180
1203
|
* @param {Boolean} disabled Disabled value
|
|
1181
1204
|
* @param {Array|HTMLCollection|NodeList} buttonList Button array
|
|
1205
|
+
* @param {Boolean} important If priveleged mode should be used (Necessary to switch importantDisabled buttons)
|
|
1182
1206
|
*/
|
|
1183
|
-
setDisabledButtons: function (disabled, buttonList) {
|
|
1207
|
+
setDisabledButtons: function (disabled, buttonList, important) {
|
|
1184
1208
|
for (let i = 0, len = buttonList.length; i < len; i++) {
|
|
1185
|
-
buttonList[i]
|
|
1209
|
+
let button = buttonList[i];
|
|
1210
|
+
if (important || !this.isImportantDisabled(button)) button.disabled = disabled;
|
|
1211
|
+
if (important) {
|
|
1212
|
+
if (disabled) {
|
|
1213
|
+
button.setAttribute('data-important-disabled', '');
|
|
1214
|
+
} else {
|
|
1215
|
+
button.removeAttribute('data-important-disabled');
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1186
1218
|
}
|
|
1187
1219
|
},
|
|
1188
1220
|
|
|
@@ -1594,7 +1626,7 @@ const util = {
|
|
|
1594
1626
|
*/
|
|
1595
1627
|
htmlRemoveWhiteSpace: function (html) {
|
|
1596
1628
|
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.
|
|
1629
|
+
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
1630
|
},
|
|
1599
1631
|
|
|
1600
1632
|
/**
|
|
@@ -1671,17 +1703,28 @@ const util = {
|
|
|
1671
1703
|
* @returns {RegExp}
|
|
1672
1704
|
*/
|
|
1673
1705
|
createTagsWhitelist: function (list) {
|
|
1674
|
-
return new RegExp('<\\/?\\b(?!\\b' + list.replace(/\|/g, '\\b|\\b') + '\\b)[^>]*>', 'gi');
|
|
1706
|
+
return new RegExp('<\\/?\\b(?!\\b' + (list || '').replace(/\|/g, '\\b|\\b') + '\\b)[^>]*>', 'gi');
|
|
1707
|
+
},
|
|
1708
|
+
|
|
1709
|
+
/**
|
|
1710
|
+
* @description Create blacklist RegExp object.
|
|
1711
|
+
* Return RegExp format: new RegExp("<\\/?\\b(?:" + list + ")\\b[^>^<]*+>", "gi")
|
|
1712
|
+
* @param {String} list Tags list ("br|p|div|pre...")
|
|
1713
|
+
* @returns {RegExp}
|
|
1714
|
+
*/
|
|
1715
|
+
createTagsBlacklist: function (list) {
|
|
1716
|
+
return new RegExp('<\\/?\\b(?:\\b' + (list || '^').replace(/\|/g, '\\b|\\b') + '\\b)[^>]*>', 'gi');
|
|
1675
1717
|
},
|
|
1676
1718
|
|
|
1677
1719
|
/**
|
|
1678
1720
|
* @description Fix tags that do not fit the editor format.
|
|
1679
1721
|
* @param {Element} documentFragment Document fragment "DOCUMENT_FRAGMENT_NODE" (nodeType === 11)
|
|
1680
1722
|
* @param {RegExp} htmlCheckWhitelistRegExp Editor tags whitelist (core._htmlCheckWhitelistRegExp)
|
|
1723
|
+
* @param {RegExp} htmlCheckBlacklistRegExp Editor tags blacklist (core._htmlCheckBlacklistRegExp)
|
|
1681
1724
|
* @param {Boolean} lowLevelCheck Row level check
|
|
1682
1725
|
* @private
|
|
1683
1726
|
*/
|
|
1684
|
-
_consistencyCheckOfHTML: function (documentFragment, htmlCheckWhitelistRegExp, lowLevelCheck) {
|
|
1727
|
+
_consistencyCheckOfHTML: function (documentFragment, htmlCheckWhitelistRegExp, htmlCheckBlacklistRegExp, lowLevelCheck) {
|
|
1685
1728
|
/**
|
|
1686
1729
|
* It is can use ".children(util.getListChildren)" to exclude text nodes, but "documentFragment.children" is not supported in IE.
|
|
1687
1730
|
* So check the node type and exclude the text no (current.nodeType !== 1)
|
|
@@ -1693,14 +1736,14 @@ const util = {
|
|
|
1693
1736
|
if (current.nodeType !== 1) return false;
|
|
1694
1737
|
|
|
1695
1738
|
// white list
|
|
1696
|
-
if (!htmlCheckWhitelistRegExp.test(current.nodeName) && current.childNodes.length === 0 && this.isNotCheckingNode(current)) {
|
|
1739
|
+
if (htmlCheckBlacklistRegExp.test(current.nodeName) || (!htmlCheckWhitelistRegExp.test(current.nodeName) && current.childNodes.length === 0 && this.isNotCheckingNode(current))) {
|
|
1697
1740
|
removeTags.push(current);
|
|
1698
1741
|
return false;
|
|
1699
1742
|
}
|
|
1700
1743
|
|
|
1701
1744
|
const nrtag = !this.getParentElement(current, this.isNotCheckingNode);
|
|
1702
1745
|
// empty tags
|
|
1703
|
-
if ((!this.isTable(current) && !this.isListCell(current)) && (this.isFormatElement(current) || this.isRangeFormatElement(current) || this.isTextStyleElement(current)) && current.childNodes.length === 0 && nrtag) {
|
|
1746
|
+
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
1747
|
emptyTags.push(current);
|
|
1705
1748
|
return false;
|
|
1706
1749
|
}
|
|
@@ -1762,17 +1805,23 @@ const util = {
|
|
|
1762
1805
|
|
|
1763
1806
|
for (let i = 0, len = wrongList.length, t, tp, children, p; i < len; i++) {
|
|
1764
1807
|
t = wrongList[i];
|
|
1808
|
+
p = t.parentNode;
|
|
1809
|
+
if (!p) continue;
|
|
1765
1810
|
|
|
1766
1811
|
tp = this.createElement('LI');
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1812
|
+
|
|
1813
|
+
if (this.isFormatElement(t)) {
|
|
1814
|
+
children = t.childNodes;
|
|
1815
|
+
while (children[0]) {
|
|
1816
|
+
tp.appendChild(children[0]);
|
|
1817
|
+
}
|
|
1818
|
+
p.insertBefore(tp, t);
|
|
1819
|
+
this.removeItem(t);
|
|
1820
|
+
} else {
|
|
1821
|
+
t = t.nextSibling;
|
|
1822
|
+
tp.appendChild(wrongList[i]);
|
|
1823
|
+
p.insertBefore(tp, t);
|
|
1770
1824
|
}
|
|
1771
|
-
|
|
1772
|
-
p = t.parentNode;
|
|
1773
|
-
if (!p) continue;
|
|
1774
|
-
p.insertBefore(tp, t);
|
|
1775
|
-
this.removeItem(t);
|
|
1776
1825
|
}
|
|
1777
1826
|
|
|
1778
1827
|
for (let i = 0, len = withoutFormatCells.length, t, f; i < len; i++) {
|
package/src/options.d.ts
CHANGED
|
@@ -31,15 +31,15 @@ export interface SunEditorOptions {
|
|
|
31
31
|
/**
|
|
32
32
|
* Add tags to the default tags whitelist of editor.
|
|
33
33
|
*/
|
|
34
|
-
addTagsWhitelist?: string;
|
|
35
|
-
/**
|
|
36
|
-
* Whitelist of tags when pasting.
|
|
37
|
-
*/
|
|
38
|
-
pasteTagsWhitelist?: string;
|
|
34
|
+
addTagsWhitelist?: string | '*';
|
|
39
35
|
/**
|
|
40
36
|
* Blacklist of the editor default tags.
|
|
41
37
|
*/
|
|
42
38
|
tagsBlacklist?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Whitelist of tags when pasting.
|
|
41
|
+
*/
|
|
42
|
+
pasteTagsWhitelist?: string | '*';
|
|
43
43
|
/**
|
|
44
44
|
* Blacklist of tags when pasting.
|
|
45
45
|
*/
|
|
@@ -47,7 +47,11 @@ export interface SunEditorOptions {
|
|
|
47
47
|
/**
|
|
48
48
|
* Add attributes whitelist of tags that should be kept undeleted from the editor.
|
|
49
49
|
*/
|
|
50
|
-
attributesWhitelist?: Record<string, string>;
|
|
50
|
+
attributesWhitelist?: Record<string, string | '*'>;
|
|
51
|
+
/**
|
|
52
|
+
* Add attribute blacklist of tags that should be deleted in editor.
|
|
53
|
+
*/
|
|
54
|
+
attributesBlacklist?: Record<string, string | '*'>;
|
|
51
55
|
/**
|
|
52
56
|
* Layout
|
|
53
57
|
* ======
|
|
@@ -60,6 +64,13 @@ export interface SunEditorOptions {
|
|
|
60
64
|
* If true, the editor is set to RTL(Right To Left) mode.
|
|
61
65
|
*/
|
|
62
66
|
rtl?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Deletes other attributes except for the property set at the time of line break.
|
|
69
|
+
* If there is no value, no all attribute is deleted.
|
|
70
|
+
* @example 'class|style': Attributes other than "class" and "style" are deleted at line break.
|
|
71
|
+
* '*': All attributes are deleted at line break.
|
|
72
|
+
*/
|
|
73
|
+
lineAttrReset?: string;
|
|
63
74
|
/**
|
|
64
75
|
* Button List
|
|
65
76
|
*/
|
|
@@ -91,6 +102,10 @@ export interface SunEditorOptions {
|
|
|
91
102
|
* Allows the usage of HTML, HEAD, BODY tags and DOCTYPE declaration
|
|
92
103
|
*/
|
|
93
104
|
fullPage?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Attributes of the iframe.
|
|
107
|
+
*/
|
|
108
|
+
iframeAttributes?: Record<string, string>;
|
|
94
109
|
/**
|
|
95
110
|
* Name of the CSS file(s) to apply inside the iframe.
|
|
96
111
|
*/
|
|
@@ -147,6 +162,16 @@ export interface SunEditorOptions {
|
|
|
147
162
|
* Displays the current node structure to resizingBar
|
|
148
163
|
*/
|
|
149
164
|
showPathLabel?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Enable/disable resize function of bottom resizing bar.
|
|
167
|
+
*/
|
|
168
|
+
resizeEnable?: boolean;
|
|
169
|
+
/**
|
|
170
|
+
* A custom HTML selector placing the resizing bar inside.
|
|
171
|
+
The class name of the element must be 'sun-editor'.
|
|
172
|
+
Element or querySelector argument.
|
|
173
|
+
*/
|
|
174
|
+
resizingBarContainer?: HTMLElement | string;
|
|
150
175
|
/**
|
|
151
176
|
* Character count
|
|
152
177
|
* ===============
|
|
@@ -212,9 +237,13 @@ export interface SunEditorOptions {
|
|
|
212
237
|
*/
|
|
213
238
|
fontSize?: number[];
|
|
214
239
|
/**
|
|
215
|
-
*
|
|
240
|
+
* The font size unit
|
|
216
241
|
*/
|
|
217
242
|
fontSizeUnit?: string;
|
|
243
|
+
/**
|
|
244
|
+
* A list of drop-down options for the 'align' plugin.
|
|
245
|
+
*/
|
|
246
|
+
alignItems?: ('left' | 'center' | 'right' | 'justify')[];
|
|
218
247
|
/**
|
|
219
248
|
* Change default formatBlock array
|
|
220
249
|
*/
|
|
@@ -247,6 +276,10 @@ export interface SunEditorOptions {
|
|
|
247
276
|
* Choose whether the image height input is visible.
|
|
248
277
|
*/
|
|
249
278
|
imageHeightShow?: boolean;
|
|
279
|
+
/**
|
|
280
|
+
* Choose whether the image align radio buttons are visible.
|
|
281
|
+
*/
|
|
282
|
+
imageAlignShow?: boolean;
|
|
250
283
|
/**
|
|
251
284
|
* The default width size of the image frame
|
|
252
285
|
*/
|
|
@@ -296,7 +329,7 @@ export interface SunEditorOptions {
|
|
|
296
329
|
imageMultipleFile?: boolean;
|
|
297
330
|
/**
|
|
298
331
|
* Define the "accept" attribute of the input.
|
|
299
|
-
*
|
|
332
|
+
* @example "*" or ".jpg, .png .."
|
|
300
333
|
*/
|
|
301
334
|
imageAccept?: string;
|
|
302
335
|
/**
|
|
@@ -323,6 +356,10 @@ export interface SunEditorOptions {
|
|
|
323
356
|
* Choose whether the video height input is visible.
|
|
324
357
|
*/
|
|
325
358
|
videoHeightShow?: boolean;
|
|
359
|
+
/**
|
|
360
|
+
* Choose whether the video align radio buttons are visible.
|
|
361
|
+
*/
|
|
362
|
+
videoAlignShow?: boolean;
|
|
326
363
|
/**
|
|
327
364
|
* Choose whether the video ratio options is visible.
|
|
328
365
|
*/
|
|
@@ -455,6 +492,10 @@ export interface SunEditorOptions {
|
|
|
455
492
|
* Link
|
|
456
493
|
* =====
|
|
457
494
|
*/
|
|
495
|
+
/**
|
|
496
|
+
* Default checked value of the "Open in new window" checkbox.
|
|
497
|
+
*/
|
|
498
|
+
linkTargetNewWindow?: boolean;
|
|
458
499
|
/**
|
|
459
500
|
* Protocol for the links (if link has been added without any protocol this one will be used).
|
|
460
501
|
*/
|
|
@@ -467,6 +508,20 @@ export interface SunEditorOptions {
|
|
|
467
508
|
* Defines default "rel" attribute list of anchor tag.
|
|
468
509
|
*/
|
|
469
510
|
linkRelDefault?: {default?: string; check_new_window?: string; check_bookmark?: string;};
|
|
511
|
+
/**
|
|
512
|
+
* If true, disables the automatic prefixing of the host URL to the value of the link. default: false {Boolean}
|
|
513
|
+
*/
|
|
514
|
+
linkNoPrefix?: boolean;
|
|
515
|
+
/*
|
|
516
|
+
* HR
|
|
517
|
+
* =====
|
|
518
|
+
*/
|
|
519
|
+
/**
|
|
520
|
+
* Defines the hr items.
|
|
521
|
+
* "class" or "style" must be specified.
|
|
522
|
+
* @example [{name: "solid", class: "__se__xxx", style: "border-style: outset;"}]
|
|
523
|
+
*/
|
|
524
|
+
hrItems?: { name: string; class?: string; style?: string }[];
|
|
470
525
|
/**
|
|
471
526
|
* Key actions
|
|
472
527
|
* =====
|
|
@@ -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
|
|
|
@@ -51,6 +51,7 @@ export default {
|
|
|
51
51
|
_resizing: options.videoResizing,
|
|
52
52
|
_resizeDotHide: !options.videoHeightShow,
|
|
53
53
|
_rotation: options.videoRotation,
|
|
54
|
+
_alignHide: !options.videoAlignShow,
|
|
54
55
|
_onlyPercentage: options.videoSizeOnlyPercentage,
|
|
55
56
|
_ratio: false,
|
|
56
57
|
_ratioX: 1,
|
|
@@ -175,7 +176,7 @@ export default {
|
|
|
175
176
|
html += '' +
|
|
176
177
|
'</div>' +
|
|
177
178
|
'<div class="se-dialog-footer">' +
|
|
178
|
-
'<div>' +
|
|
179
|
+
'<div' + (option.videoAlignShow ? '' : ' style="display: none"') + '>' +
|
|
179
180
|
'<label><input type="radio" name="suneditor_video_radio" class="se-dialog-btn-radio" value="none" checked>' + lang.dialogBox.basic + '</label>' +
|
|
180
181
|
'<label><input type="radio" name="suneditor_video_radio" class="se-dialog-btn-radio" value="left">' + lang.dialogBox.left + '</label>' +
|
|
181
182
|
'<label><input type="radio" name="suneditor_video_radio" class="se-dialog-btn-radio" value="center">' + lang.dialogBox.center + '</label>' +
|
|
@@ -372,7 +373,7 @@ export default {
|
|
|
372
373
|
videoPlugin.submitAction.call(this, this.context.video.videoInputFile.files);
|
|
373
374
|
} else if (contextVideo.videoUrlFile && contextVideo._linkValue.length > 0) {
|
|
374
375
|
this.showLoading();
|
|
375
|
-
videoPlugin.setup_url.call(this);
|
|
376
|
+
videoPlugin.setup_url.call(this, contextVideo._linkValue);
|
|
376
377
|
}
|
|
377
378
|
} catch (error) {
|
|
378
379
|
this.closeLoading();
|
|
@@ -503,12 +504,11 @@ export default {
|
|
|
503
504
|
this.closeLoading();
|
|
504
505
|
},
|
|
505
506
|
|
|
506
|
-
setup_url: function () {
|
|
507
|
+
setup_url: function (url) {
|
|
507
508
|
try {
|
|
508
509
|
const contextVideo = this.context.video;
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
if (url.length === 0) return false;
|
|
510
|
+
if (!url) url = contextVideo._linkValue;
|
|
511
|
+
if (!url) return false;
|
|
512
512
|
|
|
513
513
|
/** iframe source */
|
|
514
514
|
if (/^<iframe.*\/iframe>$/.test(url)) {
|
|
@@ -540,7 +540,7 @@ export default {
|
|
|
540
540
|
url = 'https://player.vimeo.com/video/' + url.slice(url.lastIndexOf('/') + 1);
|
|
541
541
|
}
|
|
542
542
|
|
|
543
|
-
this.plugins.video.create_video.call(this, this.plugins.video
|
|
543
|
+
this.plugins.video.create_video.call(this, this.plugins.video[(!/youtu\.?be/.test(url) && !/vimeo\.com/.test(url) ? "createVideoTag" : "createIframeTag")].call(this), url, contextVideo.inputX.value, contextVideo.inputY.value, contextVideo._align, null, this.context.dialog.updateModal);
|
|
544
544
|
} catch (error) {
|
|
545
545
|
throw Error('[SUNEDITOR.video.upload.fail] cause : "' + error.message + '"');
|
|
546
546
|
} finally {
|
|
@@ -645,10 +645,8 @@ 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
|
-
const existElement = this.util.
|
|
649
|
-
this.util.
|
|
650
|
-
return this.isWysiwygDiv(current.parentNode);
|
|
651
|
-
}.bind(this.util));
|
|
648
|
+
const existElement = (this.util.isRangeFormatElement(oFrame.parentNode) || this.util.isWysiwygDiv(oFrame.parentNode)) ?
|
|
649
|
+
oFrame : this.util.getFormatElement(oFrame) || oFrame;
|
|
652
650
|
|
|
653
651
|
const prevFrame = oFrame;
|
|
654
652
|
contextVideo._element = oFrame = oFrame.cloneNode(true);
|
|
@@ -673,7 +671,9 @@ export default {
|
|
|
673
671
|
if (format) contextVideo._align = format.style.textAlign || format.style.float;
|
|
674
672
|
this.plugins.video.setAlign.call(this, null, oFrame, cover, container);
|
|
675
673
|
|
|
676
|
-
if (this.util.
|
|
674
|
+
if (this.util.isListCell(existElement) || this.util.isFormatElement(existElement)) {
|
|
675
|
+
prevFrame.parentNode.replaceChild(container, prevFrame);
|
|
676
|
+
} else if (this.util.isFormatElement(existElement) && existElement.childNodes.length > 0) {
|
|
677
677
|
existElement.parentNode.insertBefore(container, existElement);
|
|
678
678
|
this.util.removeItem(prevFrame);
|
|
679
679
|
// clean format tag
|
|
@@ -732,7 +732,7 @@ export default {
|
|
|
732
732
|
const contextVideo = this.context.video;
|
|
733
733
|
|
|
734
734
|
if (contextVideo.videoUrlFile) contextVideo._linkValue = contextVideo.preview.textContent = contextVideo.videoUrlFile.value = (contextVideo._element.src || (contextVideo._element.querySelector('source') || '').src || '');
|
|
735
|
-
contextVideo.modal.querySelector('input[name="suneditor_video_radio"][value="' + contextVideo._align + '"]').checked = true;
|
|
735
|
+
(contextVideo.modal.querySelector('input[name="suneditor_video_radio"][value="' + contextVideo._align + '"]') || contextVideo.modal.querySelector('input[name="suneditor_video_radio"][value="none"]')).checked = true;
|
|
736
736
|
|
|
737
737
|
if (contextVideo._resizing) {
|
|
738
738
|
this.plugins.resizing._module_setModifyInputSize.call(this, contextVideo, this.plugins.video);
|
|
@@ -49,7 +49,7 @@ export default {
|
|
|
49
49
|
*/
|
|
50
50
|
drawItems: function (item) {
|
|
51
51
|
const srcName = item.src.split('/').pop();
|
|
52
|
-
return '<div class="se-file-item-img"><img src="' + item.src + '" alt="' + (item.alt || srcName) + '" data-command="pick">' +
|
|
52
|
+
return '<div class="se-file-item-img"><img src="' + (item.thumbnail || item.src) + '" alt="' + (item.alt || srcName) + '" data-command="pick" data-value="' + (item.src || item.thumbnail) + '">' +
|
|
53
53
|
'<div class="se-file-img-name se-file-name-back"></div>' +
|
|
54
54
|
'<div class="se-file-img-name __se__img_name">' + (item.name || srcName) + '</div>' +
|
|
55
55
|
'</div>';
|
|
@@ -58,8 +58,7 @@ export default {
|
|
|
58
58
|
setImage: function (target) {
|
|
59
59
|
this.callPlugin('image', function () {
|
|
60
60
|
const file = {name: target.parentNode.querySelector('.__se__img_name').textContent, size: 0};
|
|
61
|
-
this.context.image.
|
|
62
|
-
this.plugins.image.create_image.call(this, target.src, null, this.context.image._origin_w, this.context.image._origin_h, 'none', file);
|
|
61
|
+
this.plugins.image.create_image.call(this, target.getAttribute('data-value'), null, this.context.image._origin_w, this.context.image._origin_h, 'none', file, target.alt);
|
|
63
62
|
}.bind(this), null);
|
|
64
63
|
}
|
|
65
64
|
};
|