suneditor 3.0.0-beta.2 → 3.0.0-beta.20
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/CONTRIBUTING.md +186 -184
- package/LICENSE +21 -21
- package/README.md +157 -180
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +126 -123
- package/src/assets/design/color.css +131 -121
- package/src/assets/design/index.css +3 -3
- package/src/assets/design/size.css +37 -35
- package/src/assets/design/typography.css +37 -37
- package/src/assets/icons/defaultIcons.js +247 -232
- package/src/assets/suneditor-contents.css +779 -778
- package/src/assets/suneditor.css +43 -35
- package/src/core/base/eventHandlers/handler_toolbar.js +135 -135
- package/src/core/base/eventHandlers/handler_ww_clipboard.js +56 -56
- package/src/core/base/eventHandlers/handler_ww_dragDrop.js +115 -113
- package/src/core/base/eventHandlers/handler_ww_key_input.js +1200 -1200
- package/src/core/base/eventHandlers/handler_ww_mouse.js +194 -194
- package/src/core/base/eventManager.js +1550 -1484
- package/src/core/base/history.js +355 -355
- package/src/core/class/char.js +163 -162
- package/src/core/class/component.js +856 -842
- package/src/core/class/format.js +3433 -3422
- package/src/core/class/html.js +1927 -1890
- package/src/core/class/menu.js +357 -346
- package/src/core/class/nodeTransform.js +424 -424
- package/src/core/class/offset.js +858 -891
- package/src/core/class/selection.js +710 -620
- package/src/core/class/shortcuts.js +98 -98
- package/src/core/class/toolbar.js +438 -430
- package/src/core/class/ui.js +424 -422
- package/src/core/class/viewer.js +750 -750
- package/src/core/editor.js +1810 -1708
- package/src/core/section/actives.js +268 -241
- package/src/core/section/constructor.js +1348 -1661
- package/src/core/section/context.js +102 -102
- package/src/core/section/documentType.js +582 -561
- package/src/core/section/options.js +367 -0
- package/src/core/util/instanceCheck.js +59 -0
- package/src/editorInjector/_classes.js +36 -36
- package/src/editorInjector/_core.js +92 -92
- package/src/editorInjector/index.js +75 -75
- package/src/events.js +634 -622
- package/src/helper/clipboard.js +59 -59
- package/src/helper/converter.js +586 -564
- package/src/helper/dom/domCheck.js +304 -304
- package/src/helper/dom/domQuery.js +677 -669
- package/src/helper/dom/domUtils.js +618 -557
- package/src/helper/dom/index.js +12 -12
- package/src/helper/env.js +249 -240
- package/src/helper/index.js +25 -25
- package/src/helper/keyCodeMap.js +183 -183
- package/src/helper/numbers.js +72 -72
- package/src/helper/unicode.js +47 -47
- package/src/langs/ckb.js +231 -231
- package/src/langs/cs.js +231 -231
- package/src/langs/da.js +231 -231
- package/src/langs/de.js +231 -231
- package/src/langs/en.js +230 -230
- package/src/langs/es.js +231 -231
- package/src/langs/fa.js +231 -231
- package/src/langs/fr.js +231 -231
- package/src/langs/he.js +231 -231
- package/src/langs/hu.js +230 -230
- package/src/langs/index.js +28 -28
- package/src/langs/it.js +231 -231
- package/src/langs/ja.js +230 -230
- package/src/langs/km.js +230 -230
- package/src/langs/ko.js +230 -230
- package/src/langs/lv.js +231 -231
- package/src/langs/nl.js +231 -231
- package/src/langs/pl.js +231 -231
- package/src/langs/pt_br.js +231 -231
- package/src/langs/ro.js +231 -231
- package/src/langs/ru.js +231 -231
- package/src/langs/se.js +231 -231
- package/src/langs/tr.js +231 -231
- package/src/langs/uk.js +231 -231
- package/src/langs/ur.js +231 -231
- package/src/langs/zh_cn.js +231 -231
- package/src/modules/ApiManager.js +191 -191
- package/src/modules/Browser.js +669 -667
- package/src/modules/ColorPicker.js +364 -362
- package/src/modules/Controller.js +474 -454
- package/src/modules/Figure.js +1620 -1617
- package/src/modules/FileManager.js +359 -359
- package/src/modules/HueSlider.js +577 -565
- package/src/modules/Modal.js +346 -346
- package/src/modules/ModalAnchorEditor.js +643 -643
- package/src/modules/SelectMenu.js +549 -549
- package/src/modules/_DragHandle.js +17 -17
- package/src/modules/index.js +14 -14
- package/src/plugins/browser/audioGallery.js +83 -83
- package/src/plugins/browser/fileBrowser.js +103 -103
- package/src/plugins/browser/fileGallery.js +83 -83
- package/src/plugins/browser/imageGallery.js +81 -81
- package/src/plugins/browser/videoGallery.js +103 -103
- package/src/plugins/command/blockquote.js +61 -60
- package/src/plugins/command/exportPDF.js +134 -134
- package/src/plugins/command/fileUpload.js +456 -456
- package/src/plugins/command/list_bulleted.js +149 -148
- package/src/plugins/command/list_numbered.js +152 -151
- package/src/plugins/dropdown/align.js +157 -155
- package/src/plugins/dropdown/backgroundColor.js +108 -104
- package/src/plugins/dropdown/font.js +141 -137
- package/src/plugins/dropdown/fontColor.js +109 -105
- package/src/plugins/dropdown/formatBlock.js +170 -178
- package/src/plugins/dropdown/hr.js +152 -152
- package/src/plugins/dropdown/layout.js +83 -83
- package/src/plugins/dropdown/lineHeight.js +131 -130
- package/src/plugins/dropdown/list.js +123 -122
- package/src/plugins/dropdown/paragraphStyle.js +138 -138
- package/src/plugins/dropdown/table.js +4110 -4000
- package/src/plugins/dropdown/template.js +83 -83
- package/src/plugins/dropdown/textStyle.js +149 -149
- package/src/plugins/field/mention.js +242 -242
- package/src/plugins/index.js +120 -120
- package/src/plugins/input/fontSize.js +414 -410
- package/src/plugins/input/pageNavigator.js +71 -70
- package/src/plugins/modal/audio.js +677 -677
- package/src/plugins/modal/drawing.js +537 -531
- package/src/plugins/modal/embed.js +886 -886
- package/src/plugins/modal/image.js +1377 -1376
- package/src/plugins/modal/link.js +248 -240
- package/src/plugins/modal/math.js +563 -563
- package/src/plugins/modal/video.js +1226 -1226
- package/src/plugins/popup/anchor.js +224 -222
- package/src/suneditor.js +114 -107
- package/src/themes/dark.css +132 -122
- package/src/typedef.js +132 -130
- package/types/assets/icons/defaultIcons.d.ts +8 -0
- package/types/core/base/eventManager.d.ts +29 -4
- package/types/core/class/char.d.ts +2 -1
- package/types/core/class/component.d.ts +1 -2
- package/types/core/class/format.d.ts +8 -1
- package/types/core/class/html.d.ts +8 -0
- package/types/core/class/menu.d.ts +8 -0
- package/types/core/class/offset.d.ts +24 -26
- package/types/core/class/selection.d.ts +2 -0
- package/types/core/class/toolbar.d.ts +6 -0
- package/types/core/class/ui.d.ts +1 -1
- package/types/core/editor.d.ts +34 -12
- package/types/core/section/constructor.d.ts +5 -638
- package/types/core/section/documentType.d.ts +12 -2
- package/types/core/section/options.d.ts +740 -0
- package/types/core/util/instanceCheck.d.ts +50 -0
- package/types/editorInjector/_core.d.ts +5 -5
- package/types/editorInjector/index.d.ts +2 -2
- package/types/events.d.ts +2 -0
- package/types/helper/converter.d.ts +9 -0
- package/types/helper/dom/domQuery.d.ts +5 -5
- package/types/helper/dom/domUtils.d.ts +8 -0
- package/types/helper/env.d.ts +6 -1
- package/types/helper/index.d.ts +4 -1
- package/types/index.d.ts +122 -120
- package/types/langs/_Lang.d.ts +194 -194
- package/types/modules/ColorPicker.d.ts +5 -1
- package/types/modules/Controller.d.ts +8 -4
- package/types/modules/Figure.d.ts +2 -1
- package/types/modules/HueSlider.d.ts +4 -1
- package/types/modules/SelectMenu.d.ts +1 -1
- package/types/plugins/command/blockquote.d.ts +1 -0
- package/types/plugins/command/list_bulleted.d.ts +1 -0
- package/types/plugins/command/list_numbered.d.ts +1 -0
- package/types/plugins/dropdown/align.d.ts +1 -0
- package/types/plugins/dropdown/backgroundColor.d.ts +1 -0
- package/types/plugins/dropdown/font.d.ts +1 -0
- package/types/plugins/dropdown/fontColor.d.ts +1 -0
- package/types/plugins/dropdown/formatBlock.d.ts +3 -2
- package/types/plugins/dropdown/lineHeight.d.ts +1 -0
- package/types/plugins/dropdown/list.d.ts +1 -0
- package/types/plugins/dropdown/table.d.ts +6 -0
- package/types/plugins/input/fontSize.d.ts +1 -0
- package/types/plugins/modal/drawing.d.ts +4 -0
- package/types/plugins/modal/link.d.ts +32 -15
- package/types/suneditor.d.ts +13 -9
- package/types/typedef.d.ts +8 -0
|
@@ -1,561 +1,582 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview DocumentType class
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { dom, numbers, converter, env } from '../../helper';
|
|
6
|
-
|
|
7
|
-
const { _w } = env;
|
|
8
|
-
|
|
9
|
-
// A4 constants in points (72 dpi - PDF standard)
|
|
10
|
-
const MM_TO_POINTS = 2.83465; // 1mm = 2.83465pt
|
|
11
|
-
const POINTS_TO_PIXELS = 96 / 72; // convert PDF points to screen pixels
|
|
12
|
-
const A4_HEIGHT_MM = 297;
|
|
13
|
-
const A4_PAGE_HEIGHT = Math.floor(A4_HEIGHT_MM * MM_TO_POINTS * POINTS_TO_PIXELS);
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @constructor
|
|
17
|
-
* @description DocumentType, page, header management class
|
|
18
|
-
* @param {__se__EditorCore} editor - The root editor instance
|
|
19
|
-
* @param {__se__FrameContext} fc - frame context object
|
|
20
|
-
*/
|
|
21
|
-
function DocumentType(editor, fc) {
|
|
22
|
-
// members
|
|
23
|
-
this.editor = editor;
|
|
24
|
-
this.context = editor.context;
|
|
25
|
-
this.selection = editor.selection;
|
|
26
|
-
this.offset = editor.offset;
|
|
27
|
-
this.fc = fc;
|
|
28
|
-
this.ww = fc.get('wysiwyg');
|
|
29
|
-
this.wwFrame = fc.get('wysiwygFrame');
|
|
30
|
-
this.wwWidth = -1;
|
|
31
|
-
this.wwHeight = -1;
|
|
32
|
-
this.isAutoHeight = fc.get('options').get('height') === 'auto';
|
|
33
|
-
this.displayPage = this.isAutoHeight ? _w : fc.get('wysiwyg');
|
|
34
|
-
this.innerHeaders = [];
|
|
35
|
-
this._wwHeaders = [];
|
|
36
|
-
this.documentTypeInner = fc.get('documentTypeInner');
|
|
37
|
-
this.inner = null;
|
|
38
|
-
this.page = null;
|
|
39
|
-
this.totalPages = 0;
|
|
40
|
-
this.pageNum = 0;
|
|
41
|
-
this.pageHeight = -1;
|
|
42
|
-
this.pageBreaksCnt = 0;
|
|
43
|
-
this.pages = [];
|
|
44
|
-
this.pages_line = [];
|
|
45
|
-
this.prevScrollTop = 0;
|
|
46
|
-
this.useHeader = editor.options.get('_type_options').includes('header');
|
|
47
|
-
this.usePage = editor.options.get('_type_options').includes('page');
|
|
48
|
-
this.navigatorButtons = [];
|
|
49
|
-
this.pageNavigator = null;
|
|
50
|
-
this._mirror = fc.get('documentTypePageMirror');
|
|
51
|
-
this._mirrorCache = 0;
|
|
52
|
-
this._positionCache = new Map();
|
|
53
|
-
this._rePageTimeout = null;
|
|
54
|
-
|
|
55
|
-
const mirrorStyles = _w.getComputedStyle(this._mirror);
|
|
56
|
-
this._paddingTop = numbers.get(mirrorStyles.paddingTop);
|
|
57
|
-
this._paddingBottom = numbers.get(mirrorStyles.paddingBottom);
|
|
58
|
-
|
|
59
|
-
// init header
|
|
60
|
-
if (this.useHeader) {
|
|
61
|
-
const headers = this._getHeaders();
|
|
62
|
-
const inner = (this.inner = this.documentTypeInner.querySelector('.se-document-lines-inner'));
|
|
63
|
-
let headerHTML = '';
|
|
64
|
-
for (let i = 0, len = headers.length, h; i < len; i++) {
|
|
65
|
-
h = headers[i];
|
|
66
|
-
headerHTML += `<div class="se-doc-item se-doc-h${numbers.get(h.nodeName)}" title="${h.textContent}">${h.textContent}</div>`;
|
|
67
|
-
}
|
|
68
|
-
inner.innerHTML = headerHTML;
|
|
69
|
-
this.innerHeaders = inner.querySelectorAll('div');
|
|
70
|
-
|
|
71
|
-
this.editor.eventManager.addEvent(inner, 'click', OnClickHeader.bind(this, this.ww));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// init page
|
|
75
|
-
if (this.usePage) {
|
|
76
|
-
this.page = fc.get('documentTypePage');
|
|
77
|
-
this.pageNavigator = editor.plugins.pageNavigator;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
DocumentType.prototype = {
|
|
82
|
-
/**
|
|
83
|
-
* @description Refresh the document header area
|
|
84
|
-
*/
|
|
85
|
-
reHeader() {
|
|
86
|
-
if (!this.useHeader) return;
|
|
87
|
-
|
|
88
|
-
const headers = this._getHeaders();
|
|
89
|
-
const inner = this.inner;
|
|
90
|
-
const innerHeaders = this.innerHeaders;
|
|
91
|
-
|
|
92
|
-
// update or new headers
|
|
93
|
-
for (let i = 0, len = headers.length, h, hClass, innerH; i < len; i++) {
|
|
94
|
-
h = headers[i];
|
|
95
|
-
hClass = `se-doc-h${numbers.get(h.nodeName)}`;
|
|
96
|
-
innerH = innerHeaders[i];
|
|
97
|
-
|
|
98
|
-
if (i < innerHeaders.length) {
|
|
99
|
-
if (!innerH.classList.contains(hClass) || innerH.textContent !== h.textContent) {
|
|
100
|
-
innerH.textContent = innerH.title = h.textContent;
|
|
101
|
-
innerH.className = `se-doc-item ${hClass}`;
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
const newHeader = document.createElement('div');
|
|
105
|
-
newHeader.className = `se-doc-item ${hClass}`;
|
|
106
|
-
newHeader.textContent = newHeader.title = h.textContent;
|
|
107
|
-
inner.appendChild(newHeader);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// remove
|
|
112
|
-
if (innerHeaders.length > headers.length) {
|
|
113
|
-
for (let i = headers.length; i < innerHeaders.length; i++) {
|
|
114
|
-
inner.removeChild(innerHeaders[i]);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
this.innerHeaders = inner.querySelectorAll('div');
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* @description Refresh the document page
|
|
123
|
-
* @param {boolean} force - Whether to force the page to be re-rendered
|
|
124
|
-
* @returns {Promise<void>}
|
|
125
|
-
*/
|
|
126
|
-
async rePage(force) {
|
|
127
|
-
if (!this.page) return;
|
|
128
|
-
if (this._rePageTimeout) _w.clearTimeout(this._rePageTimeout);
|
|
129
|
-
|
|
130
|
-
this._rePageTimeout = _w.setTimeout(async () => {
|
|
131
|
-
await dom.utils.waitForMediaLoad(this._mirror, 1500);
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
this.pageHeight
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
let
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
this.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
this.
|
|
215
|
-
this.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
* @
|
|
222
|
-
*
|
|
223
|
-
* @param {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
},
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* @private
|
|
243
|
-
* @description
|
|
244
|
-
* @param {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
this.
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
},
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* @
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview DocumentType class
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { dom, numbers, converter, env } from '../../helper';
|
|
6
|
+
|
|
7
|
+
const { _w } = env;
|
|
8
|
+
|
|
9
|
+
// A4 constants in points (72 dpi - PDF standard)
|
|
10
|
+
const MM_TO_POINTS = 2.83465; // 1mm = 2.83465pt
|
|
11
|
+
const POINTS_TO_PIXELS = 96 / 72; // convert PDF points to screen pixels
|
|
12
|
+
const A4_HEIGHT_MM = 297;
|
|
13
|
+
const A4_PAGE_HEIGHT = Math.floor(A4_HEIGHT_MM * MM_TO_POINTS * POINTS_TO_PIXELS);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @constructor
|
|
17
|
+
* @description DocumentType, page, header management class
|
|
18
|
+
* @param {__se__EditorCore} editor - The root editor instance
|
|
19
|
+
* @param {__se__FrameContext} fc - frame context object
|
|
20
|
+
*/
|
|
21
|
+
function DocumentType(editor, fc) {
|
|
22
|
+
// members
|
|
23
|
+
this.editor = editor;
|
|
24
|
+
this.context = editor.context;
|
|
25
|
+
this.selection = editor.selection;
|
|
26
|
+
this.offset = editor.offset;
|
|
27
|
+
this.fc = fc;
|
|
28
|
+
this.ww = fc.get('wysiwyg');
|
|
29
|
+
this.wwFrame = fc.get('wysiwygFrame');
|
|
30
|
+
this.wwWidth = -1;
|
|
31
|
+
this.wwHeight = -1;
|
|
32
|
+
this.isAutoHeight = fc.get('options').get('height') === 'auto';
|
|
33
|
+
this.displayPage = this.isAutoHeight ? _w : fc.get('wysiwyg');
|
|
34
|
+
this.innerHeaders = [];
|
|
35
|
+
this._wwHeaders = [];
|
|
36
|
+
this.documentTypeInner = fc.get('documentTypeInner');
|
|
37
|
+
this.inner = null;
|
|
38
|
+
this.page = null;
|
|
39
|
+
this.totalPages = 0;
|
|
40
|
+
this.pageNum = 0;
|
|
41
|
+
this.pageHeight = -1;
|
|
42
|
+
this.pageBreaksCnt = 0;
|
|
43
|
+
this.pages = [];
|
|
44
|
+
this.pages_line = [];
|
|
45
|
+
this.prevScrollTop = 0;
|
|
46
|
+
this.useHeader = editor.options.get('_type_options').includes('header');
|
|
47
|
+
this.usePage = editor.options.get('_type_options').includes('page');
|
|
48
|
+
this.navigatorButtons = [];
|
|
49
|
+
this.pageNavigator = null;
|
|
50
|
+
this._mirror = fc.get('documentTypePageMirror');
|
|
51
|
+
this._mirrorCache = 0;
|
|
52
|
+
this._positionCache = new Map();
|
|
53
|
+
this._rePageTimeout = null;
|
|
54
|
+
|
|
55
|
+
const mirrorStyles = _w.getComputedStyle(this._mirror);
|
|
56
|
+
this._paddingTop = numbers.get(mirrorStyles.paddingTop);
|
|
57
|
+
this._paddingBottom = numbers.get(mirrorStyles.paddingBottom);
|
|
58
|
+
|
|
59
|
+
// init header
|
|
60
|
+
if (this.useHeader) {
|
|
61
|
+
const headers = this._getHeaders();
|
|
62
|
+
const inner = (this.inner = this.documentTypeInner.querySelector('.se-document-lines-inner'));
|
|
63
|
+
let headerHTML = '';
|
|
64
|
+
for (let i = 0, len = headers.length, h; i < len; i++) {
|
|
65
|
+
h = headers[i];
|
|
66
|
+
headerHTML += `<div class="se-doc-item se-doc-h${numbers.get(h.nodeName)}" title="${h.textContent}">${h.textContent}</div>`;
|
|
67
|
+
}
|
|
68
|
+
inner.innerHTML = headerHTML;
|
|
69
|
+
this.innerHeaders = inner.querySelectorAll('div');
|
|
70
|
+
|
|
71
|
+
this.editor.eventManager.addEvent(inner, 'click', OnClickHeader.bind(this, this.ww));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// init page
|
|
75
|
+
if (this.usePage) {
|
|
76
|
+
this.page = fc.get('documentTypePage');
|
|
77
|
+
this.pageNavigator = editor.plugins.pageNavigator;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
DocumentType.prototype = {
|
|
82
|
+
/**
|
|
83
|
+
* @description Refresh the document header area
|
|
84
|
+
*/
|
|
85
|
+
reHeader() {
|
|
86
|
+
if (!this.useHeader) return;
|
|
87
|
+
|
|
88
|
+
const headers = this._getHeaders();
|
|
89
|
+
const inner = this.inner;
|
|
90
|
+
const innerHeaders = this.innerHeaders;
|
|
91
|
+
|
|
92
|
+
// update or new headers
|
|
93
|
+
for (let i = 0, len = headers.length, h, hClass, innerH; i < len; i++) {
|
|
94
|
+
h = headers[i];
|
|
95
|
+
hClass = `se-doc-h${numbers.get(h.nodeName)}`;
|
|
96
|
+
innerH = innerHeaders[i];
|
|
97
|
+
|
|
98
|
+
if (i < innerHeaders.length) {
|
|
99
|
+
if (!innerH.classList.contains(hClass) || innerH.textContent !== h.textContent) {
|
|
100
|
+
innerH.textContent = innerH.title = h.textContent;
|
|
101
|
+
innerH.className = `se-doc-item ${hClass}`;
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
const newHeader = document.createElement('div');
|
|
105
|
+
newHeader.className = `se-doc-item ${hClass}`;
|
|
106
|
+
newHeader.textContent = newHeader.title = h.textContent;
|
|
107
|
+
inner.appendChild(newHeader);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// remove
|
|
112
|
+
if (innerHeaders.length > headers.length) {
|
|
113
|
+
for (let i = headers.length; i < innerHeaders.length; i++) {
|
|
114
|
+
inner.removeChild(innerHeaders[i]);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this.innerHeaders = inner.querySelectorAll('div');
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @description Refresh the document page
|
|
123
|
+
* @param {boolean} force - Whether to force the page to be re-rendered
|
|
124
|
+
* @returns {Promise<void>}
|
|
125
|
+
*/
|
|
126
|
+
async rePage(force) {
|
|
127
|
+
if (!this.page) return;
|
|
128
|
+
if (this._rePageTimeout) _w.clearTimeout(this._rePageTimeout);
|
|
129
|
+
|
|
130
|
+
this._rePageTimeout = _w.setTimeout(async () => {
|
|
131
|
+
await dom.utils.waitForMediaLoad(this._mirror, 1500);
|
|
132
|
+
|
|
133
|
+
const heightGap = this.ww.scrollHeight > this._mirror.scrollHeight ? this.ww.scrollHeight - this._mirror.scrollHeight : 0;
|
|
134
|
+
const mirrorHeight = this._mirror.scrollHeight + heightGap;
|
|
135
|
+
const pageBreaks = this.ww.querySelectorAll('.se-page-break');
|
|
136
|
+
if (!force && this.pageHeight === mirrorHeight && this.pageBreaksCnt === pageBreaks.length) return;
|
|
137
|
+
|
|
138
|
+
this.pageHeight = mirrorHeight;
|
|
139
|
+
this.pageBreaksCnt = pageBreaks.length;
|
|
140
|
+
|
|
141
|
+
// page break
|
|
142
|
+
let pageBreakHeight = 0;
|
|
143
|
+
let lastBreakPosition = 0;
|
|
144
|
+
let additionalPages = 0;
|
|
145
|
+
if (pageBreaks.length > 0) {
|
|
146
|
+
pageBreakHeight = pageBreaks[0].offsetHeight;
|
|
147
|
+
for (let i = 0; i < pageBreaks.length; i++) {
|
|
148
|
+
const breakPosition = pageBreaks[i].offsetTop;
|
|
149
|
+
const sectionHeight = breakPosition - lastBreakPosition;
|
|
150
|
+
if (sectionHeight % A4_PAGE_HEIGHT !== 0) additionalPages++;
|
|
151
|
+
lastBreakPosition = breakPosition;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const lastSectionHeight = mirrorHeight - lastBreakPosition;
|
|
155
|
+
if (lastSectionHeight > 0 && lastSectionHeight % A4_PAGE_HEIGHT !== 0) additionalPages++;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const scrollTop = this.isAutoHeight ? 0 : this._getWWScrollTop();
|
|
159
|
+
const totalPages = Math.ceil(mirrorHeight / A4_PAGE_HEIGHT) + additionalPages;
|
|
160
|
+
const wwWidth = this.wwFrame.offsetWidth + 1;
|
|
161
|
+
const pages = [];
|
|
162
|
+
|
|
163
|
+
for (let i = 0; i < pageBreaks.length; i++) {
|
|
164
|
+
pages.push({ number: i, top: pageBreaks[i].offsetTop + pageBreakHeight / 2 - scrollTop });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
this._mirrorCache = 0;
|
|
168
|
+
const chr = this.ww.children;
|
|
169
|
+
const mChr = this._mirror.children;
|
|
170
|
+
this._initializeCache(mChr);
|
|
171
|
+
|
|
172
|
+
pages.push({ number: 0, top: 0 });
|
|
173
|
+
|
|
174
|
+
for (let i = 1, t = 0; i < totalPages; i++) {
|
|
175
|
+
t += A4_PAGE_HEIGHT + (i === 1 ? this._paddingTop + this._paddingBottom : this._paddingTop);
|
|
176
|
+
if (!pages.some((p) => Math.abs(p.top - t) < 3)) {
|
|
177
|
+
const top = this._calcPageBreakTop(t, chr, mChr);
|
|
178
|
+
if (top === null) break;
|
|
179
|
+
pages.push({ number: i, top });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (pages.length === 0) {
|
|
184
|
+
this.pages_line = [];
|
|
185
|
+
this.totalPages = 1;
|
|
186
|
+
this._displayCurrentPage();
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// numbering
|
|
191
|
+
pages.sort((a, b) => a.top - b.top);
|
|
192
|
+
this.page.innerHTML = '';
|
|
193
|
+
this.pages = [];
|
|
194
|
+
|
|
195
|
+
for (let i = 0, t; i < totalPages; i++) {
|
|
196
|
+
if (!pages[i]) continue;
|
|
197
|
+
t = pages[i].top;
|
|
198
|
+
if (mirrorHeight < t) break;
|
|
199
|
+
|
|
200
|
+
const pageNumber = dom.utils.createElement(
|
|
201
|
+
'DIV',
|
|
202
|
+
{
|
|
203
|
+
style: `top:${t - scrollTop}px`,
|
|
204
|
+
innerHTML: String(i + 1)
|
|
205
|
+
},
|
|
206
|
+
`<div class="se-document-page-line" style="width: ${wwWidth}px;"></div>${i + 1}`
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
this.page.appendChild(pageNumber);
|
|
210
|
+
this.pages.push(pageNumber);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
this.pages_line = this.page.querySelectorAll('.se-document-page-line');
|
|
214
|
+
this.totalPages = this.pages.length;
|
|
215
|
+
this._displayCurrentPage();
|
|
216
|
+
}, 400);
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* @private
|
|
221
|
+
* @description Calculates and compensates for the vertical gap between the rendered content (current page)
|
|
222
|
+
* - and the mirrored preview page due to differences in width and layout.
|
|
223
|
+
* @param {number} t - The initial top position value to be adjusted.
|
|
224
|
+
* @param {HTMLElement[]} chr - The elements array in the current (main) page.
|
|
225
|
+
* @param {HTMLElement[]} mChr - The elements array in the mirrored page.
|
|
226
|
+
* @returns {number|null} - The adjusted top value.
|
|
227
|
+
*/
|
|
228
|
+
_calcPageBreakTop(t, chr, mChr) {
|
|
229
|
+
const { ci } = this._getElementAtPosition(t, mChr);
|
|
230
|
+
const mel = mChr[ci];
|
|
231
|
+
const el = chr[ci];
|
|
232
|
+
if (!mel || !el) return null;
|
|
233
|
+
|
|
234
|
+
const offsetDiff = el.offsetTop - mel.offsetTop;
|
|
235
|
+
const heightDiff = el.offsetHeight - mel.offsetHeight;
|
|
236
|
+
|
|
237
|
+
const top = t + offsetDiff + heightDiff / 2;
|
|
238
|
+
return Math.round(top);
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* @private
|
|
243
|
+
* @description Initializes the cache for document elements.
|
|
244
|
+
* @param {Array<HTMLElement>} mChr - List of mirrored elements.
|
|
245
|
+
*/
|
|
246
|
+
_initializeCache(mChr) {
|
|
247
|
+
this._positionCache.clear();
|
|
248
|
+
for (let i = 0, len = mChr.length; i < len; i++) {
|
|
249
|
+
const element = mChr[i];
|
|
250
|
+
const top = element.offsetTop;
|
|
251
|
+
const height = element.offsetHeight;
|
|
252
|
+
const bottom = top + height;
|
|
253
|
+
|
|
254
|
+
this._positionCache.set(i, {
|
|
255
|
+
top,
|
|
256
|
+
height,
|
|
257
|
+
bottom: bottom
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* @private
|
|
264
|
+
* @description Retrieves the element at a given position.
|
|
265
|
+
* @param {number} pageTop - The vertical position to check.
|
|
266
|
+
* @param {HTMLElement[]} mChr - List of mirrored elements.
|
|
267
|
+
* @returns {{ci: number, cm: number, ch: number}} The closest element and its related data.
|
|
268
|
+
* - ci: The index of the closest element.
|
|
269
|
+
* - cm: The distance between the top of the closest element and the given position.
|
|
270
|
+
* - ch: The height of the closest element.
|
|
271
|
+
*/
|
|
272
|
+
_getElementAtPosition(pageTop, mChr) {
|
|
273
|
+
let start = this._mirrorCache;
|
|
274
|
+
let end = mChr.length - 1;
|
|
275
|
+
|
|
276
|
+
while (start <= end) {
|
|
277
|
+
const mid = Math.floor((start + end) / 2);
|
|
278
|
+
const { top, height, bottom } = this._positionCache.get(mid);
|
|
279
|
+
|
|
280
|
+
if (pageTop >= top && pageTop <= bottom) {
|
|
281
|
+
this._mirrorCache = mid;
|
|
282
|
+
return { ci: mid, cm: pageTop - bottom, ch: height };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (pageTop < top) {
|
|
286
|
+
end = mid - 1;
|
|
287
|
+
} else {
|
|
288
|
+
start = mid + 1;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const closestIndex = mChr[start] ? start : end;
|
|
293
|
+
this._mirrorCache = closestIndex;
|
|
294
|
+
const iElement = this._positionCache.get(closestIndex);
|
|
295
|
+
return { ci: closestIndex, cm: pageTop - iElement.bottom, ch: iElement.height };
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* @description Resizes the document page dynamically.
|
|
300
|
+
*/
|
|
301
|
+
resizePage() {
|
|
302
|
+
const wwWidth = this.wwFrame.offsetWidth + 1;
|
|
303
|
+
const wwHeight = this.wwFrame.offsetHeight + 1;
|
|
304
|
+
let rh = false;
|
|
305
|
+
if (wwWidth === this.wwWidth && (rh = wwHeight === this.wwHeight)) return;
|
|
306
|
+
|
|
307
|
+
if (wwWidth > 800) {
|
|
308
|
+
dom.utils.removeClass(this.documentTypeInner, 'se-document-responsible');
|
|
309
|
+
} else {
|
|
310
|
+
dom.utils.addClass(this.documentTypeInner, 'se-document-responsible');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
this.wwWidth = wwWidth;
|
|
314
|
+
this.wwHeight = wwHeight;
|
|
315
|
+
const pages_line = this.pages_line;
|
|
316
|
+
for (let i = 0, len = pages_line.length; i < len; i++) {
|
|
317
|
+
pages_line[i].style.width = `${wwWidth}px`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (!rh) this.rePage(true);
|
|
321
|
+
this._displayCurrentPage();
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* @description Scrolls the document page.
|
|
326
|
+
*/
|
|
327
|
+
scrollPage() {
|
|
328
|
+
const prevScrollTop = this.prevScrollTop;
|
|
329
|
+
const scrollTop = this._getWWScrollTop();
|
|
330
|
+
if (prevScrollTop === scrollTop) return;
|
|
331
|
+
|
|
332
|
+
const pages = this.pages;
|
|
333
|
+
for (let i = 0, len = pages.length; i < len; i++) {
|
|
334
|
+
pages[i].style.top = `${numbers.get(pages[i].style.top) - (scrollTop - prevScrollTop)}px`;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
this.prevScrollTop = scrollTop;
|
|
338
|
+
this._displayCurrentPage();
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* @description Scrolls the window to a specific position.
|
|
343
|
+
*/
|
|
344
|
+
scrollWindow() {
|
|
345
|
+
if (!this.isAutoHeight) return;
|
|
346
|
+
this._displayCurrentPage();
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* @description Retrieves the current page number.
|
|
351
|
+
* @returns {number} The current page number.
|
|
352
|
+
*/
|
|
353
|
+
getCurrentPageNumber() {
|
|
354
|
+
if (this.totalPages <= 1) return 1;
|
|
355
|
+
|
|
356
|
+
let targetPosition = 0;
|
|
357
|
+
if (this.isAutoHeight) {
|
|
358
|
+
const globalTop = this._getGlobalTop();
|
|
359
|
+
targetPosition = _w.scrollY - globalTop + A4_PAGE_HEIGHT / 2;
|
|
360
|
+
if (targetPosition <= 0) return 1;
|
|
361
|
+
} else {
|
|
362
|
+
targetPosition = this.wwHeight / 2;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const pages = this.pages;
|
|
366
|
+
for (let i = 0, len = pages.length; i < len; i++) {
|
|
367
|
+
if (pages[i].offsetTop >= targetPosition) {
|
|
368
|
+
return (this.pageNum = i);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return (this.pageNum = this.totalPages);
|
|
373
|
+
},
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* @description Moves to the previous page.
|
|
377
|
+
*/
|
|
378
|
+
pageUp() {
|
|
379
|
+
const pageNum = this.pageNum - 1 <= 1 ? 1 : this.pageNum - 1;
|
|
380
|
+
this._movePage(pageNum, false);
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* @description Moves to the next page.
|
|
385
|
+
*/
|
|
386
|
+
pageDown() {
|
|
387
|
+
const pageNum = this.pageNum + 1 > this.pages.length ? this.pages.length : this.pageNum + 1;
|
|
388
|
+
this._movePage(pageNum, false);
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* @description Moves to a specific page.
|
|
393
|
+
* @param {number} pageNum - The target page number.
|
|
394
|
+
*/
|
|
395
|
+
pageGo(pageNum) {
|
|
396
|
+
if (pageNum < 1) pageNum = 1;
|
|
397
|
+
else if (pageNum > this.pages.length) pageNum = this.pages.length;
|
|
398
|
+
|
|
399
|
+
this._movePage(pageNum, true);
|
|
400
|
+
},
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* @description Highlights the header of the current line.
|
|
404
|
+
* @param {Node} line - The "line" element to be highlighted.
|
|
405
|
+
*/
|
|
406
|
+
on(line) {
|
|
407
|
+
if (!this.useHeader) return;
|
|
408
|
+
|
|
409
|
+
if (!this._is(line)) line = this._findLinesHeader(line);
|
|
410
|
+
if (!line) return;
|
|
411
|
+
|
|
412
|
+
const item = this._findItem(line);
|
|
413
|
+
if (!item) return;
|
|
414
|
+
|
|
415
|
+
dom.utils.removeClass(this.innerHeaders, 'active');
|
|
416
|
+
dom.utils.addClass(item, 'active');
|
|
417
|
+
},
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* @description Handles text changes in the document.
|
|
421
|
+
*/
|
|
422
|
+
onChangeText(header) {
|
|
423
|
+
if (!this.useHeader) return;
|
|
424
|
+
|
|
425
|
+
if (!this._is(header)) return;
|
|
426
|
+
const item = this._findItem(header);
|
|
427
|
+
if (!item) return;
|
|
428
|
+
item.textContent = header.textContent;
|
|
429
|
+
},
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* @private
|
|
433
|
+
* @description Displays the current page number.
|
|
434
|
+
*/
|
|
435
|
+
_displayCurrentPage() {
|
|
436
|
+
const pageNum = this.getCurrentPageNumber();
|
|
437
|
+
this.pageNavigator?.display(pageNum, this.totalPages);
|
|
438
|
+
},
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* @private
|
|
442
|
+
* @description Retrieves the scroll position in WYSIWYG mode.
|
|
443
|
+
* @returns {number} The current scroll position.
|
|
444
|
+
*/
|
|
445
|
+
_getWWScrollTop() {
|
|
446
|
+
return this.displayPage.scrollTop || this.displayPage.scrollY || 0;
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* @private
|
|
451
|
+
* @description Moves to a specific page and updates the view.
|
|
452
|
+
* @param {number} pageNum - The target page number.
|
|
453
|
+
*/
|
|
454
|
+
_movePage(pageNum, force) {
|
|
455
|
+
const globalTop = this._getGlobalTop();
|
|
456
|
+
const children = converter.nodeListToArray(this.ww.children);
|
|
457
|
+
const pageTop = this.page.offsetTop + numbers.get(this.pages[pageNum - 1].style.top) + (this.isAutoHeight ? 0 : this._getWWScrollTop());
|
|
458
|
+
for (let i = 0, len = children.length, c; i < len; i++) {
|
|
459
|
+
c = children[i];
|
|
460
|
+
if (c.offsetTop >= pageTop) {
|
|
461
|
+
if (!force) this.selection.setRange(c, 0, c, 0);
|
|
462
|
+
const scrollTop = i === 0 && !this.isAutoHeight ? 0 : c.offsetTop - this.page.offsetTop - c.offsetHeight + globalTop;
|
|
463
|
+
this._applyPageScroll(scrollTop, () => {
|
|
464
|
+
if (this.editor.toolbar._sticky) {
|
|
465
|
+
this.displayPage.scrollTo({ top: scrollTop - this.context.get('toolbar.main').offsetHeight, behavior: 'smooth' });
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
this.pageNum = pageNum;
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* @private
|
|
477
|
+
* @description Applies smooth scrolling for page navigation.
|
|
478
|
+
*/
|
|
479
|
+
_applyPageScroll(top, callback) {
|
|
480
|
+
this.displayPage.scrollTo({ top, behavior: 'smooth' });
|
|
481
|
+
const checkScrollEnd = () => {
|
|
482
|
+
if (Math.abs((this.displayPage.scrollY ?? this.displayPage.scrollTop) - top) < 1) {
|
|
483
|
+
callback();
|
|
484
|
+
} else {
|
|
485
|
+
_w.requestAnimationFrame(checkScrollEnd);
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
_w.requestAnimationFrame(checkScrollEnd);
|
|
490
|
+
},
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* @private
|
|
494
|
+
* @description Retrieves the global top offset of an element.
|
|
495
|
+
* @returns {number} The top offset of the element.
|
|
496
|
+
*/
|
|
497
|
+
_getGlobalTop() {
|
|
498
|
+
return this.isAutoHeight ? this.offset.getGlobal(this.wwFrame).top : 0;
|
|
499
|
+
},
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* @private
|
|
503
|
+
* @description Finds an header element of innerHeaders element.
|
|
504
|
+
* @param {Node} header - H tag element to find.
|
|
505
|
+
* @returns {HTMLElement|null} The found element, or null if not found.
|
|
506
|
+
*/
|
|
507
|
+
_findItem(header) {
|
|
508
|
+
const headers = this._wwHeaders;
|
|
509
|
+
const index = Array.prototype.indexOf.call(headers, header);
|
|
510
|
+
|
|
511
|
+
if (index !== -1 && this.innerHeaders[index]) {
|
|
512
|
+
return this.innerHeaders[index];
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return null;
|
|
516
|
+
},
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* @private
|
|
520
|
+
* @description Finds the closest header element from a given line.
|
|
521
|
+
* @param {Node} line - The "line" to check.
|
|
522
|
+
* @returns {Node|null} The closest header element, or null if not found.
|
|
523
|
+
*/
|
|
524
|
+
_findLinesHeader(line) {
|
|
525
|
+
while (line && line !== this.ww) {
|
|
526
|
+
if (this._is(line)) {
|
|
527
|
+
return line;
|
|
528
|
+
}
|
|
529
|
+
line = /** @type {HTMLElement} */ (line).previousElementSibling || line.parentElement;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return null;
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* @private
|
|
537
|
+
* @description Checks if an element is a header.
|
|
538
|
+
* @param {Node} element - The element to check.
|
|
539
|
+
* @returns {boolean} True if the element is a header, otherwise false.
|
|
540
|
+
*/
|
|
541
|
+
_is(element) {
|
|
542
|
+
return /^h[1-6]$/i.test(element?.nodeName);
|
|
543
|
+
},
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* @private
|
|
547
|
+
* @description Retrieves all headers in the document.
|
|
548
|
+
* @returns {Array<HTMLElement>} An array of header elements.
|
|
549
|
+
*/
|
|
550
|
+
_getHeaders() {
|
|
551
|
+
return (this._wwHeaders = this.ww.querySelectorAll('h1, h2, h3, h4, h5, h6'));
|
|
552
|
+
},
|
|
553
|
+
|
|
554
|
+
constructor: DocumentType
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* @private
|
|
559
|
+
* @param {HTMLElement} ww WYSIWYG element
|
|
560
|
+
* @param {Event} e Event object
|
|
561
|
+
*/
|
|
562
|
+
function OnClickHeader(ww, e) {
|
|
563
|
+
e.preventDefault();
|
|
564
|
+
|
|
565
|
+
try {
|
|
566
|
+
this.editor._preventBlur = true;
|
|
567
|
+
const clickedHeader = dom.query.getEventTarget(e);
|
|
568
|
+
if (dom.utils.hasClass(clickedHeader, 'se-doc-item')) {
|
|
569
|
+
const innerIndex = Array.prototype.indexOf.call(this.innerHeaders, clickedHeader);
|
|
570
|
+
if (innerIndex === -1) return;
|
|
571
|
+
|
|
572
|
+
const header = this._wwHeaders[innerIndex];
|
|
573
|
+
if (header) {
|
|
574
|
+
this.selection.scrollTo(header);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
} finally {
|
|
578
|
+
this.editor._preventBlur = false;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
export default DocumentType;
|