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.
Files changed (45) hide show
  1. package/README.md +107 -24
  2. package/dist/css/suneditor.min.css +1 -1
  3. package/dist/suneditor.min.js +2 -2
  4. package/package.json +1 -1
  5. package/src/assets/css/suneditor.css +25 -6
  6. package/src/assets/defaultIcons.js +2 -0
  7. package/src/lang/Lang.d.ts +3 -1
  8. package/src/lang/ckb.js +2 -0
  9. package/src/lang/da.js +2 -0
  10. package/src/lang/de.js +2 -0
  11. package/src/lang/en.js +2 -0
  12. package/src/lang/es.js +2 -0
  13. package/src/lang/fr.js +10 -8
  14. package/src/lang/he.js +2 -0
  15. package/src/lang/it.js +2 -0
  16. package/src/lang/ja.js +2 -0
  17. package/src/lang/ko.js +2 -0
  18. package/src/lang/lv.js +2 -0
  19. package/src/lang/nl.js +2 -0
  20. package/src/lang/pl.js +2 -0
  21. package/src/lang/pt_br.js +2 -0
  22. package/src/lang/ro.js +2 -0
  23. package/src/lang/ru.js +2 -0
  24. package/src/lang/se.js +2 -0
  25. package/src/lang/ua.js +2 -0
  26. package/src/lang/zh_cn.js +2 -0
  27. package/src/lib/constructor.js +50 -11
  28. package/src/lib/context.js +4 -1
  29. package/src/lib/core.d.ts +86 -11
  30. package/src/lib/core.js +555 -147
  31. package/src/lib/util.d.ts +24 -1
  32. package/src/lib/util.js +64 -15
  33. package/src/options.d.ts +63 -8
  34. package/src/plugins/dialog/audio.js +5 -5
  35. package/src/plugins/dialog/image.js +30 -20
  36. package/src/plugins/dialog/video.js +13 -13
  37. package/src/plugins/fileBrowser/imageGallery.js +2 -3
  38. package/src/plugins/modules/_anchor.js +6 -4
  39. package/src/plugins/modules/component.d.ts +1 -1
  40. package/src/plugins/modules/fileBrowser.js +6 -1
  41. package/src/plugins/modules/fileManager.js +1 -3
  42. package/src/plugins/modules/resizing.js +11 -6
  43. package/src/plugins/submenu/align.js +32 -27
  44. package/src/plugins/submenu/font.js +1 -1
  45. package/src/plugins/submenu/horizontalRule.js +19 -25
