suneditor 3.0.0-beta.2 → 3.0.0-beta.3

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 (36) hide show
  1. package/dist/suneditor.min.css +1 -1
  2. package/dist/suneditor.min.js +1 -1
  3. package/package.json +1 -1
  4. package/src/assets/design/color.css +11 -1
  5. package/src/assets/suneditor.css +17 -12
  6. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +4 -2
  7. package/src/core/base/eventHandlers/handler_ww_key_input.js +1 -1
  8. package/src/core/base/eventManager.js +61 -30
  9. package/src/core/class/char.js +3 -2
  10. package/src/core/class/component.js +17 -3
  11. package/src/core/class/format.js +13 -2
  12. package/src/core/class/html.js +58 -26
  13. package/src/core/class/selection.js +1 -8
  14. package/src/core/class/toolbar.js +2 -1
  15. package/src/core/class/ui.js +3 -1
  16. package/src/core/editor.js +124 -58
  17. package/src/core/section/actives.js +48 -23
  18. package/src/core/section/constructor.js +92 -78
  19. package/src/events.js +12 -0
  20. package/src/helper/converter.js +23 -1
  21. package/src/helper/dom/domCheck.js +2 -2
  22. package/src/modules/Controller.js +25 -5
  23. package/src/plugins/dropdown/formatBlock.js +4 -13
  24. package/src/themes/dark.css +11 -1
  25. package/types/core/base/eventManager.d.ts +16 -0
  26. package/types/core/class/char.d.ts +2 -1
  27. package/types/core/class/component.d.ts +1 -0
  28. package/types/core/class/format.d.ts +8 -1
  29. package/types/core/class/html.d.ts +8 -0
  30. package/types/core/class/ui.d.ts +1 -1
  31. package/types/core/editor.d.ts +7 -2
  32. package/types/core/section/constructor.d.ts +7 -0
  33. package/types/events.d.ts +2 -0
  34. package/types/helper/converter.d.ts +9 -0
  35. package/types/helper/index.d.ts +1 -0
  36. package/types/plugins/dropdown/formatBlock.d.ts +2 -2
@@ -1,5 +1,5 @@
1
1
  import { env, converter, dom, numbers } from '../helper';
2
- import Constructor, { InitOptions, UpdateButton, CreateShortcuts, CreateStatusbar, OPTION_FIXED_FLAG } from './section/constructor';
2
+ import Constructor, { InitOptions, UpdateButton, CreateShortcuts, CreateStatusbar, OPTION_FRAME_FIXED_FLAG, OPTION_FIXED_FLAG } from './section/constructor';
3
3
  import { UpdateStatusbarContext } from './section/context';
4
4
  import { BASIC_COMMANDS, ACTIVE_EVENT_COMMANDS, SELECT_ALL, DIR_BTN_ACTIVE, SAVE, COPY_FORMAT, FONT_STYLE, PAGE_BREAK } from './section/actives';
5
5
  import History from './base/history';
