suneditor 3.0.0-alpha.13 → 3.0.0-alpha.15

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 (35) hide show
  1. package/dist/suneditor.min.css +1 -1
  2. package/dist/suneditor.min.js +1 -1
  3. package/package.json +2 -1
  4. package/src/assets/icons/_default.js +9 -2
  5. package/src/assets/suneditor-contents.css +9 -22
  6. package/src/assets/suneditor.css +317 -183
  7. package/src/assets/variables.css +137 -0
  8. package/src/core/base/eventHandlers/handler_toolbar.js +1 -0
  9. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +9 -2
  10. package/src/core/base/eventHandlers/handler_ww_key_input.js +1 -1
  11. package/src/core/base/eventManager.js +5 -0
  12. package/src/core/class/component.js +12 -8
  13. package/src/core/class/html.js +5 -5
  14. package/src/core/class/offset.js +11 -3
  15. package/src/core/class/selection.js +5 -4
  16. package/src/core/class/toolbar.js +1 -5
  17. package/src/core/class/viewer.js +29 -7
  18. package/src/core/editor.js +61 -1
  19. package/src/core/section/actives.js +5 -0
  20. package/src/core/section/constructor.js +35 -19
  21. package/src/core/section/documentType.js +143 -19
  22. package/src/helper/domUtils.js +5 -4
  23. package/src/langs/en.js +5 -0
  24. package/src/modules/Modal.js +108 -1
  25. package/src/plugins/command/exportPdf.js +1 -1
  26. package/src/plugins/command/list_bulleted.js +1 -1
  27. package/src/plugins/command/list_numbered.js +1 -1
  28. package/src/plugins/index.js +6 -0
  29. package/src/plugins/input/fontSize.js +3 -3
  30. package/src/plugins/input/pageNavigator.js +47 -0
  31. package/src/plugins/modal/drawing.js +426 -0
  32. package/src/plugins/modal/image.js +3 -2
  33. package/src/plugins/modal/math.js +72 -34
  34. package/src/themes/dark-variables.css +85 -0
  35. package/src/themes/test.css +0 -61
@@ -43,6 +43,7 @@ const DEFAULT_CONTENT_STYLES =
43
43
  'margin|margin-block-end|margin-block-start|margin-bottom|margin-inline-end|margin-inline-start|margin-left|margin-right|margin-top|max-width|min-width|' +
44
44
  'outline|overflow|' +
45
45
  'position|padding|padding-bottom|padding-inline-start|padding-left|padding-right|padding-top|' +
46
+ 'page-break-before|page-break-after|page-break-inside|' +
46
47
  'rotate|rotateX|rotateY|' +
47
48
  'table-layout|text-align|text-decoration|text-shadow|text-transform|top|' +
48
49
  'text-indent|text-rendering|' +