@@ -121,12 +121,13 @@ export default {
121
121
  on: function (contextAnchor, update) {
122
122
  if (!update) {
123
123
  this.plugins.anchor.init.call(this, contextAnchor);
124
- contextAnchor.anchorText.value = this.getSelection().toString();
124
+ contextAnchor.anchorText.value = this.getSelection().toString().trim();
125
+ contextAnchor.newWindowCheck.checked = this.options.linkTargetNewWindow;
125
126
  } else if (contextAnchor.linkAnchor) {
126
127
  this.context.dialog.updateModal = true;
127
- const href = contextAnchor.linkAnchor.href;
128
+ const href = this.options.linkNoPrefix ? contextAnchor.linkAnchor.href.replace(contextAnchor.linkAnchor.origin + '/', '') : contextAnchor.linkAnchor.href;
128
129
  contextAnchor.linkValue = contextAnchor.preview.textContent = contextAnchor.urlInput.value = /\#.+$/.test(href) ? href.substr(href.lastIndexOf('#')) : href;
129
- contextAnchor.anchorText.value = contextAnchor.linkAnchor.textContent.trim() || contextAnchor.linkAnchor.getAttribute('alt');
130
+ contextAnchor.anchorText.value = contextAnchor.linkAnchor.textContent || contextAnchor.linkAnchor.getAttribute('alt');
130
131
  contextAnchor.newWindowCheck.checked = (/_blank/i.test(contextAnchor.linkAnchor.target) ? true : false);
131
132
  contextAnchor.downloadCheck.checked = contextAnchor.linkAnchor.download;
132
133
  }
@@ -293,9 +294,10 @@ export default {
293
294
  setLinkPreview: function (context, value) {
294
295
  const preview = context.preview;
295
296
  const protocol = this.options.linkProtocol;
297
+ const noPrefix = this.options.linkNoPrefix;
296
298
  const reservedProtocol = /^(mailto\:|tel\:|sms\:|https*\:\/\/|#)/.test(value);
297
299
  const sameProtocol = !protocol ? false : this._w.RegExp('^' + value.substr(0, protocol.length)).test(protocol);
298
- context.linkValue = preview.textContent = !value ? '' : (protocol && !reservedProtocol && !sameProtocol) ? protocol + value : reservedProtocol ? value : /^www\./.test(value) ? 'http://' + value : this.context.anchor.host + (/^\//.test(value) ? '' : '/') + value;
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;
299
301
 
300
302
  if (value.indexOf('#') === 0) {
301
303
  context.bookmark.style.display = 'block';
@@ -22,4 +22,4 @@ declare interface component extends Module {
22
22
  create_caption(): string;
23
23
  }
24
24
 
25
- export default resizing;
25
+ export default component;
@@ -229,7 +229,12 @@
229
229
  this.plugins.fileBrowser._xmlHttp = null;
230
230
  if (xmlHttp.status === 200) {
231
231
  try {
232
- this.plugins.fileBrowser._drawListItem.call(this, JSON.parse(xmlHttp.responseText).result, true);
232
+ const res = JSON.parse(xmlHttp.responseText);
233
+ if (res.result.length > 0) {
234
+ this.plugins.fileBrowser._drawListItem.call(this, res.result, true);
235
+ } else if (res.nullMessage) {
236
+ this.context.fileBrowser.list.innerHTML = res.nullMessage;
237
+ }
233
238
  } catch (e) {
234
239
  throw Error('[SUNEDITOR.fileBrowser.drawList.fail] cause : "' + e.message + '"');
235
240
  } finally {
@@ -28,8 +28,6 @@
28
28
  _checkMediaComponent: function (tag) {
29
29
  if (/IMG/i.test(tag)) {
30
30
  return !/FIGURE/i.test(tag.parentElement.nodeName) || !/FIGURE/i.test(tag.parentElement.parentElement.nodeName);
31
- } else if (/VIDEO/i.test(tag)) {
32
- return !/FIGURE/i.test(tag.parentElement.nodeName);
33
31
  }
34
32
  return true;
35
33
  },
@@ -98,7 +96,7 @@
98
96
  checkInfo: function (pluginName, tagNames, uploadEventHandler, modifyHandler, resizing) {
99
97
  let tags = [];
100
98
  for (let i = 0, len = tagNames.length; i < len; i++) {
101
- tags = tags.concat([].slice.call(this.context.element.wysiwyg.getElementsByTagName(tagNames[i])));
99
+ tags = tags.concat([].slice.call(this.context.element.wysiwyg.querySelectorAll(tagNames[i] + ':not([data-se-embed="true"])')));
102
100
  }
103
101
 
104
102
  const fileManagerPlugin = this.plugins.fileManager;
@@ -437,11 +437,16 @@
437
437
  }
438
438
 
439
439
  // align icon
440
- const alignList = contextResizing.alignMenuList;
441
- this.util.changeElement(contextResizing.alignButton.firstElementChild, contextResizing.alignIcons[align]);
442
- for (let i = 0, len = alignList.length; i < len; i++) {
443
- if (alignList[i].getAttribute('data-value') === align) this.util.addClass(alignList[i], 'on');
444
- else this.util.removeClass(alignList[i], 'on');
440
+ if (contextPlugin._alignHide) {
441
+ contextResizing.alignButton.style.display = 'none';
442
+ } else {
443
+ contextResizing.alignButton.style.display = '';
444
+ const alignList = contextResizing.alignMenuList;
445
+ this.util.changeElement(contextResizing.alignButton.firstElementChild, contextResizing.alignIcons[align]);
446
+ for (let i = 0, len = alignList.length; i < len; i++) {
447
+ if (alignList[i].getAttribute('data-value') === align) this.util.addClass(alignList[i], 'on');
448
+ else this.util.removeClass(alignList[i], 'on');
449
+ }
445
450
  }
446
451
 
447
452
  // percentage active
@@ -478,7 +483,7 @@
478
483
  }
479
484
 
480
485
  this.setControllerPosition(contextResizing.resizeButton, resizeContainer, 'bottom', addOffset);
481
- this.controllersOn(resizeContainer, contextResizing.resizeButton, this.util.setDisabledButtons.bind(this, false, this.resizingDisabledButtons), targetElement, plugin);
486
+ this.controllersOn(resizeContainer, contextResizing.resizeButton, this.util.setDisabledButtons.bind(this.util, false, this.resizingDisabledButtons), targetElement, plugin);
482
487
  this.util.setDisabledButtons(true, this.resizingDisabledButtons);
483
488
 
484
489
  contextResizing._resize_w = w;
@@ -15,9 +15,10 @@ export default {
15
15
  const context = core.context;
16
16
  context.align = {
17
17
  targetButton: targetElement,
18
+ _itemMenu: null,
18
19
  _alignList: null,
19
20
  currentAlign: '',
20
- defaultDir: core.options.rtl ? 'right' : 'left',
21
+ defaultDir: core.options.rtl ? 'right' : 'left',
21
22
  icons: {
22
23
  justify: icons.align_justify,
23
24
  left: icons.align_left,
@@ -28,7 +29,7 @@ export default {
28
29
 
29
30
  /** set submenu */
30
31
  let listDiv = this.setSubmenu(core);
31
- let listUl = listDiv.querySelector('ul');
32
+ let listUl = context.align._itemMenu = listDiv.querySelector('ul');
32
33
 
33
34
  /** add event listeners */
34
35
  listUl.addEventListener('click', this.pickup.bind(core));
@@ -45,36 +46,24 @@ export default {
45
46
  const lang = core.lang;
46
47
  const icons = core.icons;
47
48
  const listDiv = core.util.createElement('DIV');
48
- const leftDir = core.context.align.defaultDir === 'left';
49
-
50
- const leftMenu = '<li>' +
51
- '<button type="button" class="se-btn-list se-btn-align" data-command="justifyleft" data-value="left" title="' + lang.toolbar.alignLeft + '">' +
52
- '<span class="se-list-icon">' + icons.align_left + '</span>' + lang.toolbar.alignLeft +
53
- '</button>' +
54
- '</li>';
55
-
56
- const rightMenu = '<li>' +
57
- '<button type="button" class="se-btn-list se-btn-align" data-command="justifyright" data-value="right" title="' + lang.toolbar.alignRight + '">' +
58
- '<span class="se-list-icon">' + icons.align_right +'</span>' + lang.toolbar.alignRight +
59
- '</button>' +
60
- '</li>';
49
+ const alignItems = core.options.alignItems;
50
+
51
+ let html = '';
52
+ for (let i = 0, item, text; i < alignItems.length; i++) {
53
+ item = alignItems[i];
54
+ text = lang.toolbar['align' + item.charAt(0).toUpperCase() + item.slice(1)];
55
+ html += '<li>' +
56
+ '<button type="button" class="se-btn-list se-btn-align" data-value="' + item + '" title="' + text + '">' +
57
+ '<span class="se-list-icon">' + icons['align_' + item] + '</span>' + text +
58
+ '</button>' +
59
+ '</li>';
60
+ }
61
61
 
62
62
  listDiv.className = 'se-submenu se-list-layer se-list-align';
63
63
  listDiv.innerHTML = '' +
64
64
  '<div class="se-list-inner">' +
65
65
  '<ul class="se-list-basic">' +
66
- (leftDir ? leftMenu : rightMenu) +
67
- '<li>' +
68
- '<button type="button" class="se-btn-list se-btn-align" data-command="justifycenter" data-value="center" title="' + lang.toolbar.alignCenter + '">' +
69
- '<span class="se-list-icon">' + icons.align_center + '</span>' + lang.toolbar.alignCenter +
70
- '</button>' +
71
- '</li>' +
72
- (leftDir? rightMenu : leftMenu) +
73
- '<li>' +
74
- '<button type="button" class="se-btn-list se-btn-align" data-command="justifyfull" data-value="justify" title="' + lang.toolbar.alignJustify + '">' +
75
- '<span class="se-list-icon">' + icons.align_justify + '</span>' + lang.toolbar.alignJustify +
76
- '</button>' +
77
- '</li>' +
66
+ html +
78
67
  '</ul>' +
79
68
  '</div>';
80
69
 
@@ -125,6 +114,22 @@ export default {
125
114
  }
126
115
  },
127
116
 
117
+ exchangeDir: function () {
118
+ const dir = this.options.rtl ? 'right' : 'left';
119
+ if (!this.context.align || this.context.align.defaultDir === dir) return;
120
+
121
+ this.context.align.defaultDir = dir;
122
+ let menu = this.context.align._itemMenu;
123
+ let leftBtn = menu.querySelector('[data-value="left"]');
124
+ let rightBtn = menu.querySelector('[data-value="right"]');
125
+ if (leftBtn && rightBtn) {
126
+ const lp = leftBtn.parentElement;
127
+ const rp = rightBtn.parentElement;
128
+ lp.appendChild(rightBtn);
129
+ rp.appendChild(leftBtn);
130
+ }
131
+ },
132
+
128
133
  pickup: function (e) {
129
134
  e.preventDefault();
130
135
  e.stopPropagation();
@@ -78,7 +78,7 @@ export default {
78
78
  if (!element) {
79
79
  const font = this.hasFocus ? this.wwComputedStyle.fontFamily : this.lang.toolbar.font;
80
80
  this.util.changeTxt(target, font);
81
- this.util.changeTxt(tooltip, this.hasFocus ? this.lang.toolbar.font + ' (' + font + ')' : font);
81
+ this.util.changeTxt(tooltip, this.hasFocus ? this.lang.toolbar.font + (font ? ' (' + font + ')' : '') : font);
82
82
  } else if (element.style && element.style.fontFamily.length > 0) {
83
83
  const selectFont = element.style.fontFamily.replace(/["']/g,'');
84
84
  this.util.changeTxt(target, selectFont);
@@ -31,26 +31,22 @@ export default {
31
31
  setSubmenu: function (core) {
32
32
  const lang = core.lang;
33
33
  const listDiv = core.util.createElement('DIV');
34
-
34
+ const items = core.options.hrItems || [{name: lang.toolbar.hr_solid, class: '__se__solid'}, {name: lang.toolbar.hr_dashed, class: '__se__dashed'}, {name: lang.toolbar.hr_dotted, class: '__se__dotted'}];
35
+
36
+ let list = '';
37
+ for (let i = 0, len = items.length; i < len; i++) {
38
+ list += '<li>' +
39
+ '<button type="button" class="se-btn-list btn_line" data-command="horizontalRule" data-value="' + items[i].class + '" title="' + items[i].name + '">' +
40
+ '<hr' + (items[i].class ? ' class="' + items[i].class + '"' : '') + (items[i].style ? ' style="' + items[i].style + '"' : '') + '/>' +
41
+ '</button>' +
42
+ '</li>';
43
+ }
44
+
35
45
  listDiv.className = 'se-submenu se-list-layer se-list-line';
36
46
  listDiv.innerHTML = '' +
37
47
  '<div class="se-list-inner">' +
38
48
  '<ul class="se-list-basic">' +
39
- '<li>' +
40
- '<button type="button" class="se-btn-list btn_line" data-command="horizontalRule" data-value="solid" title="' + lang.toolbar.hr_solid + '">' +
41
- '<hr style="border-width: 1px 0 0; border-style: solid none none; border-color: black; border-image: initial; height: 1px;" />' +
42
- '</button>' +
43
- '</li>' +
44
- '<li>' +
45
- '<button type="button" class="se-btn-list btn_line" data-command="horizontalRule" data-value="dotted" title="' + lang.toolbar.hr_dotted + '">' +
46
- '<hr style="border-width: 1px 0 0; border-style: dotted none none; border-color: black; border-image: initial; height: 1px;" />' +
47
- '</button>' +
48
- '</li>' +
49
- '<li>' +
50
- '<button type="button" class="se-btn-list btn_line" data-command="horizontalRule" data-value="dashed" title="' + lang.toolbar.hr_dashed + '">' +
51
- '<hr style="border-width: 1px 0 0; border-style: dashed none none; border-color: black; border-image: initial; height: 1px;" />' +
52
- '</button>' +
53
- '</li>' +
49
+ list +
54
50
  '</ul>' +
55
51
  '</div>';
56
52
 
@@ -74,11 +70,9 @@ export default {
74
70
  return false;
75
71
  },
76
72
 
77
- appendHr: function (className) {
78
- const oHr = this.util.createElement('HR');
79
- oHr.className = className;
73
+ appendHr: function (hrTemp) {
80
74
  this.focus();
81
- return this.insertComponent(oHr, false, true, false);
75
+ return this.insertComponent(hrTemp.cloneNode(false), false, true, false);
82
76
  },
83
77
 
84
78
  horizontalRulePick: function (e) {
@@ -86,16 +80,16 @@ export default {
86
80
  e.stopPropagation();
87
81
 
88
82
  let target = e.target;
89
- let value = null;
83
+ let command = target.getAttribute('data-command');
90
84
 
91
- while (!value && !/UL/i.test(target.tagName)) {
92
- value = target.getAttribute('data-value');
85
+ while (!command && !/UL/i.test(target.tagName)) {
93
86
  target = target.parentNode;
87
+ command = target.getAttribute('data-command');
94
88
  }
95
89
 
96
- if (!value) return;
90
+ if (!command) return;
97
91
 
98
- const oNode = this.plugins.horizontalRule.appendHr.call(this, '__se__' + value);
92
+ const oNode = this.plugins.horizontalRule.appendHr.call(this, target.firstElementChild);
99
93
  if (oNode) {
100
94
  this.setRange(oNode, 0, oNode, 0);
101
95
  this.submenuOff();