@@ -383,11 +383,17 @@ function Editor(multiTargets, options) {
383
383
  this._notHideToolbar = false;
384
384
 
385
385
  /**
386
- * @description Variables for controlling focus and blur events
386
+ * @description Variables for controlling blur events
387
387
  * @type {boolean}
388
388
  */
389
389
  this._preventBlur = false;
390
390
 
391
+ /**
392
+ * @description Variables for controlling focus events
393
+ * @type {boolean}
394
+ */
395
+ this._preventFocus = false;
396
+
391
397
  /**
392
398
  * @description Variables for controlling selection change events
393
399
  */
@@ -762,37 +768,39 @@ Editor.prototype = {
762
768
  * @param {EditorInitOptions_editor} newOptions Options
763
769
  */
764
770
  resetOptions(newOptions) {
765
- const _keys = Object.keys;
766
771
  this.viewer.codeView(false);
767
772
  this.viewer.showBlocks(false);
768
773
 
769
- const newOptionKeys = _keys(newOptions);
774
+ const rootDiff = new Map();
775
+ const frameRoots = this.frameRoots;
776
+ const newRoots = [];
777
+ const newRootKeys = new Map();
778
+
779
+ // frame roots
780
+ const nRoot = {};
781
+ for (const k in newOptions) {
782
+ if (OPTION_FRAME_FIXED_FLAG[k] === undefined) continue;
783
+ nRoot[k] = newOptions[k];
784
+ delete newOptions[k];
785
+ }
786
+ for (const rootKey of frameRoots.keys()) {
787
+ newOptions[rootKey || ''] = { ...nRoot, ...newOptions[rootKey || ''] };
788
+ }
789
+
790
+ // check reoption validation
791
+ const newOptionKeys = Object.keys(newOptions);
770
792
  CheckResetKeys(newOptionKeys, this.plugins, '');
771
793
  if (newOptionKeys.length === 0) return;
772
794
 
795
+ if (frameRoots.size === 1) {
796
+ newOptionKeys.unshift(null);
797
+ }
798
+
773
799
  // option merge
774
- const rootDiff = {};
775
- const rootKeys = this.rootKeys;
776
- const frameRoots = this.frameRoots;
777
- const newRoots = [];
778
- const newRootKeys = {};
779
- this._originOptions = [newOptions, this._originOptions].reduce(function (init, option) {
800
+ const _originOptions = [this._originOptions, newOptions].reduce((init, option) => {
780
801
  for (const key in option) {
781
- if (rootKeys.includes(key) && option[key]) {
782
- const nro = option[key];
783
- const newKeys = _keys(nro);
784
- CheckResetKeys(newKeys, null, key + '.');
785
- if (newKeys.length === 0) continue;
786
-
787
- rootDiff[key] = new Map();
788
- const o = frameRoots.get(key).get('options').get('_origin');
789
- for (const rk in nro) {
790
- const roV = nro[rk];
791
- if (!newKeys.includes(rk) || o[rk] === roV) continue;
792
- rootDiff[key].set(GetResetDiffKey(rk), true);
793
- o[rk] = roV;
794
- }
795
- newRoots.push((newRootKeys[key] = { options: o }));
802
+ if (frameRoots.has(key || null)) {
803
+ RestoreFrameOptions(key, option, frameRoots, rootDiff, newRootKeys, newRoots);
796
804
  } else {
797
805
  init[key] = option[key];
798
806
  }
@@ -802,17 +810,25 @@ Editor.prototype = {
802
810
 
803
811
  // init options
804
812
  const options = this.options;
805
- const newMap = InitOptions(this._originOptions, newRoots, this.plugins).o;
806
- /** --------- root start --------- */
807
- for (let i = 0, k; (k = newOptionKeys[i]); i++) {
808
- if (newRootKeys[k]) {
809
- const diff = rootDiff[k];
813
+ const newO = InitOptions(_originOptions, newRoots, this.plugins);
814
+ const newOptionMap = newO.o;
815
+ const newFrameMap = newO.frameMap;
816
+ /** --------- [root start] --------- */
817
+ for (let i = 0, len = newOptionKeys.length, k; i < len; i++) {
818
+ k = newOptionKeys[i] || null;
819
+
820
+ if (newRootKeys.has(k)) {
821
+ const diff = rootDiff.get(k);
810
822
  const fc = frameRoots.get(k);
811
823
  const originOptions = fc.get('options');
812
- const newRootOptions = newRootKeys[k].options;
824
+ const newRootOptions = newFrameMap.get(k);
813
825
 
814
- // statusbar
815
- if (diff.has('statusbar')) {
826
+ // --- set options : fc ---
827
+ fc.set('options', newRootOptions);
828
+
829
+ // statusbar-changed
830
+ if (diff.has('statusbar-changed')) {
831
+ // statusbar
816
832
  dom.utils.removeItem(fc.get('statusbar'));
817
833
  if (newRootOptions.get('statusbar')) {
818
834
  const statusbar = CreateStatusbar(newRootOptions, null).statusbar;
@@ -824,6 +840,10 @@ Editor.prototype = {
824
840
  newRootOptions.set('__statusbarEvent', null);
825
841
  UpdateStatusbarContext(null, fc);
826
842
  }
843
+ // charCounter
844
+ if (fc.get('statusbar')) {
845
+ this.char.display(fc);
846
+ }
827
847
  }
828
848
 
829
849
  // iframe's options
@@ -834,6 +854,7 @@ Editor.prototype = {
834
854
  for (const origin_k in originAttr) frame.removeAttribute(origin_k, originAttr[origin_k]);
835
855
  for (const new_k in newAttr) frame.setAttribute(new_k, newAttr[new_k]);
836
856
  }
857
+
837
858
  if (diff.has('iframe_cssFileName')) {
838
859
  const docHead = fc.get('_wd').head;
839
860
  const links = docHead.getElementsByTagName('link');
@@ -844,11 +865,12 @@ Editor.prototype = {
844
865
  while (newLinks[0]) docHead.insertBefore(newLinks[0], sTag);
845
866
  }
846
867
 
847
- // --- options set ---
848
- fc.set('options', newRootOptions);
868
+ if (diff.has('placeholder')) {
869
+ fc.get('placeholder').textContent = newRootOptions.get('placeholder');
870
+ }
849
871
 
850
872
  // frame styles
851
- this.ui.setEditorStyle(newRootOptions.get('_defaultStyles'), fc);
873
+ this.ui.setEditorStyle(newRootOptions.get('editorStyle'), fc);
852
874
 
853
875
  // frame attributes
854
876
  const frame = fc.get('wysiwyg');
@@ -859,25 +881,47 @@ Editor.prototype = {
859
881
 
860
882
  continue;
861
883
  }
862
- /** --------- root end --------- */
884
+ /** --------- [root end] --------- */
863
885
 
864
- options.set(k, newMap.get(k));
886
+ // --- set options ---
887
+ options.set(k, newOptionMap.get(k));
865
888
 
866
- /** apply option */
867
- // history delay time
868
- if (k === 'historyStackDelayTime') {
869
- this.history.resetDelayTime(options.get('historyStackDelayTime'));
870
- continue;
871
- }
872
- // set dir
873
- if (k === 'textDirection') {
874
- this.setDir(options.get('_rtl') ? 'ltr' : 'rtl');
875
- continue;
889
+ /** Options that require a function call */
890
+ switch (k) {
891
+ case 'theme': {
892
+ this.ui.setTheme(options.get('theme'));
893
+ break;
894
+ }
895
+ case 'events': {
896
+ const events = options.get('events');
897
+ for (const name in events) {
898
+ this.events[name] = events[name];
899
+ }
900
+ break;
901
+ }
902
+ case 'autoStyleify': {
903
+ this.html.__resetAutoStyleify(options.get('autoStyleify'));
904
+ break;
905
+ }
906
+ case 'textDirection': {
907
+ this.setDir(options.get('_rtl') ? 'ltr' : 'rtl');
908
+ break;
909
+ }
910
+ case 'historyStackDelayTime': {
911
+ this.history.resetDelayTime(options.get('historyStackDelayTime'));
912
+ break;
913
+ }
914
+ case 'defaultLineBreakFormat': {
915
+ this.format.__resetBrLineBreak(options.get('defaultLineBreakFormat'));
916
+ }
876
917
  }
877
918
  }
878
919
 
879
920
  /** apply options */
880
- // toolbar
921
+ // _origin
922
+ this._originOptions = _originOptions;
923
+
924
+ // --- [toolbar] ---
881
925
  const toolbar = this.context.get('toolbar.main');
882
926
  // width
883
927
  if (/inline|balloon/i.test(options.get('mode')) && newOptionKeys.includes('toolbar_width')) {
@@ -886,6 +930,8 @@ Editor.prototype = {
886
930
  // hide
887
931
  if (options.get('toolbar_hide')) {
888
932
  toolbar.style.display = 'none';
933
+ } else {
934
+ toolbar.style.display = '';
889
935
  }
890
936
  // shortcuts hint
891
937
  if (options.get('shortcutsHint')) {
@@ -894,11 +940,6 @@ Editor.prototype = {
894
940
  dom.utils.addClass(toolbar, 'se-shortcut-hide');
895
941
  }
896
942
 
897
- // theme
898
- if (this._originOptions.theme !== (newOptions.theme ?? this._originOptions.theme)) {
899
- this.ui.setTheme(newOptions.theme);
900
- }
901
-
902
943
  this.effectNode = null;
903
944
  this._setFrameInfo(this.frameRoots.get(this.status.rootKey));
904
945
  },
@@ -1444,7 +1485,7 @@ Editor.prototype = {
1444
1485
 
1445
1486
  /**
1446
1487
  * @private
1447
- * @description Caches shortcut keys for commands.
1488
+ * @description Caches custom(starts with "_") shortcut keys for commands.
1448
1489
  */
1449
1490
  __cachingShortcuts() {
1450
1491
  const shortcuts = this.options.get('shortcuts');
@@ -1689,16 +1730,41 @@ Editor.prototype = {
1689
1730
  Constructor: Editor
1690
1731
  };
1691
1732
 
1733
+ function RestoreFrameOptions(key, option, frameRoots, rootDiff, newRootKeys, newRoots) {
1734
+ const nro = option[key];
1735
+ const newKeys = Object.keys(nro);
1736
+ CheckResetKeys(newKeys, null, key + '.');
1737
+ if (newKeys.length === 0) return false;
1738
+
1739
+ const rootKey = key || null;
1740
+ rootDiff.set(rootKey, new Map());
1741
+
1742
+ const o = frameRoots.get(rootKey).get('options').get('_origin');
1743
+ const no = {};
1744
+ const hasOwn = Object.prototype.hasOwnProperty;
1745
+ for (const rk in nro) {
1746
+ if (!hasOwn.call(OPTION_FRAME_FIXED_FLAG, rk)) continue;
1747
+ const roV = nro[rk];
1748
+ if (!newKeys.includes(rk) || o[rk] === roV) continue;
1749
+ rootDiff.get(rootKey).set(GetResetDiffKey(rk), true);
1750
+ no[rk] = roV;
1751
+ }
1752
+
1753
+ const newO = { ...o, ...no };
1754
+ newRootKeys.set(rootKey, new Map(Object.entries(newO)));
1755
+ newRoots.push({ key: rootKey, options: newO });
1756
+ }
1757
+
1692
1758
  function GetResetDiffKey(key) {
1693
- if (/^statusbar/i.test(key)) return 'statusbar';
1759
+ if (/^statusbar|^charCounter/.test(key)) return 'statusbar-changed';
1694
1760
  return key;
1695
1761
  }
1696
1762
 
1697
1763
  function CheckResetKeys(keys, plugins, root) {
1698
1764
  for (let i = 0, len = keys.length, k; i < len; i++) {
1699
1765
  k = keys[i];
1700
- if (OPTION_FIXED_FLAG[k] === 'fixed' || (plugins && plugins[k])) {
1701
- console.warn(`[SUNEDITOR.warn.resetOptions] "[${root + k}]" options not available in resetOptions have no effect.`);
1766
+ if (OPTION_FIXED_FLAG[k] === 'fixed' || OPTION_FRAME_FIXED_FLAG[k] === 'fixed' || (plugins && plugins[k])) {
1767
+ console.warn(`[SUNEDITOR.warn.resetOptions] The "[${root + k}]" option cannot be changed after the editor is created.`);
1702
1768
  keys.splice(i--, 1);
1703
1769
  len--;
1704
1770
  }
@@ -31,6 +31,35 @@ const __RemoveCopyformt = function (ww, button) {
31
31
  return true;
32
32
  };
33
33
 
34
+ /**
35
+ * @private
36
+ * @description Finds the first and last child elements in a selection area.
37
+ * @param {Element} selectArea Selection area element
38
+ * @returns {{ first: Node, last: Node}} Object containing the first and last child elements
39
+ */
40
+ const __findFirstAndLast = function (selectArea) {
41
+ const isContentLess = dom.check.isContentLess;
42
+ const isTable = dom.check.isTable;
43
+ const first =
44
+ dom.query.getEdgeChild(
45
+ dom.query.getEdgeChild(selectArea, (current) => !isContentLess(current), false),
46
+ (current) => {
47
+ return current.childNodes.length === 0 || current.nodeType === 3 || isTable(current);
48
+ },
49
+ false
50
+ ) || selectArea.firstChild;
51
+ const last =
52
+ dom.query.getEdgeChild(
53
+ selectArea.lastChild,
54
+ (current) => {
55
+ return current.childNodes.length === 0 || current.nodeType === 3 || isTable(current);
56
+ },
57
+ true
58
+ ) || selectArea.lastChild;
59
+
60
+ return { first, last };
61
+ };
62
+
34
63
  /**
35
64
  * @description List of commands that trigger active event handling in the editor.
36
65
  * - These commands typically apply inline formatting or structural changes.
@@ -77,39 +106,35 @@ export function SELECT_ALL(editor) {
77
106
  // select all
78
107
  const scopeTagList = scopeSelectionTags.filter((tagName) => tagName !== prevScopeTagName);
79
108
  const scopeBaseTag = dom.query.getParentElement(prevScopeTag || editor.selection.getNode(), (current) => scopeTagList.includes(current.nodeName?.toLowerCase()));
80
- const selectArea = scopeBaseTag || ww;
81
109
 
82
- let first =
83
- dom.query.getEdgeChild(
84
- dom.query.getEdgeChild(selectArea, (current) => !dom.check.isContentLess(current), false),
85
- (current) => {
86
- return current.childNodes.length === 0 || current.nodeType === 3 || dom.check.isTable(current);
87
- },
88
- false
89
- ) || selectArea.firstChild;
90
- let last =
91
- dom.query.getEdgeChild(
92
- selectArea.lastChild,
93
- (current) => {
94
- return current.childNodes.length === 0 || current.nodeType === 3 || dom.check.isTable(current);
95
- },
96
- true
97
- ) || selectArea.lastChild;
110
+ let selectArea = scopeBaseTag || ww;
111
+ let { first, last } = __findFirstAndLast(selectArea);
112
+
113
+ if (!first || !last) return;
114
+
115
+ const isZeroWidth = dom.check.isZeroWidth;
116
+ while (isZeroWidth(first) && isZeroWidth(last) && selectArea !== ww) {
117
+ selectArea = selectArea.parentElement;
118
+ ({ first, last } = __findFirstAndLast(dom.query.getParentElement(selectArea, (current) => scopeTagList.includes(current.nodeName?.toLowerCase())) || ww));
119
+ }
98
120
 
99
121
  if (!first || !last) return;
100
122
 
101
- if (dom.check.isMedia(first) || editor.component.is(first.parentElement) || dom.check.isTableElements(first)) {
102
- const info = editor.component.get(first) || editor.component.get(first.parentElement);
123
+ let info = null;
124
+ if (dom.check.isMedia(first) || (info = editor.component.get(first.parentElement)) || dom.check.isTableElements(first)) {
103
125
  const br = dom.utils.createElement('BR');
104
126
  const format = dom.utils.createElement(editor.options.get('defaultLine'), null, br);
105
127
  first = info ? info.container || info.cover : first;
106
- first.parentNode.insertBefore(format, first);
128
+ first.parentElement.insertBefore(format, first);
107
129
  first = br;
108
130
  }
109
131
 
110
- if (dom.check.isMedia(last) || editor.component.is(last.parentElement) || dom.check.isTableElements(last)) {
111
- last = dom.utils.createElement('BR');
112
- selectArea.appendChild(dom.utils.createElement(editor.options.get('defaultLine'), null, last));
132
+ if (dom.check.isMedia(last) || (info = editor.component.get(last.parentElement)) || dom.check.isTableElements(last)) {
133
+ const br = dom.utils.createElement('BR');
134
+ const format = dom.utils.createElement(editor.options.get('defaultLine'), null, br);
135
+ last = info ? info.container || info.cover : last;
136
+ last.parentElement.appendChild(format);
137
+ last = br;
113
138
  }
114
139
 
115
140
  editor.toolbar._showBalloon(editor.selection.setRange(first, 0, last, last.textContent.length));
@@ -224,107 +224,115 @@ const RETAIN_STYLE_MODE = ['repeat', 'always', 'none'];
224
224
  * @typedef {EditorBaseOptions & EditorFrameOptions} EditorInitOptions
225
225
  */
226
226
 
227
+ /** ------------- [OPTIONS FRAG] ------------- */
227
228
  /**
228
229
  * @description For all EditorInitOptions keys, only boolean | null values are allowed.
229
230
  * - 'fixed' → Immutable / null → Resettable.
230
231
  * @type {Partial<Record<keyof EditorInitOptions, "fixed" | true>>}
231
232
  */
232
- export const OPTION_FIXED_FLAG = {
233
+ export const OPTION_FRAME_FIXED_FLAG = {
233
234
  value: 'fixed',
234
- placeholder: 'fixed',
235
- editableFrameAttributes: null,
236
- width: null,
237
- minWidth: null,
238
- maxWidth: null,
239
- height: null,
240
- minHeight: null,
241
- maxHeight: null,
242
- editorStyle: null,
235
+ placeholder: true,
236
+ editableFrameAttributes: true,
237
+ width: true,
238
+ minWidth: true,
239
+ maxWidth: true,
240
+ height: true,
241
+ minHeight: true,
242
+ maxHeight: true,
243
+ editorStyle: true,
243
244
  iframe: 'fixed',
244
- iframe_fullPage: null,
245
- iframe_attributes: null,
246
- iframe_cssFileName: null,
247
- statusbar: null,
248
- statusbar_showPathLabel: null,
249
- statusbar_resizeEnable: null,
250
- charCounter: null,
251
- charCounter_max: null,
252
- charCounter_label: null,
253
- charCounter_type: null,
254
- plugins: null,
255
- excludedPlugins: null,
245
+ iframe_fullPage: 'fixed',
246
+ iframe_attributes: true,
247
+ iframe_cssFileName: true,
248
+ statusbar: true,
249
+ statusbar_showPathLabel: true,
250
+ statusbar_resizeEnable: 'fixed',
251
+ charCounter: true,
252
+ charCounter_max: true,
253
+ charCounter_label: true,
254
+ charCounter_type: true
255
+ };
256
+ /**
257
+ * @description For all EditorInitOptions keys, only boolean | null values are allowed.
258
+ * - 'fixed' → Immutable / null → Resettable.
259
+ * @type {Partial<Record<keyof EditorInitOptions, "fixed" | true>>}
260
+ */
261
+ export const OPTION_FIXED_FLAG = {
262
+ plugins: 'fixed',
263
+ excludedPlugins: 'fixed',
256
264
  buttonList: 'fixed',
257
- v2Migration: null,
258
- strictMode: null,
265
+ v2Migration: 'fixed',
266
+ strictMode: 'fixed',
259
267
  mode: 'fixed',
260
268
  type: 'fixed',
261
- theme: null,
269
+ theme: true,
262
270
  lang: 'fixed',
263
271
  fontSizeUnits: 'fixed',
264
- allowedClassName: null,
265
- closeModalOutsideClick: null,
266
- copyFormatKeepOn: null,
267
- syncTabIndent: null,
268
- tabDisable: null,
269
- autoLinkify: null,
270
- autoStyleify: null,
271
- scrollToOptions: null,
272
- componentScrollToOptions: null,
273
- retainStyleMode: null,
274
- allowedExtraTags: null,
275
- events: null,
272
+ allowedClassName: 'fixed',
273
+ closeModalOutsideClick: 'fixed',
274
+ copyFormatKeepOn: true,
275
+ syncTabIndent: true,
276
+ tabDisable: true,
277
+ autoLinkify: true,
278
+ autoStyleify: true,
279
+ scrollToOptions: true,
280
+ componentScrollToOptions: true,
281
+ retainStyleMode: true,
282
+ allowedExtraTags: 'fixed',
283
+ events: true,
276
284
  __textStyleTags: 'fixed',
277
285
  textStyleTags: 'fixed',
278
286
  convertTextTags: 'fixed',
279
- __tagStyles: null,
287
+ __tagStyles: 'fixed',
280
288
  tagStyles: 'fixed',
281
289
  spanStyles: 'fixed',
282
290
  lineStyles: 'fixed',
283
- textDirection: null,
284
- reverseButtons: null,
285
- historyStackDelayTime: null,
286
- lineAttrReset: null,
287
- printClass: null,
291
+ textDirection: true,
292
+ reverseButtons: 'fixed',
293
+ historyStackDelayTime: true,
294
+ lineAttrReset: true,
295
+ printClass: true,
288
296
  defaultLine: 'fixed',
289
- defaultLineBreakFormat: null,
290
- scopeSelectionTags: null,
297
+ defaultLineBreakFormat: true,
298
+ scopeSelectionTags: true,
291
299
  __defaultElementWhitelist: 'fixed',
292
300
  elementWhitelist: 'fixed',
293
301
  elementBlacklist: 'fixed',
294
302
  __defaultAttributeWhitelist: 'fixed',
295
303
  attributeWhitelist: 'fixed',
296
304
  attributeBlacklist: 'fixed',
297
- __defaultFormatLine: null,
305
+ __defaultFormatLine: 'fixed',
298
306
  formatLine: 'fixed',
299
- __defaultFormatBrLine: null,
307
+ __defaultFormatBrLine: 'fixed',
300
308
  formatBrLine: 'fixed',
301
309
  __defaultFormatClosureBrLine: 'fixed',
302
310
  formatClosureBrLine: 'fixed',
303
- __defaultFormatBlock: null,
311
+ __defaultFormatBlock: 'fixed',
304
312
  formatBlock: 'fixed',
305
- __defaultFormatClosureBlock: null,
313
+ __defaultFormatClosureBlock: 'fixed',
306
314
  formatClosureBlock: 'fixed',
307
- allowedEmptyTags: null,
308
- toolbar_width: null,
315
+ allowedEmptyTags: true,
316
+ toolbar_width: true,
309
317
  toolbar_container: 'fixed',
310
- toolbar_sticky: null,
311
- toolbar_hide: null,
318
+ toolbar_sticky: true,
319
+ toolbar_hide: true,
312
320
  subToolbar: 'fixed',
313
321
  statusbar_container: 'fixed',
314
- shortcutsHint: null,
322
+ shortcutsHint: true,
315
323
  shortcutsDisable: 'fixed',
316
324
  shortcuts: 'fixed',
317
- fullScreenOffset: null,
318
- previewTemplate: null,
319
- printTemplate: null,
320
- componentAutoSelect: null,
321
- defaultUrlProtocol: null,
322
- allUsedStyles: null,
323
- toastMessageTime: null,
325
+ fullScreenOffset: true,
326
+ previewTemplate: true,
327
+ printTemplate: true,
328
+ componentAutoSelect: true,
329
+ defaultUrlProtocol: true,
330
+ allUsedStyles: 'fixed',
331
+ toastMessageTime: true,
324
332
  icons: 'fixed',
325
- freeCodeViewMode: null,
326
- __lineFormatFilter: null,
327
- __pluginRetainFilter: null,
333
+ freeCodeViewMode: true,
334
+ __lineFormatFilter: true,
335
+ __pluginRetainFilter: true,
328
336
  __listCommonStyle: 'fixed',
329
337
  externalLibs: 'fixed'
330
338
  };
@@ -438,7 +446,7 @@ function Constructor(editorTargets, options) {
438
446
  const to = optionMap.frameMap.get(editTarget.key);
439
447
  const top_div = dom.utils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') });
440
448
  const container = dom.utils.createElement('DIV', { class: 'se-container' });
441
- const editor_div = dom.utils.createElement('DIV', { class: 'se-wrapper' + (o.get('type') === 'document' ? ' se-type-document' : '') });
449
+ const editor_div = dom.utils.createElement('DIV', { class: 'se-wrapper' + (o.get('type') === 'document' ? ' se-type-document' : '') + (o.get('_type_options').includes('header') ? ' se-type-document-header' : '') });
442
450
 
443
451
  container.appendChild(dom.utils.createElement('DIV', { class: 'se-toolbar-shadow' }));
444
452
 
@@ -574,13 +582,16 @@ export function CreateShortcuts(command, button, values, keyMap, rc, reverseKeys
574
582
  plugin = null;
575
583
  method = a[a.length - 1].trim?.();
576
584
  if (method.startsWith('~')) {
585
+ // plugin key, method
577
586
  plugin = command;
578
587
  method = a.pop().trim().substring(1);
579
- } else if (method.startsWith('p~')) {
588
+ } else if (method.startsWith('$~')) {
589
+ // custom key, plugin method
580
590
  const a_ = a.pop().trim().substring(2).split('.');
581
591
  plugin = a_[0];
582
592
  method = a_[1];
583
593
  } else if (method.startsWith('$')) {
594
+ // directly method
584
595
  _i = 1;
585
596
  method = values[i + 2];
586
597
  } else {
@@ -613,13 +624,16 @@ export function CreateShortcuts(command, button, values, keyMap, rc, reverseKeys
613
624
  }
614
625
  }
615
626
 
616
- k = c ? v + (s ? '1000' : '') : v;
617
- if (!keyMap.has(k)) {
618
- r = rc.indexOf(command);
619
- r = r === -1 ? '' : numbers.isOdd(r) ? rc[r + 1] : rc[r - 1];
620
- if (r) reverseKeys.push(k);
627
+ v = v.split('|');
628
+ for (let j = 0, len = v.length; j < len; j++) {
629
+ k = c ? v[j] + (s ? '1000' : '') : v[j];
630
+ if (!keyMap.has(k)) {
631
+ r = rc.indexOf(command);
632
+ r = r === -1 ? '' : numbers.isOdd(r) ? rc[r + 1] : rc[r - 1];
633
+ if (r) reverseKeys.push(k);
621
634
 
622
- keyMap.set(k, { c, s, edge, space, enter, textTrigger, plugin, command, method, r, type: button?.getAttribute('data-type'), button, key: k });
635
+ keyMap.set(k, { c, s, edge, space, enter, textTrigger, plugin, command, method, r, type: button?.getAttribute('data-type'), button, key: k });
636
+ }
623
637
  }
624
638
 
625
639
  if (!(t = values[i + 1])) continue;
@@ -809,7 +823,7 @@ export function InitOptions(options, editorTargets, plugins) {
809
823
  /** whitelist, blacklist */
810
824
  // default line
811
825
  o.set('defaultLine', typeof options.defaultLine === 'string' && options.defaultLine.length > 0 ? options.defaultLine : 'p');
812
- o.set('_defaultBrLineBreak', options.defaultLineBreakFormat === 'br');
826
+ o.set('defaultLineBreakFormat', options.defaultLineBreakFormat || 'line');
813
827
  o.set('scopeSelectionTags', options.scopeSelectionTags || DEFAULT_SCOPE_SELECTION_TAGS.split('|'));
814
828
  // element
815
829
  const elw = (typeof options.elementWhitelist === 'string' ? options.elementWhitelist : '').toLowerCase();
@@ -926,9 +940,9 @@ export function InitOptions(options, editorTargets, plugins) {
926
940
  list_numbered: ['!+1.+_+~shortcut', ''],
927
941
  list_bulleted: ['!+*.+_+~shortcut', ''],
928
942
  // custom
929
- _h1: ['c+s+Digit1+p~formatBlock.createHeader', ''],
930
- _h2: ['c+s+Digit2+p~formatBlock.createHeader', ''],
931
- _h3: ['c+s+Digit3+p~formatBlock.createHeader', '']
943
+ _h1: ['c+s+Digit1|Numpad1+$~formatBlock.applyHeaderByShortcut', ''],
944
+ _h2: ['c+s+Digit2|Numpad2+$~formatBlock.applyHeaderByShortcut', ''],
945
+ _h3: ['c+s+Digit3|Numpad3+$~formatBlock.applyHeaderByShortcut', '']
932
946
  },
933
947
  options.shortcuts || {}
934
948
  ].reduce((_default, _new) => {
@@ -1115,6 +1129,7 @@ function InitFrameOptions(o, origin) {
1115
1129
  fo.set('height', height ? (numbers.is(height) ? height + 'px' : height) : 'auto');
1116
1130
  fo.set('minHeight', (numbers.is(minHeight) ? minHeight + 'px' : minHeight) || '');
1117
1131
  fo.set('maxHeight', (numbers.is(maxHeight) ? maxHeight + 'px' : maxHeight) || '');
1132
+ fo.set('editorStyle', editorStyle);
1118
1133
  fo.set('_defaultStyles', converter._setDefaultOptionStyle(fo, typeof editorStyle === 'string' ? editorStyle : ''));
1119
1134
  // iframe
1120
1135
  fo.set('iframe', !!(iframe_fullPage || iframe));
@@ -1175,9 +1190,8 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
1175
1190
 
1176
1191
  // textarea for code view
1177
1192
  const textarea = dom.utils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-code-viewer', style: editorStyles.frame });
1178
- let placeholder = null;
1193
+ const placeholder = dom.utils.createElement('SPAN', { class: 'se-placeholder' });
1179
1194
  if (targetOptions.get('placeholder')) {
1180
- placeholder = dom.utils.createElement('SPAN', { class: 'se-placeholder' });
1181
1195
  placeholder.textContent = targetOptions.get('placeholder');
1182
1196
  }
1183
1197