@@ -118,7 +119,7 @@ const Constructor = function (editorTargets, options) {
118
119
  const loadingBox = domUtils.createElement('DIV', { class: 'se-loading-box sun-editor-common' }, '<div class="se-loading-effect"></div>');
119
120
 
120
121
  /** --- carrier wrapper --------------------------------------------------------------- */
121
- const editor_carrier_wrapper = domUtils.createElement('DIV', { class: 'sun-editor sun-editor-carrier-wrapper sun-editor-common' + (o.get('_rtl') ? ' se-rtl' : '') });
122
+ const editor_carrier_wrapper = domUtils.createElement('DIV', { class: 'sun-editor sun-editor-carrier-wrapper sun-editor-common' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') });
122
123
  // menuTray
123
124
  const menuTray = domUtils.createElement('DIV', { class: 'se-menu-tray' });
124
125
  editor_carrier_wrapper.appendChild(menuTray);
@@ -185,7 +186,7 @@ const Constructor = function (editorTargets, options) {
185
186
  for (let i = 0, len = editorTargets.length; i < len; i++) {
186
187
  const editTarget = editorTargets[i];
187
188
  const to = editTarget.options;
188
- const top_div = domUtils.createElement('DIV', { class: 'sun-editor' + (to.get('_rtl') ? ' se-rtl' : '') });
189
+ const top_div = domUtils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') + (to.get('_rtl') ? ' se-rtl' : '') });
189
190
  const container = domUtils.createElement('DIV', { class: 'se-container' });
190
191
  const editor_div = domUtils.createElement('DIV', { class: 'se-wrapper' + (o.get('type') === 'document' ? ' se-type-document' : '') });
191
192
 
@@ -215,7 +216,7 @@ const Constructor = function (editorTargets, options) {
215
216
  if (statusbar) {
216
217
  if (statusbarContainer) {
217
218
  if (!default_status_bar) {
218
- statusbarContainer.appendChild(domUtils.createElement('DIV', { class: 'sun-editor' }, statusbar));
219
+ statusbarContainer.appendChild(domUtils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') }, statusbar));
219
220
  default_status_bar = statusbar;
220
221
  }
221
222
  } else {
@@ -264,7 +265,7 @@ const Constructor = function (editorTargets, options) {
264
265
  // toolbar container
265
266
  const toolbar_container = o.get('toolbar_container');
266
267
  if (toolbar_container) {
267
- const top_div = domUtils.createElement('DIV', { class: 'sun-editor' + (o.get('_rtl') ? ' se-rtl' : '') });
268
+ const top_div = domUtils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') });
268
269
  const container = domUtils.createElement('DIV', { class: 'se-container' });
269
270
  container.appendChild(toolbar);
270
271
  if (subbar) container.appendChild(subbar);
@@ -362,6 +363,7 @@ export function InitOptions(options, editorTargets, plugins) {
362
363
  o.set('v2Migration', !!options.v2Migration);
363
364
 
364
365
  /** Base */
366
+ o.set('buttons', new Set(buttonList.toString().split(',')));
365
367
  const modeValue = options.strictMode !== false;
366
368
  o.set('strictMode', {
367
369
  tagFilter: modeValue,
@@ -376,6 +378,8 @@ export function InitOptions(options, editorTargets, plugins) {
376
378
  o.set('__pluginRetainFilter', options.__pluginRetainFilter ?? true);
377
379
  o.set('mode', options.mode || 'classic'); // classic, inline, balloon, balloon-always
378
380
  o.set('type', options.type?.split(':')[0] || ''); // document:header,page
381
+ o.set('theme', options.theme || '');
382
+ o.set('_themeClass', options.theme ? ` se-theme-${options.theme}` : '');
379
383
  o.set('type-options', options.type?.split(':')[1] || '');
380
384
  o.set('externalLibs', options.externalLibs || {});
381
385
  o.set('keepStyleOnDelete', !!options.keepStyleOnDelete);
@@ -485,9 +489,9 @@ export function InitOptions(options, editorTargets, plugins) {
485
489
 
486
490
  // etc
487
491
  o.set('historyStackDelayTime', typeof options.historyStackDelayTime === 'number' ? options.historyStackDelayTime : 400);
488
- o.set('_editableClass', 'sun-editor-editable' + (o.get('_rtl') ? ' se-rtl' : ''));
492
+ o.set('_editableClass', 'sun-editor-editable' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : ''));
489
493
  o.set('lineAttrReset', ['id'].concat(options.lineAttrReset && typeof options.lineAttrReset === 'string' ? options.lineAttrReset.toLowerCase().split('|') : []));
490
- o.set('printClass', typeof options.printClass === 'string' ? options.printClass : null);
494
+ o.set('printClass', typeof options.printClass === 'string' ? options.printClass + ' ' + o.get('_editableClass') : null);
491
495
 
492
496
  /** whitelist, blacklist */
493
497
  // default line
@@ -571,6 +575,7 @@ export function InitOptions(options, editorTargets, plugins) {
571
575
  o.set('_subMode', subbar.mode || 'balloon');
572
576
  o.set('toolbar.sub_width', subbar.width ? (numbers.is(subbar.width) ? subbar.width + 'px' : subbar.width) : 'auto');
573
577
  subButtons = o.get('_rtl') ? subbar.buttonList.reverse() : subbar.buttonList;
578
+ o.set('buttons_sub', new Set(subButtons.toString().split(',')));
574
579
  }
575
580
  }
576
581
 
@@ -986,7 +991,12 @@ function _defaultButtons(options, icons, lang) {
986
991
  dir_rtl: ['', lang.dir_rtl, 'dir_rtl', '', icons.dir_rtl],
987
992
  save: ['se-component-enabled', lang.save, 'save', '', icons.save],
988
993
  newDocument: ['se-component-enabled', lang.newDocument, 'newDocument', '', icons.new_document],
989
- selectAll: ['se-component-enabled', lang.selectAll, 'selectAll', '', icons.select_all]
994
+ selectAll: ['se-component-enabled', lang.selectAll, 'selectAll', '', icons.select_all],
995
+ pageBreak: ['se-component-enabled', lang.pageBreak, 'pageBreak', '', icons.page_break],
996
+ // document type buttons
997
+ pageUp: ['se-component-enabled', lang.pageUp, 'pageUp', '', icons.page_up],
998
+ pageDown: ['se-component-enabled', lang.pageDown, 'pageDown', '', icons.page_down],
999
+ pageNavigator: ['se-component-enabled', '', 'pageNavigator', 'input', '']
990
1000
  };
991
1001
  }
992
1002
 
@@ -1016,6 +1026,8 @@ function _createModuleGroup() {
1016
1026
  * @returns {Object}
1017
1027
  */
1018
1028
  function _createButton(className, title, dataCommand, dataType, innerHTML, _disabled, icons) {
1029
+ if (!innerHTML) innerHTML = '';
1030
+
1019
1031
  const oLi = domUtils.createElement('LI');
1020
1032
  const label = title || '';
1021
1033
  const isDiv = /^INPUT|FIELD$/i.test(dataType);
@@ -1066,9 +1078,13 @@ export function UpdateButton(element, plugin, icons, lang) {
1066
1078
 
1067
1079
  const noneInner = plugin.inner === false;
1068
1080
 
1069
- element.innerHTML = noneInner
1070
- ? ''
1071
- : (plugin.inner || icons[plugin.icon] || plugin.icon || '<span class="se-icon-text">!</span>') + '<span class="se-tooltip-inner"><span class="se-tooltip-text">' + (lang[plugin.title] || plugin.title) + '</span></span>';
1081
+ if (plugin.inner?.nodeType === 1) {
1082
+ element.appendChild(plugin.inner);
1083
+ } else {
1084
+ element.innerHTML = noneInner
1085
+ ? ''
1086
+ : (plugin.inner || icons[plugin.icon] || plugin.icon || '<span class="se-icon-text">!</span>') + '<span class="se-tooltip-inner"><span class="se-tooltip-text">' + (lang[plugin.title] || plugin.title) + '</span></span>';
1087
+ }
1072
1088
 
1073
1089
  element.setAttribute('aria-label', plugin.title);
1074
1090
 
@@ -1081,24 +1097,24 @@ export function UpdateButton(element, plugin, icons, lang) {
1081
1097
  }
1082
1098
 
1083
1099
  // side, replace button
1084
- if (plugin.afterButton) {
1085
- domUtils.addClass(plugin.afterButton, 'se-toolbar-btn');
1086
- element.parentElement.appendChild(plugin.afterButton);
1100
+ if (plugin.afterItem) {
1101
+ domUtils.addClass(plugin.afterItem, 'se-toolbar-btn');
1102
+ element.parentElement.appendChild(plugin.afterItem);
1087
1103
 
1088
1104
  domUtils.addClass(element, 'se-side-btn-a');
1089
- domUtils.addClass(plugin.afterButton, 'se-side-btn-after');
1105
+ domUtils.addClass(plugin.afterItem, 'se-side-btn-after');
1090
1106
  }
1091
- if (plugin.beforeButton) {
1092
- domUtils.addClass(plugin.beforeButton, 'se-toolbar-btn');
1093
- element.parentElement.insertBefore(plugin.beforeButton, element);
1107
+ if (plugin.beforeItem) {
1108
+ domUtils.addClass(plugin.beforeItem, 'se-toolbar-btn');
1109
+ element.parentElement.insertBefore(plugin.beforeItem, element);
1094
1110
 
1095
- if (plugin.afterButton) {
1111
+ if (plugin.afterItem) {
1096
1112
  domUtils.addClass(element, 'se-side-btn');
1097
1113
  domUtils.removeClass(element, 'se-side-btn-a');
1098
1114
  } else {
1099
1115
  domUtils.addClass(element, 'se-side-btn-b');
1100
1116
  }
1101
- domUtils.addClass(plugin.beforeButton, 'se-side-btn-before');
1117
+ domUtils.addClass(plugin.beforeItem, 'se-side-btn-before');
1102
1118
  }
1103
1119
  if (plugin.replaceButton) {
1104
1120
  element.parentElement.appendChild(plugin.replaceButton);
@@ -2,27 +2,38 @@
2
2
  * @fileoverview DocumentType class
3
3
  */
4
4
 
5
- import { domUtils, numbers, env } from '../../helper';
5
+ import { domUtils, numbers, converter, env } from '../../helper';
6
6
 
7
+ const { _w } = env;
7
8
  const A4_HEIGHT_INCHES = 11.7; // A4 height(inches)
8
- const A4_HEIGHT = A4_HEIGHT_INCHES * env.DPI * 96; // 1 inch = 96px
9
+ const A4_HEIGHT = A4_HEIGHT_INCHES * 96; // 1 inch = 96px
9
10
 
10
11
  const DocumentType = function (editor, fc) {
11
12
  // members
12
13
  this.editor = editor;
14
+ this.selection = editor.selection;
15
+ this.offset = editor.offset;
13
16
  this.fc = fc;
14
17
  this.ww = fc.get('wysiwyg');
15
18
  this.wwFrame = fc.get('wysiwygFrame');
16
19
  this.wwWidth = -1;
20
+ this.wwHeight = -1;
21
+ this.isAutoHeight = fc.get('options').get('height') === 'auto';
22
+ this.displayPage = this.isAutoHeight ? _w : fc.get('wysiwyg');
17
23
  this.innerHeaders = [];
18
24
  this._wwHeaders = [];
19
25
  this.inner = null;
20
26
  this.page = null;
27
+ this.totalPages = 0;
28
+ this.pageNum = 0;
21
29
  this.pageHeight = -1;
22
30
  this.pages = [];
23
31
  this.pages_line = [];
32
+ this.prevScrollTop = 0;
24
33
  this.useHeader = editor.options.get('type-options').includes('header');
25
34
  this.usePage = editor.options.get('type-options').includes('page');
35
+ this.navigatorButtons = [];
36
+ this.pageNavigator = null;
26
37
 
27
38
  // init header
28
39
  if (this.useHeader) {
@@ -42,6 +53,7 @@ const DocumentType = function (editor, fc) {
42
53
  // init page
43
54
  if (this.usePage) {
44
55
  this.page = fc.get('documentTypePage');
56
+ this.pageNavigator = editor.plugins.pageNavigator;
45
57
  }
46
58
  };
47
59
 
@@ -85,43 +97,101 @@ DocumentType.prototype = {
85
97
  rePage() {
86
98
  if (!this.page) return;
87
99
 
88
- const height = this.wwFrame.scrollHeight;
100
+ const height = this.displayPage.scrollHeight ?? this.ww.scrollHeight;
89
101
  if (this.pageHeight === height) return;
90
102
  this.pageHeight = height;
91
103
 
92
- const page = this.page;
93
- const scrollTop = this.ww.scrollTop;
94
- const wwWidth = this.wwFrame.offsetWidth + 1;
95
104
  const totalPages = Math.ceil(height / A4_HEIGHT);
105
+ const scrollTop = (this.prevScrollTop = this._getWWScrollTop());
106
+ const wwWidth = this.wwFrame.offsetWidth + 1;
107
+ const pageBreaks = this.ww.querySelectorAll('.se-page-break');
108
+
109
+ const pages = [];
110
+ const pageTop = this.page.offsetTop;
111
+ for (let i = 0, len = pageBreaks.length; i < len; i++) {
112
+ pages.push({ number: i, top: pageBreaks[i].offsetTop - pageTop + pageBreaks[i].offsetHeight / 2 - scrollTop });
113
+ }
96
114
 
115
+ for (let i = 0, t; i < totalPages; i++) {
116
+ t = i * A4_HEIGHT - scrollTop;
117
+ let inserted = false;
118
+ for (let j = 0, jLen = pages.length; j < jLen; j++) {
119
+ if (t < pages[j].top) {
120
+ pages.splice(j, 0, { number: i + pageBreaks.length, top: t });
121
+ inserted = true;
122
+ break;
123
+ }
124
+ }
125
+ if (!inserted) {
126
+ pages.push({ number: i + pageBreaks.length, top: t });
127
+ }
128
+ }
129
+
130
+ // set page number
97
131
  this.page.innerHTML = '';
98
132
  this.pages = [];
99
- for (let i = 0; i < totalPages; i++) {
100
- const pageNumber = domUtils.createElement('DIV', { style: `top:${i * A4_HEIGHT + scrollTop}px`, innerHTML: i + 1 }, `<div class="se-document-page-line" style="width: ${wwWidth}px;"></div>${i + 1}`);
101
- page.appendChild(pageNumber);
133
+ for (let i = 0, len = pages.length; i < len; i++) {
134
+ const pageNumber = domUtils.createElement('DIV', { style: `top:${pages[i].top}px`, innerHTML: i + 1 }, `<div class="se-document-page-line" style="width: ${wwWidth}px;"></div>${i + 1}`);
135
+ this.page.appendChild(pageNumber);
102
136
  this.pages.push(pageNumber);
103
137
  }
104
138
 
105
139
  this.pages_line = this.page.querySelectorAll('.se-document-page-line');
106
- },
107
-
108
- scrollPage() {
109
- const scrollTop = this.wwFrame.scrollTop;
110
- const pages = this.pages;
111
- for (let i = 0, len = pages.length; i < len; i++) {
112
- pages[i].style.top = `${i * A4_HEIGHT - scrollTop}px`;
113
- }
140
+ this.totalPages = totalPages;
114
141
  },
115
142
 
116
143
  resizePage() {
117
144
  const wwWidth = this.wwFrame.offsetWidth + 1;
118
- if (wwWidth === this.wwWidth) return;
145
+ const wwHeight = this.wwFrame.offsetHeight + 1;
146
+ if (wwWidth === this.wwWidth || wwHeight === this.wwHeight) return;
119
147
 
120
148
  this.wwWidth = wwWidth;
149
+ this.wwHeight = wwHeight;
121
150
  const pages_line = this.pages_line;
122
151
  for (let i = 0, len = pages_line.length; i < len; i++) {
123
152
  pages_line[i].style.width = `${wwWidth}px`;
124
153
  }
154
+
155
+ this._displayCurrentPage();
156
+ },
157
+
158
+ scrollPage() {
159
+ const prevScrollTop = this.prevScrollTop;
160
+ const scrollTop = this._getWWScrollTop();
161
+ if (prevScrollTop === scrollTop) return;
162
+
163
+ const pages = this.pages;
164
+ for (let i = 0, len = pages.length; i < len; i++) {
165
+ pages[i].style.top = `${numbers.get(pages[i].style.top) - (scrollTop - prevScrollTop)}px`;
166
+ }
167
+
168
+ this.prevScrollTop = scrollTop;
169
+ this._displayCurrentPage();
170
+ },
171
+
172
+ getCurrentPageNumber() {
173
+ if (this.totalPages <= 1) return 1;
174
+
175
+ const scrollTop = this.isAutoHeight ? _w.scrollY + this.wwHeight / 2 - this._getGlobalTop() : this._getWWScrollTop() + this.wwHeight / 2;
176
+ const pageNum = this.isAutoHeight ? Math.floor(scrollTop / A4_HEIGHT) : Math.ceil(scrollTop / A4_HEIGHT);
177
+ return (this.pageNum = pageNum < 1 ? 1 : pageNum > this.pages.length ? this.pages.length : pageNum);
178
+ },
179
+
180
+ pageUp() {
181
+ const pageNum = this.pageNum - 1 <= 1 ? 1 : this.pageNum - 1;
182
+ this._movePage(pageNum, false);
183
+ },
184
+
185
+ pageDown() {
186
+ const pageNum = this.pageNum + 1 > this.pages.length ? this.pages.length : this.pageNum + 1;
187
+ this._movePage(pageNum, false);
188
+ },
189
+
190
+ pageGo(pageNum) {
191
+ if (pageNum < 1) pageNum = 1;
192
+ else if (pageNum > this.pages.length) pageNum = this.pages.length;
193
+
194
+ this._movePage(pageNum, true);
125
195
  },
126
196
 
127
197
  on(line) {
@@ -146,6 +216,60 @@ DocumentType.prototype = {
146
216
  item.textContent = header.textContent;
147
217
  },
148
218
 
219
+ scrollWindow() {
220
+ if (!this.isAutoHeight) return;
221
+ this._displayCurrentPage();
222
+ },
223
+
224
+ _displayCurrentPage() {
225
+ const pageNum = this.getCurrentPageNumber();
226
+ this.pageNavigator?.display(pageNum, this.totalPages);
227
+ },
228
+
229
+ _getWWScrollTop() {
230
+ return this.displayPage.scrollTop || 0;
231
+ },
232
+
233
+ _movePage(pageNum, force) {
234
+ if (!force && this.pageNum === pageNum) return;
235
+
236
+ const globalTop = this._getGlobalTop();
237
+ const children = converter.nodeListToArray(this.ww.children);
238
+ const pageTop = this.page.offsetTop + numbers.get(this.pages[pageNum - 1].style.top) + this._getWWScrollTop();
239
+ for (let i = 0, len = children.length, c; i < len; i++) {
240
+ c = children[i];
241
+ if (c.offsetTop >= pageTop) {
242
+ if (!force) this.selection.setRange(c, 0, c, 0);
243
+ const scrollTop = i === 0 && !this.isAutoHeight ? 0 : c.offsetTop - this.page.offsetTop - c.offsetHeight + globalTop;
244
+ this._applyPageScroll(scrollTop, () => {
245
+ if (this.editor.toolbar._sticky) {
246
+ this.displayPage.scrollTo({ top: scrollTop - this.editor.context.get('toolbar.main').offsetHeight, behavior: 'smooth' });
247
+ }
248
+ });
249
+
250
+ this.pageNum = pageNum;
251
+ break;
252
+ }
253
+ }
254
+ },
255
+
256
+ _applyPageScroll(top, callback) {
257
+ this.displayPage.scrollTo({ top, behavior: 'smooth' });
258
+ const checkScrollEnd = () => {
259
+ if (Math.abs((this.displayPage.scrollY ?? this.displayPage.scrollTop) - top) < 1) {
260
+ callback();
261
+ } else {
262
+ _w.requestAnimationFrame(checkScrollEnd);
263
+ }
264
+ };
265
+
266
+ _w.requestAnimationFrame(checkScrollEnd);
267
+ },
268
+
269
+ _getGlobalTop() {
270
+ return this.isAutoHeight ? this.offset.getGlobal(this.wwFrame).top : 0;
271
+ },
272
+
149
273
  _findItem(header) {
150
274
  const headers = this._wwHeaders;
151
275
  const index = Array.prototype.indexOf.call(headers, header);
@@ -191,7 +315,7 @@ function OnClickHeader(ww, e) {
191
315
 
192
316
  const header = this._wwHeaders[innerIndex];
193
317
  if (header) {
194
- this.editor.selection.scrollTo(header);
318
+ this.selection.scrollTo(header);
195
319
  }
196
320
  }
197
321
  } finally {
@@ -1163,11 +1163,12 @@ export function applyInlineStylesAll(wwTarget, includeWW, styles) {
1163
1163
  tempTarget.appendChild(wwTarget);
1164
1164
  _d.body.appendChild(tempTarget);
1165
1165
 
1166
- const elements = wwTarget.querySelectorAll('*');
1167
- for (let i = includeWW ? 0 : 1, el; (el = elements[i]); i++) {
1166
+ const elements = includeWW ? [wwTarget].concat(Array.from(wwTarget.querySelectorAll('*'))) : wwTarget.querySelectorAll('*');
1167
+ for (let i = 0, el; (el = elements[i]); i++) {
1168
1168
  const computedStyle = _w.getComputedStyle(el);
1169
- for (const props of styles || computedStyle) {
1170
- el.style[props] = computedStyle.getPropertyValue(props) || '';
1169
+ const els = el.style;
1170
+ for (const props of styles) {
1171
+ els.setProperty(props, computedStyle.getPropertyValue(props) || '');
1171
1172
  }
1172
1173
  }
1173
1174
 
package/src/langs/en.js CHANGED
@@ -69,6 +69,8 @@
69
69
  dir_rtl: 'Right to left',
70
70
  download: 'Download',
71
71
  drag: 'Drag',
72
+ drawing: 'Drawing',
73
+ drawing_modal_title: 'Drawing',
72
74
  edit: 'Edit',
73
75
  exportPdf: 'Export to PDF',
74
76
  exportWord: 'Export to Word',
@@ -137,6 +139,9 @@
137
139
  numberedList: 'Numbered list',
138
140
  outdent: 'Outdent',
139
141
  pageBreak: 'Page break',
142
+ pageDown: 'Page down',
143
+ pageNumber: 'Page number',
144
+ pageUp: 'Page up',
140
145
  paragraphStyle: 'Paragraph style',
141
146
  preview: 'Preview',
142
147
  print: 'print',
@@ -1,11 +1,13 @@
1
1
  import CoreInjector from '../editorInjector/_core';
2
2
  import { CreateTooltipInner } from '../core/section/constructor';
3
- import { env } from '../helper';
3
+ import { domUtils, env } from '../helper';
4
4
 
5
5
  const { _w } = env;
6
+ const DIRECTION_CURSOR_MAP = { w: 'ns-resize', h: 'ew-resize', c: 'nwse-resize', wRTL: 'ns-resize', hRTL: 'ew-resize', cRTL: 'nesw-resize' };
6
7
 
7
8
  const Modal = function (inst, element) {
8
9
  CoreInjector.call(this, inst.editor);
10
+ this.offset = this.editor.offset;
9
11
 
10
12
  // members
11
13
  this.inst = inst;
@@ -20,6 +22,8 @@ const Modal = function (inst, element) {
20
22
  this._bindClose = null;
21
23
  this._onClickEvent = null;
22
24
  this._closeSignal = false;
25
+ // resie
26
+ this._resizeBody = null;
23
27
 
24
28
  // add element
25
29
  this._modalInner.appendChild(element);
@@ -27,6 +31,26 @@ const Modal = function (inst, element) {
27
31
  // init
28
32
  this.eventManager.addEvent(element.querySelector('form'), 'submit', Action.bind(this));
29
33
  this._closeSignal = !this.eventManager.addEvent(element.querySelector('[data-command="close"]'), 'click', this.close.bind(this));
34
+
35
+ // resize
36
+ if (element.querySelector('.se-modal-resize-handle-w') || element.querySelector('.se-modal-resize-handle-h') || element.querySelector('.se-modal-resize-handle-c') || element.querySelector('.se-modal-resize-form')) {
37
+ if (!(this._resizeBody = element.querySelector('.se-modal-resize-form')) && (this._resizeBody = element.querySelector('.se-modal-body'))) {
38
+ this.eventManager.addEvent(element.querySelector('.se-modal-resize-handle-w'), 'mousedown', OnResizeMouseDown.bind(this, 'w'));
39
+ this.eventManager.addEvent(element.querySelector('.se-modal-resize-handle-h'), 'mousedown', OnResizeMouseDown.bind(this, 'h'));
40
+ this.eventManager.addEvent(element.querySelector('.se-modal-resize-handle-c'), 'mousedown', OnResizeMouseDown.bind(this, 'c'));
41
+
42
+ this._currentHandle = null;
43
+ this.__resizeDir = '';
44
+ this.__offetTop = 0;
45
+ this.__offetLeft = 0;
46
+ this.__globalEventHandlers = {
47
+ mousemove: OnResize.bind(this),
48
+ mouseup: OnResizeMouseUp.bind(this)
49
+ };
50
+ this._bindClose_mousemove = null;
51
+ this._bindClose_mouseup = null;
52
+ }
53
+ }
30
54
  };
31
55
 
32
56
  Modal.prototype = {
@@ -51,6 +75,16 @@ Modal.prototype = {
51
75
  this._modalInner.style.display = 'block';
52
76
  this.form.style.display = 'block';
53
77
 
78
+ if (this._resizeBody) {
79
+ const offset = this._saveOffset();
80
+ const { maxWidth, maxHeight } = _w.getComputedStyle(this.form);
81
+ const mw = `${this.form.offsetWidth - offset.width}px`;
82
+ const mh = `${this.form.offsetTop + (this.form.offsetHeight - this._resizeBody.offsetHeight)}px`;
83
+ // set max
84
+ if (maxWidth && typeof this.__resizeDir === 'string') domUtils.setStyle(this._resizeBody, 'max-width', `calc(${maxWidth} - ${mw})`);
85
+ if (maxHeight) domUtils.setStyle(this._resizeBody, 'max-height', `calc(${maxHeight} - ${mh})`);
86
+ }
87
+
54
88
  if (this.focusElement) this.focusElement.focus();
55
89
  },
56
90
 
@@ -59,6 +93,7 @@ Modal.prototype = {
59
93
  * The plugin's "init" method is called.
60
94
  */
61
95
  close() {
96
+ this.__removeGlobalEvent();
62
97
  this._fixCurrentController(false);
63
98
  _w.setTimeout(() => {
64
99
  this.editor.opendModal = null;
@@ -73,6 +108,7 @@ Modal.prototype = {
73
108
  this._modalArea.style.display = 'none';
74
109
 
75
110
  if (typeof this.inst.init === 'function') this.inst.init();
111
+ if (typeof this.inst.off === 'function') this.inst.off(this.isUpdate);
76
112
  this.editor.focus();
77
113
  },
78
114
 
@@ -84,6 +120,26 @@ Modal.prototype = {
84
120
  }
85
121
  },
86
122
 
123
+ _saveOffset() {
124
+ const offset = this.offset.getGlobal(this._resizeBody);
125
+ this.__offetTop = offset.top;
126
+ this.__offetLeft = offset.left;
127
+ return offset;
128
+ },
129
+
130
+ __addGlobalEvent(dir) {
131
+ this.__removeGlobalEvent();
132
+ this.editor.enableBackWrapper(DIRECTION_CURSOR_MAP[dir]);
133
+ this._bindClose_mousemove = this.eventManager.addGlobalEvent('mousemove', this.__globalEventHandlers.mousemove, true);
134
+ this._bindClose_mouseup = this.eventManager.addGlobalEvent('mouseup', this.__globalEventHandlers.mouseup, true);
135
+ },
136
+
137
+ __removeGlobalEvent() {
138
+ this.editor.disableBackWrapper();
139
+ if (this._bindClose_mousemove) this._bindClose_mousemove = this.eventManager.removeGlobalEvent(this._bindClose_mousemove);
140
+ if (this._bindClose_mouseup) this._bindClose_mouseup = this.eventManager.removeGlobalEvent(this._bindClose_mouseup);
141
+ },
142
+
87
143
  constructor: Modal
88
144
  };
89
145
 
@@ -130,6 +186,57 @@ function CloseListener(e) {
130
186
  this.close();
131
187
  }
132
188
 
189
+ /** Resize events */
190
+ function OnResizeMouseDown(dir, e) {
191
+ domUtils.addClass((this._currentHandle = e.target), 'active');
192
+ this.__addGlobalEvent((this.__resizeDir = dir + (this.options.get('_rtl') ? 'RTL' : '')));
193
+ }
194
+
195
+ function OnResize(e) {
196
+ switch (this.__resizeDir) {
197
+ case 'w':
198
+ case 'wRTL': {
199
+ const h = e.clientY - this.__offetTop - this._resizeBody.offsetHeight;
200
+ this._resizeBody.style.height = this._resizeBody.offsetHeight + h + 'px';
201
+ break;
202
+ }
203
+ case 'h': {
204
+ const w = e.clientX - this.__offetLeft - this._resizeBody.offsetWidth;
205
+ this._resizeBody.style.width = this._resizeBody.offsetWidth + w + 'px';
206
+ break;
207
+ }
208
+ case 'hRTL': {
209
+ const w = this.__offetLeft - e.clientX;
210
+ this._resizeBody.style.width = this._resizeBody.offsetWidth + w + 'px';
211
+ break;
212
+ }
213
+ case 'c': {
214
+ const w = e.clientX - this.__offetLeft - this._resizeBody.offsetWidth;
215
+ const h = e.clientY - this.__offetTop - this._resizeBody.offsetHeight;
216
+ this._resizeBody.style.width = this._resizeBody.offsetWidth + w + 'px';
217
+ this._resizeBody.style.height = this._resizeBody.offsetHeight + h + 'px';
218
+ break;
219
+ }
220
+ case 'cRTL': {
221
+ const w = this.__offetLeft - e.clientX;
222
+ const h = e.clientY - this.__offetTop - this._resizeBody.offsetHeight;
223
+ this._resizeBody.style.width = this._resizeBody.offsetWidth + w + 'px';
224
+ this._resizeBody.style.height = this._resizeBody.offsetHeight + h + 'px';
225
+ break;
226
+ }
227
+ }
228
+
229
+ this._saveOffset();
230
+
231
+ if (typeof this.inst.modalResize === 'function') this.inst.modalResize();
232
+ }
233
+
234
+ function OnResizeMouseUp() {
235
+ domUtils.removeClass(this._currentHandle, 'active');
236
+ this._currentHandle = null;
237
+ this.__removeGlobalEvent();
238
+ }
239
+
133
240
  // HTML Creator ======================================================================================================
134
241
 
135
242
  // Create a file input tag
@@ -45,7 +45,7 @@ ExportPdf.prototype = {
45
45
 
46
46
  try {
47
47
  const topArea = this.editor.frameContext.get('topArea');
48
- const editableDiv = domUtils.createElement('div', { class: this.editor.frameContext.get('wysiwygFrame').className }, this.html.get());
48
+ const editableDiv = domUtils.createElement('div', { class: this.editor.frameContext.get('wysiwyg').className }, this.html.get());
49
49
  ww = domUtils.createElement('div', { style: `position: absolute; left: -10000px; width: ${topArea.clientWidth}px; height: auto;` }, editableDiv);
50
50
 
51
51
  if (this.apiUrl) {
@@ -8,7 +8,7 @@ const List_bulleted = function (editor) {
8
8
  EditorInjector.call(this, editor);
9
9
  this.title = this.lang.bulletedList;
10
10
  this.icon = 'list_bulleted';
11
- this.afterButton = domUtils.createElement(
11
+ this.afterItem = domUtils.createElement(
12
12
  'button',
13
13
  { class: 'se-btn se-tooltip se-sub-arrow-btn', 'data-command': List_bulleted.key, 'data-type': 'dropdown' },
14
14
  `${this.icons.arrow_down}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.lang.bulletedList}</span></span>`
@@ -8,7 +8,7 @@ const List_numbered = function (editor) {
8
8
  EditorInjector.call(this, editor);
9
9
  this.title = this.lang.numberedList;
10
10
  this.icon = 'list_numbered';
11
- this.afterButton = domUtils.createElement(
11
+ this.afterItem = domUtils.createElement(
12
12
  'button',
13
13
  { class: 'se-btn se-tooltip se-sub-arrow-btn', 'data-command': List_numbered.key, 'data-type': 'dropdown' },
14
14
  `${this.icons.arrow_down}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.lang.numberedList}</span></span>`
@@ -29,12 +29,14 @@ import image from './modal/image';
29
29
  import video from './modal/video';
30
30
  import audio from './modal/audio';
31
31
  import math from './modal/math';
32
+ import drawing from './modal/drawing';
32
33
 
33
34
  // file browser
34
35
  import imageGallery from './fileBrowser/imageGallery';
35
36
 
36
37
  // input
37
38
  import fontSize from './input/fontSize';
39
+ import pageNavigator from './input/pageNavigator';
38
40
 
39
41
  // popup
40
42
  import anchor from './popup/anchor';
@@ -64,8 +66,10 @@ export {
64
66
  video,
65
67
  audio,
66
68
  math,
69
+ drawing,
67
70
  imageGallery,
68
71
  fontSize,
72
+ pageNavigator,
69
73
  anchor
70
74
  };
71
75
  export default {
@@ -93,7 +97,9 @@ export default {
93
97
  video,
94
98
  audio,
95
99
  math,
100
+ drawing,
96
101
  imageGallery,
97
102
  fontSize,
103
+ pageNavigator,
98
104
  anchor
99
105
  };