@textbus/platform-browser 3.0.0-alpha.51 → 3.0.0-alpha.53

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.
@@ -1,105 +1,105 @@
1
1
  import 'reflect-metadata';
2
2
  import { InjectionToken, Injectable, Inject, Injector, Optional } from '@tanbo/di';
3
- import { VTextNode, VElement, Controller, Selection, RootComponentRef, Renderer, Slot, ContentType, Keyboard, Commander, Scheduler, makeError, Starter, NativeRenderer, NativeSelectionBridge, OutputRenderer, Registry, invokeListener, History } from '@textbus/core';
3
+ import { VTextNode, VElement, Controller, Selection, RootComponentRef, Renderer, Scheduler, Slot, ContentType, Keyboard, Commander, makeError, Starter, NativeRenderer, NativeSelectionBridge, OutputRenderer, Registry, invokeListener, History } from '@textbus/core';
4
4
  import { Subject, filter, fromEvent, Subscription, merge, map, Observable, distinctUntilChanged } from '@tanbo/stream';
5
5
 
6
- function createElement(tagName, options = {}) {
7
- const el = document.createElement(tagName);
8
- if (options.classes) {
9
- el.classList.add(...options.classes);
10
- }
11
- if (options.attrs) {
12
- Object.keys(options.attrs).forEach(key => {
13
- el.setAttribute(key, options.attrs[key]);
14
- });
15
- }
16
- if (options.props) {
17
- Object.keys(options.props).forEach(key => {
18
- el[key] = options.props[key];
19
- });
20
- }
21
- if (options.styles) {
22
- Object.assign(el.style, options.styles);
23
- }
24
- if (options.children) {
25
- options.children.filter(i => i).forEach(item => {
26
- el.appendChild(item);
27
- });
28
- }
29
- if (options.on) {
30
- Object.keys(options.on).forEach(key => {
31
- el.addEventListener(key, options.on[key]);
32
- });
33
- }
34
- return el;
35
- }
36
- function createTextNode(content) {
37
- return document.createTextNode(content);
38
- }
39
- function getLayoutRectByRange(range) {
40
- let { startContainer, startOffset } = range;
41
- if (startContainer.nodeType === Node.TEXT_NODE) {
42
- if (startOffset > 0) {
43
- return range.getBoundingClientRect();
44
- }
45
- const parentNode = startContainer.parentNode;
46
- startOffset = Array.from(parentNode.childNodes).indexOf(startContainer);
47
- startContainer = parentNode;
48
- }
49
- const beforeNode = startContainer.childNodes[startOffset - 1];
50
- if (beforeNode) {
51
- if (beforeNode.nodeType === Node.ELEMENT_NODE && beforeNode.nodeName.toLowerCase() !== 'br') {
52
- const rect = beforeNode.getBoundingClientRect();
53
- return {
54
- left: rect.right,
55
- top: rect.top,
56
- width: rect.width,
57
- height: rect.height
58
- };
59
- }
60
- else if (beforeNode.nodeType === Node.TEXT_NODE) {
61
- const range2 = document.createRange();
62
- range2.selectNodeContents(beforeNode);
63
- range2.collapse();
64
- return range2.getBoundingClientRect();
65
- }
66
- }
67
- const offsetNode = startContainer.childNodes[startOffset];
68
- let isInsertBefore = false;
69
- if (!offsetNode) {
70
- const lastChild = startContainer.lastChild;
71
- if (lastChild && lastChild.nodeType === Node.ELEMENT_NODE) {
72
- const rect = lastChild.getBoundingClientRect();
73
- return {
74
- left: rect.right,
75
- top: rect.top,
76
- width: rect.width,
77
- height: rect.height
78
- };
79
- }
80
- }
81
- if (offsetNode) {
82
- if (offsetNode.nodeType === Node.ELEMENT_NODE && offsetNode.nodeName.toLowerCase() !== 'br') {
83
- return offsetNode.getBoundingClientRect();
84
- }
85
- isInsertBefore = true;
86
- }
87
- const span = startContainer.ownerDocument.createElement('span');
88
- span.innerText = '\u200b';
89
- span.style.display = 'inline-block';
90
- if (isInsertBefore) {
91
- startContainer.insertBefore(span, offsetNode);
92
- }
93
- else {
94
- startContainer.appendChild(span);
95
- }
96
- const rect = span.getBoundingClientRect();
97
- startContainer.removeChild(span);
98
- return rect;
6
+ function createElement(tagName, options = {}) {
7
+ const el = document.createElement(tagName);
8
+ if (options.classes) {
9
+ el.classList.add(...options.classes);
10
+ }
11
+ if (options.attrs) {
12
+ Object.keys(options.attrs).forEach(key => {
13
+ el.setAttribute(key, options.attrs[key]);
14
+ });
15
+ }
16
+ if (options.props) {
17
+ Object.keys(options.props).forEach(key => {
18
+ el[key] = options.props[key];
19
+ });
20
+ }
21
+ if (options.styles) {
22
+ Object.assign(el.style, options.styles);
23
+ }
24
+ if (options.children) {
25
+ options.children.filter(i => i).forEach(item => {
26
+ el.appendChild(item);
27
+ });
28
+ }
29
+ if (options.on) {
30
+ Object.keys(options.on).forEach(key => {
31
+ el.addEventListener(key, options.on[key]);
32
+ });
33
+ }
34
+ return el;
35
+ }
36
+ function createTextNode(content) {
37
+ return document.createTextNode(content);
38
+ }
39
+ function getLayoutRectByRange(range) {
40
+ let { startContainer, startOffset } = range;
41
+ if (startContainer.nodeType === Node.TEXT_NODE) {
42
+ if (startOffset > 0) {
43
+ return range.getBoundingClientRect();
44
+ }
45
+ const parentNode = startContainer.parentNode;
46
+ startOffset = Array.from(parentNode.childNodes).indexOf(startContainer);
47
+ startContainer = parentNode;
48
+ }
49
+ const beforeNode = startContainer.childNodes[startOffset - 1];
50
+ if (beforeNode) {
51
+ if (beforeNode.nodeType === Node.ELEMENT_NODE && beforeNode.nodeName.toLowerCase() !== 'br') {
52
+ const rect = beforeNode.getBoundingClientRect();
53
+ return {
54
+ left: rect.right,
55
+ top: rect.top,
56
+ width: rect.width,
57
+ height: rect.height
58
+ };
59
+ }
60
+ else if (beforeNode.nodeType === Node.TEXT_NODE) {
61
+ const range2 = document.createRange();
62
+ range2.setStart(beforeNode, beforeNode.textContent.length);
63
+ range2.setEnd(beforeNode, beforeNode.textContent.length);
64
+ return range2.getBoundingClientRect();
65
+ }
66
+ }
67
+ const offsetNode = startContainer.childNodes[startOffset];
68
+ let isInsertBefore = false;
69
+ if (!offsetNode) {
70
+ const lastChild = startContainer.lastChild;
71
+ if (lastChild && lastChild.nodeType === Node.ELEMENT_NODE) {
72
+ const rect = lastChild.getBoundingClientRect();
73
+ return {
74
+ left: rect.right,
75
+ top: rect.top,
76
+ width: rect.width,
77
+ height: rect.height
78
+ };
79
+ }
80
+ }
81
+ if (offsetNode) {
82
+ if (offsetNode.nodeType === Node.ELEMENT_NODE && offsetNode.nodeName.toLowerCase() !== 'br') {
83
+ return offsetNode.getBoundingClientRect();
84
+ }
85
+ isInsertBefore = true;
86
+ }
87
+ const span = startContainer.ownerDocument.createElement('span');
88
+ span.innerText = '\u200b';
89
+ span.style.display = 'inline-block';
90
+ if (isInsertBefore) {
91
+ startContainer.insertBefore(span, offsetNode);
92
+ }
93
+ else {
94
+ startContainer.appendChild(span);
95
+ }
96
+ const rect = span.getBoundingClientRect();
97
+ startContainer.removeChild(span);
98
+ return rect;
99
99
  }
100
100
 
101
- const isWindows = () => /win(dows|32|64)/i.test(navigator.userAgent);
102
- const isMac = () => /mac os/i.test(navigator.userAgent);
101
+ const isWindows = () => /win(dows|32|64)/i.test(navigator.userAgent);
102
+ const isMac = () => /mac os/i.test(navigator.userAgent);
103
103
  const isSafari = () => /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
104
104
 
105
105
  /******************************************************************************
@@ -142,2572 +142,2577 @@ function __awaiter(thisArg, _arguments, P, generator) {
142
142
  });
143
143
  }
144
144
 
145
- /**
146
- * 编辑器可选项依赖注入 token
147
- */
148
- const EDITOR_OPTIONS = new InjectionToken('EDITOR_OPTIONS');
149
- /**
150
- * 编辑器容器依赖注入 token
151
- */
152
- const VIEW_CONTAINER = new InjectionToken('VIEW_CONTAINER');
153
- /**
154
- * 编辑器容器依赖注入 token
155
- */
156
- const VIEW_DOCUMENT = new InjectionToken('VIEW_DOCUMENT');
157
- /**
158
- * 编辑器容器遮罩层 token
159
- */
145
+ /**
146
+ * 编辑器可选项依赖注入 token
147
+ */
148
+ const EDITOR_OPTIONS = new InjectionToken('EDITOR_OPTIONS');
149
+ /**
150
+ * 编辑器容器依赖注入 token
151
+ */
152
+ const VIEW_CONTAINER = new InjectionToken('VIEW_CONTAINER');
153
+ /**
154
+ * 编辑器容器依赖注入 token
155
+ */
156
+ const VIEW_DOCUMENT = new InjectionToken('VIEW_DOCUMENT');
157
+ /**
158
+ * 编辑器容器遮罩层 token
159
+ */
160
160
  const VIEW_MASK = new InjectionToken('VIEW_MASK');
161
161
 
162
- class Input {
162
+ class Input {
163
163
  }
164
164
 
165
- /**
166
- * Textbus PC 端选区桥接实现
167
- */
168
- let SelectionBridge = class SelectionBridge {
169
- constructor(config, injector, controller, selection, rootComponentRef, input, renderer) {
170
- this.config = config;
171
- this.injector = injector;
172
- this.controller = controller;
173
- this.selection = selection;
174
- this.rootComponentRef = rootComponentRef;
175
- this.input = input;
176
- this.renderer = renderer;
177
- this.nativeSelection = document.getSelection();
178
- this.selectionMaskElement = createElement('style');
179
- this.selectionChangeEvent = new Subject();
180
- this.subs = [];
181
- this.connector = null;
182
- this.ignoreSelectionChange = false;
183
- this.changeFromUser = false;
184
- this.docContainer = injector.get(VIEW_DOCUMENT);
185
- this.maskContainer = injector.get(VIEW_MASK);
186
- this.onSelectionChange = this.selectionChangeEvent.asObservable().pipe(filter(() => {
187
- return !controller.readonly;
188
- }));
189
- document.head.appendChild(this.selectionMaskElement);
190
- this.sub = this.onSelectionChange.subscribe((r) => {
191
- if (r) {
192
- input.focus(r, this.changeFromUser);
193
- }
194
- else {
195
- input.blur();
196
- }
197
- });
198
- this.sub.add(fromEvent(document, 'focusin').subscribe(ev => {
199
- let target = ev.target;
200
- if (/^(input|textarea|select)$/i.test(target.nodeName)) {
201
- if (target.tagName.toLowerCase() === 'input' && /^(range|date)$/.test(target.type)) {
202
- return;
203
- }
204
- this.ignoreSelectionChange = true;
205
- return;
206
- }
207
- if (!config.useContentEditable) {
208
- while (target) {
209
- if (target.contentEditable === 'true') {
210
- this.ignoreSelectionChange = true;
211
- return;
212
- }
213
- target = target.parentNode;
214
- }
215
- }
216
- }));
217
- this.sub.add(fromEvent(document, 'focusout').subscribe(() => {
218
- this.ignoreSelectionChange = false;
219
- }));
220
- }
221
- connect(connector) {
222
- this.disConnect();
223
- this.connector = connector;
224
- this.syncSelection(connector);
225
- this.listen(connector);
226
- }
227
- disConnect() {
228
- this.connector = null;
229
- this.unListen();
230
- }
231
- getRect(location) {
232
- const { focus, anchor } = this.getPositionByRange({
233
- focusOffset: location.offset,
234
- anchorOffset: location.offset,
235
- focusSlot: location.slot,
236
- anchorSlot: location.slot
237
- });
238
- if (!focus || !anchor) {
239
- return null;
240
- }
241
- const nativeRange = document.createRange();
242
- nativeRange.setStart(focus.node, focus.offset);
243
- nativeRange.collapse();
244
- return getLayoutRectByRange(nativeRange);
245
- }
246
- restore(abstractSelection, formLocal) {
247
- this.changeFromUser = formLocal;
248
- if (this.ignoreSelectionChange || !this.connector) {
249
- return;
250
- }
251
- this.unListen();
252
- if (!abstractSelection) {
253
- this.nativeSelection.removeAllRanges();
254
- this.selectionChangeEvent.next(null);
255
- this.listen(this.connector);
256
- return;
257
- }
258
- const { focus, anchor } = this.getPositionByRange(abstractSelection);
259
- if (!focus || !anchor) {
260
- this.nativeSelection.removeAllRanges();
261
- this.selectionChangeEvent.next(null);
262
- this.listen(this.connector);
263
- return;
264
- }
265
- this.nativeSelection.setBaseAndExtent(anchor.node, anchor.offset, focus.node, focus.offset);
266
- if (this.nativeSelection.rangeCount) {
267
- const nativeRange = this.nativeSelection.getRangeAt(0);
268
- this.selectionChangeEvent.next(nativeRange);
269
- }
270
- else {
271
- this.selectionChangeEvent.next(null);
272
- }
273
- // hack start 浏览器会触发上面选区更改事件
274
- const bind = () => {
275
- if (this.connector) {
276
- this.listen(this.connector);
277
- }
278
- };
279
- if (typeof requestIdleCallback === 'function') {
280
- requestIdleCallback(bind);
281
- }
282
- else {
283
- setTimeout(bind, 30);
284
- }
285
- // hack end
286
- }
287
- destroy() {
288
- this.sub.unsubscribe();
289
- }
290
- getPositionByRange(abstractSelection) {
291
- let focus;
292
- let anchor;
293
- try {
294
- focus = this.findSelectedNodeAndOffset(abstractSelection.focusSlot, abstractSelection.focusOffset);
295
- anchor = focus;
296
- if (abstractSelection.anchorSlot !== abstractSelection.focusSlot ||
297
- abstractSelection.anchorOffset !== abstractSelection.focusOffset) {
298
- anchor = this.findSelectedNodeAndOffset(abstractSelection.anchorSlot, abstractSelection.anchorOffset);
299
- }
300
- return {
301
- focus,
302
- anchor
303
- };
304
- }
305
- catch (e) {
306
- return {
307
- focus: null,
308
- anchor: null
309
- };
310
- }
311
- }
312
- getPreviousLinePositionByCurrent(position) {
313
- return this.getLinePosition(position, false);
314
- }
315
- getNextLinePositionByCurrent(position) {
316
- return this.getLinePosition(position, true);
317
- }
318
- // private getLinePosition(currentPosition: SelectionPosition, toNext: boolean): SelectionPosition | null {
319
- // clearTimeout(this.cacheCaretPositionTimer)
320
- // let p: SelectionPosition | null
321
- // if (this.oldCaretPosition) {
322
- // p = this.caretRangeFromPoint(currentPosition, this.oldCaretPosition.left, toNext)
323
- // } else {
324
- // this.oldCaretPosition = this.getRect(currentPosition)!
325
- // p = this.caretRangeFromPoint(currentPosition, this.oldCaretPosition.left, toNext)
326
- // }
327
- // this.cacheCaretPositionTimer = setTimeout(() => {
328
- // this.oldCaretPosition = null
329
- // }, 3000)
330
- // return p
331
- // }
332
- //
333
- // private caretRangeFromPoint(currentPosition: SelectionPosition, x: number, toNext: boolean): SelectionPosition | null {
334
- // const rect = this.getRect(currentPosition)!
335
- // const fn = document.caretRangeFromPoint || function (x: number, y: number) {
336
- // const range = (document as any).caretPositionFromPoint(x, y)
337
- // return {
338
- // startContainer: range.offsetNode,
339
- // startOffset: range.offset
340
- // }
341
- // }
342
- //
343
- // const current = fn.call(document, rect.left, rect.top)!
344
- //
345
- // let startTop = toNext ? rect.top + rect.height : rect.top
346
- // const step = toNext ? 5 : -5
347
- // while (true) {
348
- // startTop += step
349
- // const newPosition = fn.call(document, x, startTop)
350
- // if (!newPosition) {
351
- // return toNext ?
352
- // this.selection.findLastPosition(this.rootComponentRef.component.slots.last, true) :
353
- // this.selection.findFirstPosition(this.rootComponentRef.component.slots.first, true)
354
- // }
355
- // if (newPosition.startContainer !== current.startContainer || newPosition.startOffset !== current.startOffset) {
356
- // return this.getCorrectedPosition(newPosition.startContainer, newPosition.startOffset, toNext)
357
- // }
358
- // }
359
- // return null
360
- // }
361
- getLinePosition(currentPosition, toNext) {
362
- clearTimeout(this.cacheCaretPositionTimer);
363
- let p;
364
- if (this.oldCaretPosition) {
365
- p = toNext ?
366
- this.getNextLinePositionByOffset(currentPosition, this.oldCaretPosition.left) :
367
- this.getPreviousLinePositionByOffset(currentPosition, this.oldCaretPosition.left);
368
- }
369
- else {
370
- this.oldCaretPosition = this.getRect(currentPosition);
371
- p = toNext ?
372
- this.getNextLinePositionByOffset(currentPosition, this.oldCaretPosition.left) :
373
- this.getPreviousLinePositionByOffset(currentPosition, this.oldCaretPosition.left);
374
- }
375
- this.cacheCaretPositionTimer = setTimeout(() => {
376
- this.oldCaretPosition = null;
377
- }, 3000);
378
- return p;
379
- }
380
- /**
381
- * 获取选区向上移动一行的位置。
382
- * @param currentPosition
383
- * @param startLeft 参考位置。
384
- */
385
- getPreviousLinePositionByOffset(currentPosition, startLeft) {
386
- let isToPrevLine = false;
387
- let loopCount = 0;
388
- let minLeft = startLeft;
389
- let focusSlot = currentPosition.slot;
390
- let focusOffset = currentPosition.offset;
391
- let minTop = this.getRect({
392
- slot: focusSlot,
393
- offset: focusOffset
394
- }).top;
395
- let position;
396
- let oldPosition;
397
- let oldLeft = 0;
398
- while (true) {
399
- loopCount++;
400
- position = this.selection.getPreviousPositionByPosition(focusSlot, focusOffset);
401
- focusSlot = position.slot;
402
- focusOffset = position.offset;
403
- const rect2 = this.getRect(position);
404
- if (!isToPrevLine) {
405
- if (rect2.left > minLeft || rect2.top + rect2.height <= minTop) {
406
- isToPrevLine = true;
407
- }
408
- else if (rect2.left === minLeft && rect2.top === minTop) {
409
- return position;
410
- }
411
- minLeft = rect2.left;
412
- minTop = rect2.top;
413
- }
414
- if (isToPrevLine) {
415
- if (rect2.left < startLeft) {
416
- return position;
417
- }
418
- if (oldPosition) {
419
- if (rect2.left >= oldLeft) {
420
- return oldPosition;
421
- }
422
- }
423
- oldLeft = rect2.left;
424
- oldPosition = position;
425
- }
426
- if (loopCount > 10000) {
427
- break;
428
- }
429
- }
430
- return position || {
431
- offset: 0,
432
- slot: focusSlot
433
- };
434
- }
435
- /**
436
- * 获取选区向下移动一行的位置。
437
- * @param currentPosition
438
- * @param startLeft 参考位置。
439
- */
440
- getNextLinePositionByOffset(currentPosition, startLeft) {
441
- let isToNextLine = false;
442
- let loopCount = 0;
443
- let maxRight = startLeft;
444
- let focusSlot = currentPosition.slot;
445
- let focusOffset = currentPosition.offset;
446
- const rect = this.getRect({
447
- slot: focusSlot,
448
- offset: focusOffset
449
- });
450
- let minTop = rect.top;
451
- let oldPosition;
452
- let oldLeft = 0;
453
- while (true) {
454
- loopCount++;
455
- const position = this.selection.getNextPositionByPosition(focusSlot, focusOffset);
456
- focusSlot = position.slot;
457
- focusOffset = position.offset;
458
- const rect2 = this.getRect(position);
459
- if (!isToNextLine) {
460
- if (rect2.left < maxRight || rect2.top >= minTop + rect.height) {
461
- isToNextLine = true;
462
- }
463
- else if (rect2.left === maxRight && rect2.top === minTop) {
464
- return position;
465
- }
466
- maxRight = rect2.left;
467
- minTop = rect2.top;
468
- oldPosition = position;
469
- }
470
- if (isToNextLine) {
471
- if (rect2.left > startLeft) {
472
- return oldPosition;
473
- }
474
- if (oldPosition) {
475
- if (rect2.left <= oldLeft) {
476
- return oldPosition;
477
- }
478
- }
479
- oldPosition = position;
480
- oldLeft = rect2.left;
481
- }
482
- if (loopCount > 10000) {
483
- break;
484
- }
485
- }
486
- return oldPosition || {
487
- offset: focusSlot.length,
488
- slot: focusSlot
489
- };
490
- }
491
- unListen() {
492
- this.subs.forEach(i => i.unsubscribe());
493
- this.subs = [];
494
- }
495
- listen(connector) {
496
- if (!this.config.useContentEditable) {
497
- const selection = this.nativeSelection;
498
- this.subs.push(fromEvent(this.docContainer, 'mousedown').subscribe(ev => {
499
- if (this.ignoreSelectionChange || ev.button === 2) {
500
- return;
501
- }
502
- if (!ev.shiftKey) {
503
- selection.removeAllRanges();
504
- }
505
- }));
506
- }
507
- this.subs.push(fromEvent(document, 'selectionchange').subscribe(() => {
508
- this.syncSelection(connector);
509
- }));
510
- }
511
- syncSelection(connector) {
512
- var _a;
513
- const selection = this.nativeSelection;
514
- this.changeFromUser = true;
515
- if (this.ignoreSelectionChange ||
516
- this.input.composition ||
517
- selection.rangeCount === 0 ||
518
- !this.docContainer.contains(selection.anchorNode) ||
519
- this.rootComponentRef.component.slots.length === 0) {
520
- return;
521
- }
522
- const rawRange = selection.getRangeAt(0);
523
- const nativeRange = rawRange.cloneRange();
524
- const isFocusEnd = selection.focusNode === nativeRange.endContainer && selection.focusOffset === nativeRange.endOffset;
525
- const isFocusStart = selection.focusNode === nativeRange.startContainer && selection.focusOffset === nativeRange.startOffset;
526
- if (!this.docContainer.contains(selection.focusNode)) {
527
- if (isFocusEnd) {
528
- const vEle = this.renderer.getVNodeBySlot(this.rootComponentRef.component.slots.first);
529
- if (!vEle) {
530
- return;
531
- }
532
- const nativeNode = this.renderer.getNativeNodeByVNode(vEle);
533
- if (!nativeNode) {
534
- return;
535
- }
536
- nativeRange.setEndAfter(nativeNode.lastChild);
537
- }
538
- else {
539
- const vEle = this.renderer.getVNodeBySlot(this.rootComponentRef.component.slots.last);
540
- if (!vEle) {
541
- return;
542
- }
543
- const nativeNode = this.renderer.getNativeNodeByVNode(vEle);
544
- if (!nativeNode) {
545
- return;
546
- }
547
- nativeRange.setStartBefore(nativeNode.firstChild);
548
- }
549
- }
550
- const startPosition = this.getCorrectedPosition(nativeRange.startContainer, nativeRange.startOffset, isFocusStart);
551
- const endPosition = nativeRange.collapsed ?
552
- startPosition :
553
- this.getCorrectedPosition(nativeRange.endContainer, nativeRange.endOffset, isFocusEnd);
554
- if ([Node.ELEMENT_NODE, Node.TEXT_NODE].includes((_a = nativeRange.commonAncestorContainer) === null || _a === void 0 ? void 0 : _a.nodeType) &&
555
- startPosition && endPosition) {
556
- const abstractSelection = isFocusEnd ? {
557
- anchorSlot: startPosition.slot,
558
- anchorOffset: startPosition.offset,
559
- focusSlot: endPosition.slot,
560
- focusOffset: endPosition.offset
561
- } : {
562
- focusSlot: startPosition.slot,
563
- focusOffset: startPosition.offset,
564
- anchorSlot: endPosition.slot,
565
- anchorOffset: endPosition.offset
566
- };
567
- const { focus, anchor } = this.getPositionByRange(abstractSelection);
568
- if (focus && anchor) {
569
- let start = anchor;
570
- let end = focus;
571
- if (isFocusStart) {
572
- start = focus;
573
- end = anchor;
574
- }
575
- if (nativeRange.startContainer !== start.node || nativeRange.startOffset !== start.offset) {
576
- nativeRange.setStart(start.node, start.offset);
577
- }
578
- if (nativeRange.endContainer !== end.node || nativeRange.endOffset !== end.offset) {
579
- nativeRange.setEnd(end.node, end.offset);
580
- }
581
- connector.setSelection(abstractSelection);
582
- if (selection.isCollapsed) {
583
- rawRange.setStart(start.node, start.offset);
584
- rawRange.setEnd(end.node, end.offset);
585
- }
586
- this.selectionChangeEvent.next(nativeRange);
587
- }
588
- else {
589
- connector.setSelection(null);
590
- }
591
- return;
592
- }
593
- connector.setSelection(null);
594
- }
595
- findSelectedNodeAndOffset(slot, offset) {
596
- const prev = slot.getContentAtIndex(offset - 1);
597
- const vNodes = this.renderer.getVNodesBySlot(slot);
598
- if (prev) {
599
- if (typeof prev !== 'string') {
600
- const vNode = this.renderer.getVNodeByComponent(prev);
601
- const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
602
- return {
603
- node: nativeNode.parentNode,
604
- offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode) + 1
605
- };
606
- }
607
- else if (prev === '\n') {
608
- for (const vNode of vNodes) {
609
- if (vNode instanceof VTextNode) {
610
- continue;
611
- }
612
- if (vNode.tagName === 'br') {
613
- const position = this.renderer.getLocationByVNode(vNode);
614
- if (position) {
615
- if (position.endIndex === offset) {
616
- const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
617
- const parentNode = nativeNode.parentNode;
618
- return {
619
- node: parentNode,
620
- offset: Array.from(parentNode.childNodes).indexOf(nativeNode) + 1
621
- };
622
- }
623
- }
624
- }
625
- }
626
- }
627
- }
628
- const current = slot.getContentAtIndex(offset);
629
- if (current && typeof current !== 'string') {
630
- const vNode = this.renderer.getVNodeByComponent(current);
631
- const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
632
- return {
633
- node: nativeNode.parentNode,
634
- offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode)
635
- };
636
- }
637
- for (const vNode of vNodes) {
638
- if (vNode instanceof VElement) {
639
- if (vNode.tagName === 'br') {
640
- const position = this.renderer.getLocationByVNode(vNode);
641
- if (position) {
642
- if (position.startIndex === offset) {
643
- const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
644
- const parentNode = nativeNode.parentNode;
645
- return {
646
- node: parentNode,
647
- offset: Array.from(parentNode.childNodes).indexOf(nativeNode)
648
- };
649
- }
650
- }
651
- }
652
- continue;
653
- }
654
- const position = this.renderer.getLocationByVNode(vNode);
655
- if (position) {
656
- if (offset >= position.startIndex && offset <= position.endIndex) {
657
- const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
658
- return {
659
- node: nativeNode,
660
- offset: offset - position.startIndex
661
- };
662
- }
663
- }
664
- }
665
- return null;
666
- }
667
- getCorrectedPosition(node, offset, toAfter, excludeNodes = []) {
668
- excludeNodes.push(node);
669
- if (node.nodeType === Node.ELEMENT_NODE) {
670
- const containerPosition = this.renderer.getLocationByNativeNode(node);
671
- const childNode = node.childNodes[offset];
672
- if (childNode) {
673
- const childPosition = this.renderer.getLocationByNativeNode(childNode);
674
- if (childPosition) {
675
- if (containerPosition) {
676
- return {
677
- slot: childPosition.slot,
678
- offset: childPosition.startIndex
679
- };
680
- }
681
- return this.findFocusNode(childNode, toAfter, excludeNodes);
682
- }
683
- return this.findFocusNode(childNode, toAfter, excludeNodes);
684
- }
685
- const prevNode = node.childNodes[offset - 1];
686
- if (prevNode) {
687
- const prevPosition = this.renderer.getLocationByNativeNode(prevNode);
688
- if (prevPosition && containerPosition) {
689
- return {
690
- slot: prevPosition.slot,
691
- offset: prevPosition.endIndex
692
- };
693
- }
694
- }
695
- if (containerPosition) {
696
- return {
697
- slot: containerPosition.slot,
698
- offset: containerPosition.endIndex
699
- };
700
- }
701
- const nextNode = toAfter ? node.nextSibling : node.previousSibling;
702
- if (nextNode) {
703
- return this.findFocusNode(nextNode, toAfter, excludeNodes);
704
- }
705
- return this.findFocusNodeByParent(node, toAfter, excludeNodes);
706
- }
707
- else if (node.nodeType === Node.TEXT_NODE) {
708
- const containerPosition = this.renderer.getLocationByNativeNode(node);
709
- if (containerPosition) {
710
- return {
711
- slot: containerPosition.slot,
712
- offset: containerPosition.startIndex + offset
713
- };
714
- }
715
- const nextNode = toAfter ? node.nextSibling : node.previousSibling;
716
- if (nextNode) {
717
- return this.findFocusNode(nextNode, toAfter, excludeNodes);
718
- }
719
- return this.findFocusNodeByParent(node, toAfter, excludeNodes);
720
- }
721
- return null;
722
- }
723
- findFocusNode(node, toAfter = false, excludeNodes = []) {
724
- if (excludeNodes.includes(node)) {
725
- const next = toAfter ? node.nextSibling : node.previousSibling;
726
- if (next) {
727
- return this.findFocusNode(next, toAfter, excludeNodes);
728
- }
729
- return this.findFocusNodeByParent(node, toAfter, excludeNodes);
730
- }
731
- excludeNodes.push(node);
732
- const position = this.renderer.getLocationByNativeNode(node);
733
- if (position) {
734
- return {
735
- slot: position.slot,
736
- offset: toAfter ? position.startIndex : position.endIndex
737
- };
738
- }
739
- const firstChild = toAfter ? node.firstChild : node.lastChild;
740
- if (firstChild) {
741
- return this.findFocusNode(firstChild, toAfter, excludeNodes);
742
- }
743
- const nextSibling = toAfter ? node.nextSibling : node.previousSibling;
744
- if (nextSibling) {
745
- return this.findFocusNode(nextSibling, toAfter, excludeNodes);
746
- }
747
- return this.findFocusNodeByParent(node, toAfter, excludeNodes);
748
- }
749
- findFocusNodeByParent(node, toAfter, excludeNodes) {
750
- const parentNode = node.parentNode;
751
- if (parentNode) {
752
- const parentPosition = this.renderer.getLocationByNativeNode(parentNode);
753
- if (parentPosition) {
754
- return {
755
- slot: parentPosition.slot,
756
- offset: toAfter ? parentPosition.endIndex : parentPosition.startIndex
757
- };
758
- }
759
- excludeNodes.push(node);
760
- return this.findFocusNode(parentNode, toAfter, excludeNodes);
761
- }
762
- return null;
763
- }
764
- };
765
- SelectionBridge = __decorate([
766
- Injectable(),
767
- __param(0, Inject(EDITOR_OPTIONS)),
768
- __metadata("design:paramtypes", [Object, Injector,
769
- Controller,
770
- Selection,
771
- RootComponentRef,
772
- Input,
773
- Renderer])
165
+ /**
166
+ * Textbus PC 端选区桥接实现
167
+ */
168
+ let SelectionBridge = class SelectionBridge {
169
+ constructor(config, injector, controller, selection, rootComponentRef, input, renderer) {
170
+ this.config = config;
171
+ this.injector = injector;
172
+ this.controller = controller;
173
+ this.selection = selection;
174
+ this.rootComponentRef = rootComponentRef;
175
+ this.input = input;
176
+ this.renderer = renderer;
177
+ this.nativeSelection = document.getSelection();
178
+ this.selectionMaskElement = createElement('style');
179
+ this.selectionChangeEvent = new Subject();
180
+ this.subs = [];
181
+ this.connector = null;
182
+ this.ignoreSelectionChange = false;
183
+ this.changeFromUser = false;
184
+ this.docContainer = injector.get(VIEW_DOCUMENT);
185
+ this.maskContainer = injector.get(VIEW_MASK);
186
+ this.onSelectionChange = this.selectionChangeEvent.asObservable().pipe(filter(() => {
187
+ return !controller.readonly;
188
+ }));
189
+ document.head.appendChild(this.selectionMaskElement);
190
+ this.sub = this.onSelectionChange.subscribe((r) => {
191
+ if (r) {
192
+ input.focus(r, this.changeFromUser);
193
+ }
194
+ else {
195
+ input.blur();
196
+ }
197
+ });
198
+ this.sub.add(fromEvent(document, 'focusin').subscribe(ev => {
199
+ let target = ev.target;
200
+ if (/^(input|textarea|select)$/i.test(target.nodeName)) {
201
+ if (target.tagName.toLowerCase() === 'input' && /^(range|date)$/.test(target.type)) {
202
+ return;
203
+ }
204
+ this.ignoreSelectionChange = true;
205
+ return;
206
+ }
207
+ if (!config.useContentEditable) {
208
+ while (target) {
209
+ if (target.contentEditable === 'true') {
210
+ this.ignoreSelectionChange = true;
211
+ return;
212
+ }
213
+ target = target.parentNode;
214
+ }
215
+ }
216
+ }));
217
+ this.sub.add(fromEvent(document, 'focusout').subscribe(() => {
218
+ this.ignoreSelectionChange = false;
219
+ }));
220
+ }
221
+ connect(connector) {
222
+ this.disConnect();
223
+ this.connector = connector;
224
+ this.syncSelection(connector);
225
+ this.listen(connector);
226
+ }
227
+ disConnect() {
228
+ this.connector = null;
229
+ this.unListen();
230
+ }
231
+ getRect(location) {
232
+ const { focus, anchor } = this.getPositionByRange({
233
+ focusOffset: location.offset,
234
+ anchorOffset: location.offset,
235
+ focusSlot: location.slot,
236
+ anchorSlot: location.slot
237
+ });
238
+ if (!focus || !anchor) {
239
+ return null;
240
+ }
241
+ const nativeRange = document.createRange();
242
+ nativeRange.setStart(focus.node, focus.offset);
243
+ nativeRange.collapse();
244
+ return getLayoutRectByRange(nativeRange);
245
+ }
246
+ restore(abstractSelection, formLocal) {
247
+ this.changeFromUser = formLocal;
248
+ if (this.ignoreSelectionChange || !this.connector) {
249
+ return;
250
+ }
251
+ this.unListen();
252
+ if (!abstractSelection) {
253
+ this.nativeSelection.removeAllRanges();
254
+ this.selectionChangeEvent.next(null);
255
+ this.listen(this.connector);
256
+ return;
257
+ }
258
+ const { focus, anchor } = this.getPositionByRange(abstractSelection);
259
+ if (!focus || !anchor) {
260
+ this.nativeSelection.removeAllRanges();
261
+ this.selectionChangeEvent.next(null);
262
+ this.listen(this.connector);
263
+ return;
264
+ }
265
+ this.nativeSelection.setBaseAndExtent(anchor.node, anchor.offset, focus.node, focus.offset);
266
+ if (this.nativeSelection.rangeCount) {
267
+ const nativeRange = this.nativeSelection.getRangeAt(0);
268
+ this.selectionChangeEvent.next(nativeRange);
269
+ }
270
+ else {
271
+ this.selectionChangeEvent.next(null);
272
+ }
273
+ // hack start 浏览器会触发上面选区更改事件
274
+ const bind = () => {
275
+ if (this.connector) {
276
+ this.listen(this.connector);
277
+ }
278
+ };
279
+ if (typeof requestIdleCallback === 'function') {
280
+ requestIdleCallback(bind);
281
+ }
282
+ else {
283
+ setTimeout(bind, 30);
284
+ }
285
+ // hack end
286
+ }
287
+ destroy() {
288
+ this.sub.unsubscribe();
289
+ }
290
+ getPositionByRange(abstractSelection) {
291
+ let focus;
292
+ let anchor;
293
+ try {
294
+ focus = this.findSelectedNodeAndOffset(abstractSelection.focusSlot, abstractSelection.focusOffset);
295
+ anchor = focus;
296
+ if (abstractSelection.anchorSlot !== abstractSelection.focusSlot ||
297
+ abstractSelection.anchorOffset !== abstractSelection.focusOffset) {
298
+ anchor = this.findSelectedNodeAndOffset(abstractSelection.anchorSlot, abstractSelection.anchorOffset);
299
+ }
300
+ return {
301
+ focus,
302
+ anchor
303
+ };
304
+ }
305
+ catch (e) {
306
+ return {
307
+ focus: null,
308
+ anchor: null
309
+ };
310
+ }
311
+ }
312
+ getPreviousLinePositionByCurrent(position) {
313
+ return this.getLinePosition(position, false);
314
+ }
315
+ getNextLinePositionByCurrent(position) {
316
+ return this.getLinePosition(position, true);
317
+ }
318
+ // private getLinePosition(currentPosition: SelectionPosition, toNext: boolean): SelectionPosition | null {
319
+ // clearTimeout(this.cacheCaretPositionTimer)
320
+ // let p: SelectionPosition | null
321
+ // if (this.oldCaretPosition) {
322
+ // p = this.caretRangeFromPoint(currentPosition, this.oldCaretPosition.left, toNext)
323
+ // } else {
324
+ // this.oldCaretPosition = this.getRect(currentPosition)!
325
+ // p = this.caretRangeFromPoint(currentPosition, this.oldCaretPosition.left, toNext)
326
+ // }
327
+ // this.cacheCaretPositionTimer = setTimeout(() => {
328
+ // this.oldCaretPosition = null
329
+ // }, 3000)
330
+ // return p
331
+ // }
332
+ //
333
+ // private caretRangeFromPoint(currentPosition: SelectionPosition, x: number, toNext: boolean): SelectionPosition | null {
334
+ // const rect = this.getRect(currentPosition)!
335
+ // const fn = document.caretRangeFromPoint || function (x: number, y: number) {
336
+ // const range = (document as any).caretPositionFromPoint(x, y)
337
+ // return {
338
+ // startContainer: range.offsetNode,
339
+ // startOffset: range.offset
340
+ // }
341
+ // }
342
+ //
343
+ // const current = fn.call(document, rect.left, rect.top)!
344
+ //
345
+ // let startTop = toNext ? rect.top + rect.height : rect.top
346
+ // const step = toNext ? 5 : -5
347
+ // while (true) {
348
+ // startTop += step
349
+ // const newPosition = fn.call(document, x, startTop)
350
+ // if (!newPosition) {
351
+ // return toNext ?
352
+ // this.selection.findLastPosition(this.rootComponentRef.component.slots.last, true) :
353
+ // this.selection.findFirstPosition(this.rootComponentRef.component.slots.first, true)
354
+ // }
355
+ // if (newPosition.startContainer !== current.startContainer || newPosition.startOffset !== current.startOffset) {
356
+ // return this.getCorrectedPosition(newPosition.startContainer, newPosition.startOffset, toNext)
357
+ // }
358
+ // }
359
+ // return null
360
+ // }
361
+ getLinePosition(currentPosition, toNext) {
362
+ clearTimeout(this.cacheCaretPositionTimer);
363
+ let p;
364
+ if (this.oldCaretPosition) {
365
+ p = toNext ?
366
+ this.getNextLinePositionByOffset(currentPosition, this.oldCaretPosition.left) :
367
+ this.getPreviousLinePositionByOffset(currentPosition, this.oldCaretPosition.left);
368
+ }
369
+ else {
370
+ this.oldCaretPosition = this.getRect(currentPosition);
371
+ p = toNext ?
372
+ this.getNextLinePositionByOffset(currentPosition, this.oldCaretPosition.left) :
373
+ this.getPreviousLinePositionByOffset(currentPosition, this.oldCaretPosition.left);
374
+ }
375
+ this.cacheCaretPositionTimer = setTimeout(() => {
376
+ this.oldCaretPosition = null;
377
+ }, 3000);
378
+ return p;
379
+ }
380
+ /**
381
+ * 获取选区向上移动一行的位置。
382
+ * @param currentPosition
383
+ * @param startLeft 参考位置。
384
+ */
385
+ getPreviousLinePositionByOffset(currentPosition, startLeft) {
386
+ let isToPrevLine = false;
387
+ let loopCount = 0;
388
+ let minLeft = startLeft;
389
+ let focusSlot = currentPosition.slot;
390
+ let focusOffset = currentPosition.offset;
391
+ let minTop = this.getRect({
392
+ slot: focusSlot,
393
+ offset: focusOffset
394
+ }).top;
395
+ let position;
396
+ let oldPosition;
397
+ let oldLeft = 0;
398
+ while (true) {
399
+ loopCount++;
400
+ position = this.selection.getPreviousPositionByPosition(focusSlot, focusOffset);
401
+ focusSlot = position.slot;
402
+ focusOffset = position.offset;
403
+ const rect2 = this.getRect(position);
404
+ if (!isToPrevLine) {
405
+ if (rect2.left > minLeft || rect2.top + rect2.height <= minTop) {
406
+ isToPrevLine = true;
407
+ }
408
+ else if (rect2.left === minLeft && rect2.top === minTop) {
409
+ return position;
410
+ }
411
+ minLeft = rect2.left;
412
+ minTop = rect2.top;
413
+ }
414
+ if (isToPrevLine) {
415
+ if (rect2.left < startLeft) {
416
+ return position;
417
+ }
418
+ if (oldPosition) {
419
+ if (rect2.left >= oldLeft) {
420
+ return oldPosition;
421
+ }
422
+ }
423
+ oldLeft = rect2.left;
424
+ oldPosition = position;
425
+ }
426
+ if (loopCount > 10000) {
427
+ break;
428
+ }
429
+ }
430
+ return position || {
431
+ offset: 0,
432
+ slot: focusSlot
433
+ };
434
+ }
435
+ /**
436
+ * 获取选区向下移动一行的位置。
437
+ * @param currentPosition
438
+ * @param startLeft 参考位置。
439
+ */
440
+ getNextLinePositionByOffset(currentPosition, startLeft) {
441
+ let isToNextLine = false;
442
+ let loopCount = 0;
443
+ let maxRight = startLeft;
444
+ let focusSlot = currentPosition.slot;
445
+ let focusOffset = currentPosition.offset;
446
+ const rect = this.getRect({
447
+ slot: focusSlot,
448
+ offset: focusOffset
449
+ });
450
+ let minTop = rect.top;
451
+ let oldPosition;
452
+ let oldLeft = 0;
453
+ while (true) {
454
+ loopCount++;
455
+ const position = this.selection.getNextPositionByPosition(focusSlot, focusOffset);
456
+ focusSlot = position.slot;
457
+ focusOffset = position.offset;
458
+ const rect2 = this.getRect(position);
459
+ if (!isToNextLine) {
460
+ if (rect2.left < maxRight || rect2.top >= minTop + rect.height) {
461
+ isToNextLine = true;
462
+ }
463
+ else if (rect2.left === maxRight && rect2.top === minTop) {
464
+ return position;
465
+ }
466
+ maxRight = rect2.left;
467
+ minTop = rect2.top;
468
+ oldPosition = position;
469
+ }
470
+ if (isToNextLine) {
471
+ if (rect2.left > startLeft) {
472
+ return oldPosition;
473
+ }
474
+ if (oldPosition) {
475
+ if (rect2.left <= oldLeft) {
476
+ return oldPosition;
477
+ }
478
+ }
479
+ oldPosition = position;
480
+ oldLeft = rect2.left;
481
+ }
482
+ if (loopCount > 10000) {
483
+ break;
484
+ }
485
+ }
486
+ return oldPosition || {
487
+ offset: focusSlot.length,
488
+ slot: focusSlot
489
+ };
490
+ }
491
+ unListen() {
492
+ this.subs.forEach(i => i.unsubscribe());
493
+ this.subs = [];
494
+ }
495
+ listen(connector) {
496
+ if (!this.config.useContentEditable) {
497
+ const selection = this.nativeSelection;
498
+ this.subs.push(fromEvent(this.docContainer, 'mousedown').subscribe(ev => {
499
+ if (this.ignoreSelectionChange || ev.button === 2) {
500
+ return;
501
+ }
502
+ if (!ev.shiftKey) {
503
+ selection.removeAllRanges();
504
+ }
505
+ }));
506
+ }
507
+ this.subs.push(fromEvent(document, 'selectionchange').subscribe(() => {
508
+ this.syncSelection(connector);
509
+ }));
510
+ }
511
+ syncSelection(connector) {
512
+ var _a;
513
+ const selection = this.nativeSelection;
514
+ this.changeFromUser = true;
515
+ if (this.ignoreSelectionChange ||
516
+ this.input.composition ||
517
+ selection.rangeCount === 0 ||
518
+ !this.docContainer.contains(selection.anchorNode) ||
519
+ this.rootComponentRef.component.slots.length === 0) {
520
+ return;
521
+ }
522
+ const rawRange = selection.getRangeAt(0);
523
+ const nativeRange = rawRange.cloneRange();
524
+ const isFocusEnd = selection.focusNode === nativeRange.endContainer && selection.focusOffset === nativeRange.endOffset;
525
+ const isFocusStart = selection.focusNode === nativeRange.startContainer && selection.focusOffset === nativeRange.startOffset;
526
+ if (!this.docContainer.contains(selection.focusNode)) {
527
+ if (isFocusEnd) {
528
+ const vEle = this.renderer.getVNodeBySlot(this.rootComponentRef.component.slots.first);
529
+ if (!vEle) {
530
+ return;
531
+ }
532
+ const nativeNode = this.renderer.getNativeNodeByVNode(vEle);
533
+ if (!nativeNode) {
534
+ return;
535
+ }
536
+ nativeRange.setEndAfter(nativeNode.lastChild);
537
+ }
538
+ else {
539
+ const vEle = this.renderer.getVNodeBySlot(this.rootComponentRef.component.slots.last);
540
+ if (!vEle) {
541
+ return;
542
+ }
543
+ const nativeNode = this.renderer.getNativeNodeByVNode(vEle);
544
+ if (!nativeNode) {
545
+ return;
546
+ }
547
+ nativeRange.setStartBefore(nativeNode.firstChild);
548
+ }
549
+ }
550
+ const startPosition = this.getCorrectedPosition(nativeRange.startContainer, nativeRange.startOffset, isFocusStart);
551
+ const endPosition = nativeRange.collapsed ?
552
+ startPosition :
553
+ this.getCorrectedPosition(nativeRange.endContainer, nativeRange.endOffset, isFocusEnd);
554
+ if ([Node.ELEMENT_NODE, Node.TEXT_NODE].includes((_a = nativeRange.commonAncestorContainer) === null || _a === void 0 ? void 0 : _a.nodeType) &&
555
+ startPosition && endPosition) {
556
+ const abstractSelection = isFocusEnd ? {
557
+ anchorSlot: startPosition.slot,
558
+ anchorOffset: startPosition.offset,
559
+ focusSlot: endPosition.slot,
560
+ focusOffset: endPosition.offset
561
+ } : {
562
+ focusSlot: startPosition.slot,
563
+ focusOffset: startPosition.offset,
564
+ anchorSlot: endPosition.slot,
565
+ anchorOffset: endPosition.offset
566
+ };
567
+ const { focus, anchor } = this.getPositionByRange(abstractSelection);
568
+ if (focus && anchor) {
569
+ let start = anchor;
570
+ let end = focus;
571
+ if (isFocusStart) {
572
+ start = focus;
573
+ end = anchor;
574
+ }
575
+ if (nativeRange.startContainer !== start.node || nativeRange.startOffset !== start.offset) {
576
+ nativeRange.setStart(start.node, start.offset);
577
+ }
578
+ if (nativeRange.endContainer !== end.node || nativeRange.endOffset !== end.offset) {
579
+ nativeRange.setEnd(end.node, end.offset);
580
+ }
581
+ connector.setSelection(abstractSelection);
582
+ if (selection.isCollapsed) {
583
+ rawRange.setStart(start.node, start.offset);
584
+ rawRange.setEnd(end.node, end.offset);
585
+ }
586
+ this.selectionChangeEvent.next(nativeRange);
587
+ }
588
+ else {
589
+ connector.setSelection(null);
590
+ }
591
+ return;
592
+ }
593
+ connector.setSelection(null);
594
+ }
595
+ findSelectedNodeAndOffset(slot, offset) {
596
+ const prev = slot.getContentAtIndex(offset - 1);
597
+ const vNodes = this.renderer.getVNodesBySlot(slot);
598
+ if (prev) {
599
+ if (typeof prev !== 'string') {
600
+ const vNode = this.renderer.getVNodeByComponent(prev);
601
+ const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
602
+ return {
603
+ node: nativeNode.parentNode,
604
+ offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode) + 1
605
+ };
606
+ }
607
+ else if (prev === '\n') {
608
+ for (const vNode of vNodes) {
609
+ if (vNode instanceof VTextNode) {
610
+ continue;
611
+ }
612
+ if (vNode.tagName === 'br') {
613
+ const position = this.renderer.getLocationByVNode(vNode);
614
+ if (position) {
615
+ if (position.endIndex === offset) {
616
+ const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
617
+ const parentNode = nativeNode.parentNode;
618
+ return {
619
+ node: parentNode,
620
+ offset: Array.from(parentNode.childNodes).indexOf(nativeNode) + 1
621
+ };
622
+ }
623
+ }
624
+ }
625
+ }
626
+ }
627
+ }
628
+ const current = slot.getContentAtIndex(offset);
629
+ if (current && typeof current !== 'string') {
630
+ const vNode = this.renderer.getVNodeByComponent(current);
631
+ const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
632
+ return {
633
+ node: nativeNode.parentNode,
634
+ offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode)
635
+ };
636
+ }
637
+ for (const vNode of vNodes) {
638
+ if (vNode instanceof VElement) {
639
+ if (vNode.tagName === 'br') {
640
+ const position = this.renderer.getLocationByVNode(vNode);
641
+ if (position) {
642
+ if (position.startIndex === offset) {
643
+ const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
644
+ const parentNode = nativeNode.parentNode;
645
+ return {
646
+ node: parentNode,
647
+ offset: Array.from(parentNode.childNodes).indexOf(nativeNode)
648
+ };
649
+ }
650
+ }
651
+ }
652
+ continue;
653
+ }
654
+ const position = this.renderer.getLocationByVNode(vNode);
655
+ if (position) {
656
+ if (offset >= position.startIndex && offset <= position.endIndex) {
657
+ const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
658
+ return {
659
+ node: nativeNode,
660
+ offset: offset - position.startIndex
661
+ };
662
+ }
663
+ }
664
+ }
665
+ return null;
666
+ }
667
+ getCorrectedPosition(node, offset, toAfter, excludeNodes = []) {
668
+ excludeNodes.push(node);
669
+ if (node.nodeType === Node.ELEMENT_NODE) {
670
+ const containerPosition = this.renderer.getLocationByNativeNode(node);
671
+ const childNode = node.childNodes[offset];
672
+ if (childNode) {
673
+ const childPosition = this.renderer.getLocationByNativeNode(childNode);
674
+ if (childPosition) {
675
+ if (containerPosition) {
676
+ return {
677
+ slot: childPosition.slot,
678
+ offset: childPosition.startIndex
679
+ };
680
+ }
681
+ return this.findFocusNode(childNode, toAfter, excludeNodes);
682
+ }
683
+ return this.findFocusNode(childNode, toAfter, excludeNodes);
684
+ }
685
+ const prevNode = node.childNodes[offset - 1];
686
+ if (prevNode) {
687
+ const prevPosition = this.renderer.getLocationByNativeNode(prevNode);
688
+ if (prevPosition && containerPosition) {
689
+ return {
690
+ slot: prevPosition.slot,
691
+ offset: prevPosition.endIndex
692
+ };
693
+ }
694
+ }
695
+ if (containerPosition) {
696
+ return {
697
+ slot: containerPosition.slot,
698
+ offset: containerPosition.endIndex
699
+ };
700
+ }
701
+ const nextNode = toAfter ? node.nextSibling : node.previousSibling;
702
+ if (nextNode) {
703
+ return this.findFocusNode(nextNode, toAfter, excludeNodes);
704
+ }
705
+ return this.findFocusNodeByParent(node, toAfter, excludeNodes);
706
+ }
707
+ else if (node.nodeType === Node.TEXT_NODE) {
708
+ const containerPosition = this.renderer.getLocationByNativeNode(node);
709
+ if (containerPosition) {
710
+ return {
711
+ slot: containerPosition.slot,
712
+ offset: containerPosition.startIndex + offset
713
+ };
714
+ }
715
+ const nextNode = toAfter ? node.nextSibling : node.previousSibling;
716
+ if (nextNode) {
717
+ return this.findFocusNode(nextNode, toAfter, excludeNodes);
718
+ }
719
+ return this.findFocusNodeByParent(node, toAfter, excludeNodes);
720
+ }
721
+ return null;
722
+ }
723
+ findFocusNode(node, toAfter = false, excludeNodes = []) {
724
+ if (excludeNodes.includes(node)) {
725
+ const next = toAfter ? node.nextSibling : node.previousSibling;
726
+ if (next) {
727
+ return this.findFocusNode(next, toAfter, excludeNodes);
728
+ }
729
+ return this.findFocusNodeByParent(node, toAfter, excludeNodes);
730
+ }
731
+ excludeNodes.push(node);
732
+ const position = this.renderer.getLocationByNativeNode(node);
733
+ if (position) {
734
+ return {
735
+ slot: position.slot,
736
+ offset: toAfter ? position.startIndex : position.endIndex
737
+ };
738
+ }
739
+ const firstChild = toAfter ? node.firstChild : node.lastChild;
740
+ if (firstChild) {
741
+ return this.findFocusNode(firstChild, toAfter, excludeNodes);
742
+ }
743
+ const nextSibling = toAfter ? node.nextSibling : node.previousSibling;
744
+ if (nextSibling) {
745
+ return this.findFocusNode(nextSibling, toAfter, excludeNodes);
746
+ }
747
+ return this.findFocusNodeByParent(node, toAfter, excludeNodes);
748
+ }
749
+ findFocusNodeByParent(node, toAfter, excludeNodes) {
750
+ const parentNode = node.parentNode;
751
+ if (parentNode) {
752
+ const parentPosition = this.renderer.getLocationByNativeNode(parentNode);
753
+ if (parentPosition) {
754
+ return {
755
+ slot: parentPosition.slot,
756
+ offset: toAfter ? parentPosition.endIndex : parentPosition.startIndex
757
+ };
758
+ }
759
+ excludeNodes.push(node);
760
+ return this.findFocusNode(parentNode, toAfter, excludeNodes);
761
+ }
762
+ return null;
763
+ }
764
+ };
765
+ SelectionBridge = __decorate([
766
+ Injectable(),
767
+ __param(0, Inject(EDITOR_OPTIONS)),
768
+ __metadata("design:paramtypes", [Object, Injector,
769
+ Controller,
770
+ Selection,
771
+ RootComponentRef,
772
+ Input,
773
+ Renderer])
774
774
  ], SelectionBridge);
775
775
 
776
- class CollaborateSelectionAwarenessDelegate {
777
- }
778
- let CollaborateCursor = class CollaborateCursor {
779
- constructor(injector, nativeSelection, renderer, selection, awarenessDelegate) {
780
- this.injector = injector;
781
- this.nativeSelection = nativeSelection;
782
- this.renderer = renderer;
783
- this.selection = selection;
784
- this.awarenessDelegate = awarenessDelegate;
785
- this.host = createElement('div', {
786
- styles: {
787
- position: 'absolute',
788
- left: 0,
789
- top: 0,
790
- width: '100%',
791
- height: '100%',
792
- pointerEvents: 'none',
793
- zIndex: 1
794
- }
795
- });
796
- this.canvasContainer = createElement('div', {
797
- styles: {
798
- position: 'absolute',
799
- left: 0,
800
- top: 0,
801
- width: '100%',
802
- height: '100%',
803
- overflow: 'hidden'
804
- }
805
- });
806
- this.canvas = createElement('canvas', {
807
- styles: {
808
- position: 'absolute',
809
- opacity: 0.5,
810
- left: 0,
811
- top: 0,
812
- width: '100%',
813
- height: document.documentElement.clientHeight + 'px',
814
- pointerEvents: 'none',
815
- }
816
- });
817
- this.context = this.canvas.getContext('2d');
818
- this.tooltips = createElement('div', {
819
- styles: {
820
- position: 'absolute',
821
- left: 0,
822
- top: 0,
823
- width: '100%',
824
- height: '100%',
825
- pointerEvents: 'none',
826
- fontSize: '12px',
827
- zIndex: 10
828
- }
829
- });
830
- this.onRectsChange = new Subject();
831
- this.subscription = new Subscription();
832
- this.currentSelection = [];
833
- this.container = injector.get(VIEW_CONTAINER);
834
- this.canvasContainer.append(this.canvas);
835
- this.host.append(this.canvasContainer, this.tooltips);
836
- this.container.prepend(this.host);
837
- this.subscription.add(this.onRectsChange.subscribe(rects => {
838
- for (const rect of rects) {
839
- this.context.fillStyle = rect.color;
840
- this.context.beginPath();
841
- this.context.rect(rect.left, rect.top, rect.width, rect.height);
842
- this.context.fill();
843
- this.context.closePath();
844
- }
845
- }), fromEvent(window, 'resize').subscribe(() => {
846
- this.canvas.style.height = document.documentElement.clientHeight + 'px';
847
- this.refresh();
848
- }), this.renderer.onViewUpdated.subscribe(() => {
849
- this.refresh();
850
- }));
851
- }
852
- refresh() {
853
- this.draw(this.currentSelection);
854
- }
855
- destroy() {
856
- this.subscription.unsubscribe();
857
- }
858
- draw(paths) {
859
- this.currentSelection = paths;
860
- const containerRect = this.container.getBoundingClientRect();
861
- this.canvas.style.top = containerRect.top * -1 + 'px';
862
- this.canvas.width = this.canvas.offsetWidth;
863
- this.canvas.height = this.canvas.offsetHeight;
864
- this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
865
- const users = [];
866
- paths.filter(i => {
867
- return i.paths.anchor.length && i.paths.focus.length;
868
- }).forEach(item => {
869
- const anchorPaths = [...item.paths.anchor];
870
- const focusPaths = [...item.paths.focus];
871
- const anchorOffset = anchorPaths.pop();
872
- const anchorSlot = this.selection.findSlotByPaths(anchorPaths);
873
- const focusOffset = focusPaths.pop();
874
- const focusSlot = this.selection.findSlotByPaths(focusPaths);
875
- if (!anchorSlot || !focusSlot) {
876
- return;
877
- }
878
- const { focus, anchor } = this.nativeSelection.getPositionByRange({
879
- focusOffset,
880
- anchorOffset,
881
- focusSlot,
882
- anchorSlot
883
- });
884
- if (!focus || !anchor) {
885
- return;
886
- }
887
- const nativeRange = document.createRange();
888
- nativeRange.setStart(anchor.node, anchor.offset);
889
- nativeRange.setEnd(focus.node, focus.offset);
890
- if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
891
- nativeRange.setStart(focus.node, focus.offset);
892
- nativeRange.setEnd(anchor.node, anchor.offset);
893
- }
894
- let rects = false;
895
- if (this.awarenessDelegate) {
896
- rects = this.awarenessDelegate.getRects({
897
- focusOffset,
898
- anchorOffset,
899
- focusSlot,
900
- anchorSlot
901
- }, nativeRange);
902
- }
903
- if (!rects) {
904
- rects = nativeRange.getClientRects();
905
- }
906
- const selectionRects = [];
907
- for (let i = rects.length - 1; i >= 0; i--) {
908
- const rect = rects[i];
909
- selectionRects.push({
910
- id: item.id,
911
- color: item.color,
912
- username: item.username,
913
- left: rect.left - containerRect.left,
914
- top: rect.top,
915
- width: rect.width,
916
- height: rect.height,
917
- });
918
- }
919
- this.onRectsChange.next(selectionRects);
920
- const cursorRange = nativeRange.cloneRange();
921
- cursorRange.setStart(focus.node, focus.offset);
922
- cursorRange.collapse(true);
923
- const cursorRect = getLayoutRectByRange(cursorRange);
924
- const rect = {
925
- id: item.id,
926
- username: item.username,
927
- color: item.color,
928
- left: cursorRect.left - containerRect.left,
929
- top: cursorRect.top - containerRect.top,
930
- width: 1,
931
- height: cursorRect.height
932
- };
933
- if (rect.left < 0 || rect.top < 0 || rect.left > containerRect.width) {
934
- return;
935
- }
936
- users.push(rect);
937
- });
938
- this.drawUserCursor(users);
939
- }
940
- drawUserCursor(rects) {
941
- for (let i = 0; i < rects.length; i++) {
942
- const rect = rects[i];
943
- const { cursor, userTip, anchor } = this.getUserCursor(i);
944
- Object.assign(cursor.style, {
945
- left: rect.left + 'px',
946
- top: rect.top + 'px',
947
- width: rect.width + 'px',
948
- height: rect.height + 'px',
949
- background: rect.color,
950
- display: 'block'
951
- });
952
- anchor.style.background = rect.color;
953
- userTip.innerText = rect.username;
954
- userTip.style.background = rect.color;
955
- }
956
- for (let i = rects.length; i < this.tooltips.children.length; i++) {
957
- this.tooltips.removeChild(this.tooltips.children[i]);
958
- }
959
- }
960
- getUserCursor(index) {
961
- let child = this.tooltips.children[index];
962
- if (child) {
963
- const anchor = child.children[0];
964
- return {
965
- cursor: child,
966
- anchor,
967
- userTip: anchor.children[0]
968
- };
969
- }
970
- const userTip = createElement('span', {
971
- styles: {
972
- position: 'absolute',
973
- left: '50%',
974
- transform: 'translateX(-50%)',
975
- marginBottom: '2px',
976
- bottom: '100%',
977
- whiteSpace: 'nowrap',
978
- color: '#fff',
979
- boxShadow: '0 1px 2px rgba(0,0,0,.1)',
980
- opacity: 0.8,
981
- borderRadius: '3px',
982
- padding: '3px 5px',
983
- pointerEvents: 'none',
984
- }
985
- });
986
- const anchor = createElement('span', {
987
- styles: {
988
- position: 'absolute',
989
- top: '-2px',
990
- left: '-2px',
991
- width: '5px',
992
- height: '5px',
993
- borderRadius: '50%',
994
- pointerEvents: 'auto',
995
- pointer: 'cursor',
996
- },
997
- children: [userTip]
998
- });
999
- child = createElement('span', {
1000
- styles: {
1001
- position: 'absolute',
1002
- },
1003
- children: [
1004
- anchor
1005
- ]
1006
- });
1007
- this.tooltips.append(child);
1008
- return {
1009
- cursor: child,
1010
- anchor,
1011
- userTip
1012
- };
1013
- }
1014
- };
1015
- CollaborateCursor = __decorate([
1016
- Injectable(),
1017
- __param(4, Optional()),
1018
- __metadata("design:paramtypes", [Injector,
1019
- SelectionBridge,
1020
- Renderer,
1021
- Selection,
1022
- CollaborateSelectionAwarenessDelegate])
776
+ class CollaborateSelectionAwarenessDelegate {
777
+ }
778
+ let CollaborateCursor = class CollaborateCursor {
779
+ constructor(injector, nativeSelection, scheduler, selection, awarenessDelegate) {
780
+ this.injector = injector;
781
+ this.nativeSelection = nativeSelection;
782
+ this.scheduler = scheduler;
783
+ this.selection = selection;
784
+ this.awarenessDelegate = awarenessDelegate;
785
+ this.host = createElement('div', {
786
+ styles: {
787
+ position: 'absolute',
788
+ left: 0,
789
+ top: 0,
790
+ width: '100%',
791
+ height: '100%',
792
+ pointerEvents: 'none',
793
+ zIndex: 1
794
+ }
795
+ });
796
+ this.canvasContainer = createElement('div', {
797
+ styles: {
798
+ position: 'absolute',
799
+ left: 0,
800
+ top: 0,
801
+ width: '100%',
802
+ height: '100%',
803
+ overflow: 'hidden'
804
+ }
805
+ });
806
+ this.canvas = createElement('canvas', {
807
+ styles: {
808
+ position: 'absolute',
809
+ opacity: 0.5,
810
+ left: 0,
811
+ top: 0,
812
+ width: '100%',
813
+ height: document.documentElement.clientHeight + 'px',
814
+ pointerEvents: 'none',
815
+ }
816
+ });
817
+ this.context = this.canvas.getContext('2d');
818
+ this.tooltips = createElement('div', {
819
+ styles: {
820
+ position: 'absolute',
821
+ left: 0,
822
+ top: 0,
823
+ width: '100%',
824
+ height: '100%',
825
+ pointerEvents: 'none',
826
+ fontSize: '12px',
827
+ zIndex: 10
828
+ }
829
+ });
830
+ this.onRectsChange = new Subject();
831
+ this.subscription = new Subscription();
832
+ this.currentSelection = [];
833
+ this.container = injector.get(VIEW_CONTAINER);
834
+ this.canvasContainer.append(this.canvas);
835
+ this.host.append(this.canvasContainer, this.tooltips);
836
+ this.container.prepend(this.host);
837
+ this.subscription.add(this.onRectsChange.subscribe(rects => {
838
+ for (const rect of rects) {
839
+ this.context.fillStyle = rect.color;
840
+ this.context.beginPath();
841
+ this.context.rect(rect.left, rect.top, rect.width, rect.height);
842
+ this.context.fill();
843
+ this.context.closePath();
844
+ }
845
+ }), fromEvent(window, 'resize').subscribe(() => {
846
+ this.canvas.style.height = document.documentElement.clientHeight + 'px';
847
+ this.refresh();
848
+ }), this.scheduler.onDocChanged.subscribe(() => {
849
+ this.refresh();
850
+ }));
851
+ }
852
+ refresh() {
853
+ this.draw(this.currentSelection);
854
+ }
855
+ destroy() {
856
+ this.subscription.unsubscribe();
857
+ }
858
+ draw(paths) {
859
+ this.currentSelection = paths;
860
+ const containerRect = this.container.getBoundingClientRect();
861
+ this.canvas.style.top = containerRect.top * -1 + 'px';
862
+ this.canvas.width = this.canvas.offsetWidth;
863
+ this.canvas.height = this.canvas.offsetHeight;
864
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
865
+ const users = [];
866
+ paths.filter(i => {
867
+ return i.paths.anchor.length && i.paths.focus.length;
868
+ }).forEach(item => {
869
+ const anchorPaths = [...item.paths.anchor];
870
+ const focusPaths = [...item.paths.focus];
871
+ const anchorOffset = anchorPaths.pop();
872
+ const anchorSlot = this.selection.findSlotByPaths(anchorPaths);
873
+ const focusOffset = focusPaths.pop();
874
+ const focusSlot = this.selection.findSlotByPaths(focusPaths);
875
+ if (!anchorSlot || !focusSlot) {
876
+ return;
877
+ }
878
+ const { focus, anchor } = this.nativeSelection.getPositionByRange({
879
+ focusOffset,
880
+ anchorOffset,
881
+ focusSlot,
882
+ anchorSlot
883
+ });
884
+ if (!focus || !anchor) {
885
+ return;
886
+ }
887
+ const nativeRange = document.createRange();
888
+ nativeRange.setStart(anchor.node, anchor.offset);
889
+ nativeRange.setEnd(focus.node, focus.offset);
890
+ if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
891
+ nativeRange.setStart(focus.node, focus.offset);
892
+ nativeRange.setEnd(anchor.node, anchor.offset);
893
+ }
894
+ let rects = false;
895
+ if (this.awarenessDelegate) {
896
+ rects = this.awarenessDelegate.getRects({
897
+ focusOffset,
898
+ anchorOffset,
899
+ focusSlot,
900
+ anchorSlot
901
+ }, nativeRange);
902
+ }
903
+ if (!rects) {
904
+ rects = nativeRange.getClientRects();
905
+ }
906
+ const selectionRects = [];
907
+ for (let i = rects.length - 1; i >= 0; i--) {
908
+ const rect = rects[i];
909
+ selectionRects.push({
910
+ id: item.id,
911
+ color: item.color,
912
+ username: item.username,
913
+ left: rect.left - containerRect.left,
914
+ top: rect.top,
915
+ width: rect.width,
916
+ height: rect.height,
917
+ });
918
+ }
919
+ this.onRectsChange.next(selectionRects);
920
+ const cursorRange = nativeRange.cloneRange();
921
+ cursorRange.setStart(focus.node, focus.offset);
922
+ cursorRange.collapse(true);
923
+ const cursorRect = getLayoutRectByRange(cursorRange);
924
+ const rect = {
925
+ id: item.id,
926
+ username: item.username,
927
+ color: item.color,
928
+ left: cursorRect.left - containerRect.left,
929
+ top: cursorRect.top - containerRect.top,
930
+ width: 1,
931
+ height: cursorRect.height
932
+ };
933
+ if (rect.left < 0 || rect.top < 0 || rect.left > containerRect.width) {
934
+ return;
935
+ }
936
+ users.push(rect);
937
+ });
938
+ this.drawUserCursor(users);
939
+ }
940
+ drawUserCursor(rects) {
941
+ for (let i = 0; i < rects.length; i++) {
942
+ const rect = rects[i];
943
+ const { cursor, userTip, anchor } = this.getUserCursor(i);
944
+ Object.assign(cursor.style, {
945
+ left: rect.left + 'px',
946
+ top: rect.top + 'px',
947
+ width: rect.width + 'px',
948
+ height: rect.height + 'px',
949
+ background: rect.color,
950
+ display: 'block'
951
+ });
952
+ anchor.style.background = rect.color;
953
+ userTip.innerText = rect.username;
954
+ userTip.style.background = rect.color;
955
+ }
956
+ for (let i = rects.length; i < this.tooltips.children.length; i++) {
957
+ this.tooltips.removeChild(this.tooltips.children[i]);
958
+ }
959
+ }
960
+ getUserCursor(index) {
961
+ let child = this.tooltips.children[index];
962
+ if (child) {
963
+ const anchor = child.children[0];
964
+ return {
965
+ cursor: child,
966
+ anchor,
967
+ userTip: anchor.children[0]
968
+ };
969
+ }
970
+ const userTip = createElement('span', {
971
+ styles: {
972
+ position: 'absolute',
973
+ left: '50%',
974
+ transform: 'translateX(-50%)',
975
+ marginBottom: '2px',
976
+ bottom: '100%',
977
+ whiteSpace: 'nowrap',
978
+ color: '#fff',
979
+ boxShadow: '0 1px 2px rgba(0,0,0,.1)',
980
+ opacity: 0.8,
981
+ borderRadius: '3px',
982
+ padding: '3px 5px',
983
+ pointerEvents: 'none',
984
+ }
985
+ });
986
+ const anchor = createElement('span', {
987
+ styles: {
988
+ position: 'absolute',
989
+ top: '-2px',
990
+ left: '-2px',
991
+ width: '5px',
992
+ height: '5px',
993
+ borderRadius: '50%',
994
+ pointerEvents: 'auto',
995
+ pointer: 'cursor',
996
+ },
997
+ children: [userTip]
998
+ });
999
+ child = createElement('span', {
1000
+ styles: {
1001
+ position: 'absolute',
1002
+ },
1003
+ children: [
1004
+ anchor
1005
+ ]
1006
+ });
1007
+ this.tooltips.append(child);
1008
+ return {
1009
+ cursor: child,
1010
+ anchor,
1011
+ userTip
1012
+ };
1013
+ }
1014
+ };
1015
+ CollaborateCursor = __decorate([
1016
+ Injectable(),
1017
+ __param(4, Optional()),
1018
+ __metadata("design:paramtypes", [Injector,
1019
+ SelectionBridge,
1020
+ Scheduler,
1021
+ Selection,
1022
+ CollaborateSelectionAwarenessDelegate])
1023
1023
  ], CollaborateCursor);
1024
1024
 
1025
- var DomRenderer_1;
1026
- /**
1027
- * Textbus PC 端浏览器渲染能力实现
1028
- */
1029
- let DomRenderer = DomRenderer_1 = class DomRenderer {
1030
- constructor() {
1031
- this.isSVG = new RegExp(`^(${[
1032
- // 'a',
1033
- 'animate',
1034
- 'animateMotion',
1035
- 'animateTransform',
1036
- 'circle',
1037
- 'clipPath',
1038
- 'defs',
1039
- 'desc',
1040
- 'ellipse',
1041
- 'feBlend',
1042
- 'feColorMatrix',
1043
- 'feComponentTransfer',
1044
- 'feComposite',
1045
- 'feConvolveMatrix',
1046
- 'feDiffuseLighting',
1047
- 'feDisplacementMap',
1048
- 'feDistantLight',
1049
- 'feDropShadow',
1050
- 'feFlood',
1051
- 'feFuncA',
1052
- 'feFuncB',
1053
- 'feFuncG',
1054
- 'feFuncR',
1055
- 'feGaussianBlur',
1056
- 'feImage',
1057
- 'feMerge',
1058
- 'feMergeNode',
1059
- 'feMorphology',
1060
- 'feOffset',
1061
- 'fePointLight',
1062
- 'feSpecularLighting',
1063
- 'feSpotLight',
1064
- 'feTile',
1065
- 'feTurbulence',
1066
- 'filter',
1067
- 'foreignObject',
1068
- 'g',
1069
- 'image',
1070
- 'line',
1071
- 'linearGradient',
1072
- 'marker',
1073
- 'mask',
1074
- 'metadata',
1075
- 'mpath',
1076
- 'path',
1077
- 'pattern',
1078
- 'polygon',
1079
- 'polyline',
1080
- 'radialGradient',
1081
- 'rect',
1082
- // 'script',
1083
- 'set',
1084
- 'stop',
1085
- // 'style',
1086
- 'svg',
1087
- 'switch',
1088
- 'symbol',
1089
- 'text',
1090
- 'textPath',
1091
- 'title',
1092
- 'tspan',
1093
- 'use',
1094
- 'view'
1095
- ].join('|')})$`, 'i');
1096
- this.xlinkNameSpace = 'http://www.w3.org/1999/xlink';
1097
- this.possibleXlinkNames = {
1098
- xlinkActuate: 'xlink:actuate',
1099
- xlinkactuate: 'xlink:actuate',
1100
- 'xlink:actuate': 'xlink:actuate',
1101
- xlinkArcrole: 'xlink:arcrole',
1102
- xlinkarcrole: 'xlink:arcrole',
1103
- 'xlink:arcrole': 'xlink:arcrole',
1104
- xlinkHref: 'xlink:href',
1105
- xlinkhref: 'xlink:href',
1106
- 'xlink:href': 'xlink:href',
1107
- xlinkRole: 'xlink:role',
1108
- xlinkrole: 'xlink:role',
1109
- 'xlink:role': 'xlink:role',
1110
- xlinkShow: 'xlink:show',
1111
- xlinkshow: 'xlink:show',
1112
- 'xlink:show': 'xlink:show',
1113
- xlinkTitle: 'xlink:title',
1114
- xlinktitle: 'xlink:title',
1115
- 'xlink:title': 'xlink:title',
1116
- xlinkType: 'xlink:type',
1117
- xlinktype: 'xlink:type',
1118
- 'xlink:type': 'xlink:type'
1119
- };
1120
- this.formElement = {
1121
- input: ['disabled', 'readonly', 'value'],
1122
- select: ['disabled', 'readonly'],
1123
- option: ['disabled', 'selected', 'value'],
1124
- button: ['disabled'],
1125
- video: ['controls', 'autoplay', 'loop', 'muted'],
1126
- audio: ['controls', 'autoplay', 'loop', 'muted'],
1127
- };
1128
- }
1129
- listen(node, type, callback) {
1130
- node.addEventListener(type, callback);
1131
- }
1132
- unListen(node, type, callback) {
1133
- node.removeEventListener(type, callback);
1134
- }
1135
- createTextNode(textContent) {
1136
- return document.createTextNode(DomRenderer_1.replaceEmpty(textContent, '\u00a0'));
1137
- }
1138
- createElement(name) {
1139
- if (this.isSVG.test(name)) {
1140
- return document.createElementNS('http://www.w3.org/2000/svg', name);
1141
- }
1142
- return document.createElement(name);
1143
- }
1144
- appendChild(parent, newChild) {
1145
- parent.appendChild(newChild);
1146
- }
1147
- remove(node) {
1148
- var _a;
1149
- (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
1150
- }
1151
- insertBefore(newNode, ref) {
1152
- ref.parentNode.insertBefore(newNode, ref);
1153
- }
1154
- getChildByIndex(parent, index) {
1155
- return parent.childNodes[index] || null;
1156
- }
1157
- addClass(target, name) {
1158
- target.classList.add(name);
1159
- }
1160
- removeClass(target, name) {
1161
- target.classList.remove(name);
1162
- }
1163
- setStyle(target, key, value) {
1164
- target.style[key] = value !== null && value !== void 0 ? value : '';
1165
- }
1166
- syncTextContent(target, content) {
1167
- if (target.textContent !== content) {
1168
- target.textContent = content;
1169
- }
1170
- }
1171
- removeStyle(target, key) {
1172
- target.style[key] = '';
1173
- }
1174
- setAttribute(target, key, value) {
1175
- if (this.possibleXlinkNames[key]) {
1176
- this.setXlinkAttribute(target, this.possibleXlinkNames[key], value);
1177
- return;
1178
- }
1179
- target.setAttribute(key, value);
1180
- const propNames = this.formElement[target.tagName.toLowerCase()];
1181
- if (propNames && propNames.includes(key)) {
1182
- target[key] = Boolean(value);
1183
- }
1184
- }
1185
- removeAttribute(target, key) {
1186
- if (this.possibleXlinkNames[key]) {
1187
- this.removeXlinkAttribute(target, this.possibleXlinkNames[key]);
1188
- }
1189
- target.removeAttribute(key);
1190
- const propNames = this.formElement[target.tagName.toLowerCase()];
1191
- if (propNames && propNames.includes(key)) {
1192
- target[key] = false;
1193
- }
1194
- }
1195
- setXlinkAttribute(target, key, value) {
1196
- target.setAttributeNS(this.xlinkNameSpace, key, value);
1197
- }
1198
- removeXlinkAttribute(target, key) {
1199
- target.removeAttributeNS(this.xlinkNameSpace, key);
1200
- }
1201
- replace(newChild, oldChild) {
1202
- oldChild.parentNode.replaceChild(newChild, oldChild);
1203
- }
1204
- copy() {
1205
- document.execCommand('copy');
1206
- }
1207
- static replaceEmpty(s, target) {
1208
- return s.replace(/\s\s+/g, str => {
1209
- return ' ' + Array.from({
1210
- length: str.length - 1
1211
- }).fill(target).join('');
1212
- }).replace(/^\s|\s$/g, target);
1213
- }
1214
- };
1215
- DomRenderer = DomRenderer_1 = __decorate([
1216
- Injectable()
1025
+ var DomRenderer_1;
1026
+ /**
1027
+ * Textbus PC 端浏览器渲染能力实现
1028
+ */
1029
+ let DomRenderer = DomRenderer_1 = class DomRenderer {
1030
+ constructor() {
1031
+ this.isSVG = new RegExp(`^(${[
1032
+ // 'a',
1033
+ 'animate',
1034
+ 'animateMotion',
1035
+ 'animateTransform',
1036
+ 'circle',
1037
+ 'clipPath',
1038
+ 'defs',
1039
+ 'desc',
1040
+ 'ellipse',
1041
+ 'feBlend',
1042
+ 'feColorMatrix',
1043
+ 'feComponentTransfer',
1044
+ 'feComposite',
1045
+ 'feConvolveMatrix',
1046
+ 'feDiffuseLighting',
1047
+ 'feDisplacementMap',
1048
+ 'feDistantLight',
1049
+ 'feDropShadow',
1050
+ 'feFlood',
1051
+ 'feFuncA',
1052
+ 'feFuncB',
1053
+ 'feFuncG',
1054
+ 'feFuncR',
1055
+ 'feGaussianBlur',
1056
+ 'feImage',
1057
+ 'feMerge',
1058
+ 'feMergeNode',
1059
+ 'feMorphology',
1060
+ 'feOffset',
1061
+ 'fePointLight',
1062
+ 'feSpecularLighting',
1063
+ 'feSpotLight',
1064
+ 'feTile',
1065
+ 'feTurbulence',
1066
+ 'filter',
1067
+ 'foreignObject',
1068
+ 'g',
1069
+ 'image',
1070
+ 'line',
1071
+ 'linearGradient',
1072
+ 'marker',
1073
+ 'mask',
1074
+ 'metadata',
1075
+ 'mpath',
1076
+ 'path',
1077
+ 'pattern',
1078
+ 'polygon',
1079
+ 'polyline',
1080
+ 'radialGradient',
1081
+ 'rect',
1082
+ // 'script',
1083
+ 'set',
1084
+ 'stop',
1085
+ // 'style',
1086
+ 'svg',
1087
+ 'switch',
1088
+ 'symbol',
1089
+ 'text',
1090
+ 'textPath',
1091
+ 'title',
1092
+ 'tspan',
1093
+ 'use',
1094
+ 'view'
1095
+ ].join('|')})$`, 'i');
1096
+ this.xlinkNameSpace = 'http://www.w3.org/1999/xlink';
1097
+ this.possibleXlinkNames = {
1098
+ xlinkActuate: 'xlink:actuate',
1099
+ xlinkactuate: 'xlink:actuate',
1100
+ 'xlink:actuate': 'xlink:actuate',
1101
+ xlinkArcrole: 'xlink:arcrole',
1102
+ xlinkarcrole: 'xlink:arcrole',
1103
+ 'xlink:arcrole': 'xlink:arcrole',
1104
+ xlinkHref: 'xlink:href',
1105
+ xlinkhref: 'xlink:href',
1106
+ 'xlink:href': 'xlink:href',
1107
+ xlinkRole: 'xlink:role',
1108
+ xlinkrole: 'xlink:role',
1109
+ 'xlink:role': 'xlink:role',
1110
+ xlinkShow: 'xlink:show',
1111
+ xlinkshow: 'xlink:show',
1112
+ 'xlink:show': 'xlink:show',
1113
+ xlinkTitle: 'xlink:title',
1114
+ xlinktitle: 'xlink:title',
1115
+ 'xlink:title': 'xlink:title',
1116
+ xlinkType: 'xlink:type',
1117
+ xlinktype: 'xlink:type',
1118
+ 'xlink:type': 'xlink:type'
1119
+ };
1120
+ this.formElement = {
1121
+ input: ['disabled', 'readonly', 'value'],
1122
+ select: ['disabled', 'readonly'],
1123
+ option: ['disabled', 'selected', 'value'],
1124
+ button: ['disabled'],
1125
+ video: ['controls', 'autoplay', 'loop', 'muted'],
1126
+ audio: ['controls', 'autoplay', 'loop', 'muted'],
1127
+ };
1128
+ }
1129
+ listen(node, type, callback) {
1130
+ node.addEventListener(type, callback);
1131
+ }
1132
+ unListen(node, type, callback) {
1133
+ node.removeEventListener(type, callback);
1134
+ }
1135
+ createTextNode(textContent) {
1136
+ return document.createTextNode(DomRenderer_1.replaceEmpty(textContent, '\u00a0'));
1137
+ }
1138
+ createElement(name) {
1139
+ if (this.isSVG.test(name)) {
1140
+ return document.createElementNS('http://www.w3.org/2000/svg', name);
1141
+ }
1142
+ return document.createElement(name);
1143
+ }
1144
+ appendChild(parent, newChild) {
1145
+ parent.appendChild(newChild);
1146
+ }
1147
+ remove(node) {
1148
+ var _a;
1149
+ (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
1150
+ }
1151
+ insertBefore(newNode, ref) {
1152
+ ref.parentNode.insertBefore(newNode, ref);
1153
+ }
1154
+ getChildByIndex(parent, index) {
1155
+ return parent.childNodes[index] || null;
1156
+ }
1157
+ addClass(target, name) {
1158
+ target.classList.add(name);
1159
+ }
1160
+ removeClass(target, name) {
1161
+ target.classList.remove(name);
1162
+ }
1163
+ setStyle(target, key, value) {
1164
+ target.style[key] = value !== null && value !== void 0 ? value : '';
1165
+ }
1166
+ syncTextContent(target, content) {
1167
+ if (target.textContent !== content) {
1168
+ target.textContent = content;
1169
+ }
1170
+ }
1171
+ removeStyle(target, key) {
1172
+ target.style[key] = '';
1173
+ }
1174
+ setAttribute(target, key, value) {
1175
+ if (this.possibleXlinkNames[key]) {
1176
+ this.setXlinkAttribute(target, this.possibleXlinkNames[key], value);
1177
+ return;
1178
+ }
1179
+ target.setAttribute(key, value);
1180
+ const propNames = this.formElement[target.tagName.toLowerCase()];
1181
+ if (propNames && propNames.includes(key)) {
1182
+ target[key] = Boolean(value);
1183
+ }
1184
+ }
1185
+ removeAttribute(target, key) {
1186
+ if (this.possibleXlinkNames[key]) {
1187
+ this.removeXlinkAttribute(target, this.possibleXlinkNames[key]);
1188
+ }
1189
+ target.removeAttribute(key);
1190
+ const propNames = this.formElement[target.tagName.toLowerCase()];
1191
+ if (propNames && propNames.includes(key)) {
1192
+ target[key] = false;
1193
+ }
1194
+ }
1195
+ setXlinkAttribute(target, key, value) {
1196
+ target.setAttributeNS(this.xlinkNameSpace, key, value);
1197
+ }
1198
+ removeXlinkAttribute(target, key) {
1199
+ target.removeAttributeNS(this.xlinkNameSpace, key);
1200
+ }
1201
+ replace(newChild, oldChild) {
1202
+ oldChild.parentNode.replaceChild(newChild, oldChild);
1203
+ }
1204
+ copy() {
1205
+ document.execCommand('copy');
1206
+ }
1207
+ static replaceEmpty(s, target) {
1208
+ return s.replace(/\s\s+/g, str => {
1209
+ return ' ' + Array.from({
1210
+ length: str.length - 1
1211
+ }).fill(target).join('');
1212
+ }).replace(/^\s|\s$/g, target);
1213
+ }
1214
+ };
1215
+ DomRenderer = DomRenderer_1 = __decorate([
1216
+ Injectable()
1217
1217
  ], DomRenderer);
1218
1218
 
1219
- var Parser_1;
1220
- let Parser = Parser_1 = class Parser {
1221
- static parseHTML(html) {
1222
- return new DOMParser().parseFromString(html, 'text/html').body;
1223
- }
1224
- constructor(options, injector) {
1225
- var _a;
1226
- this.options = options;
1227
- this.injector = injector;
1228
- const componentLoaders = [
1229
- ...(options.componentLoaders || [])
1230
- ];
1231
- const formatLoaders = [
1232
- ...(options.formatLoaders || [])
1233
- ];
1234
- const attributeLoaders = [
1235
- ...(options.attributeLoaders || [])
1236
- ];
1237
- (_a = options.imports) === null || _a === void 0 ? void 0 : _a.forEach(i => {
1238
- componentLoaders.push(...(i.componentLoaders || []));
1239
- formatLoaders.push(...(i.formatLoaders || []));
1240
- });
1241
- this.componentLoaders = componentLoaders;
1242
- this.formatLoaders = formatLoaders;
1243
- this.attributeLoaders = attributeLoaders;
1244
- }
1245
- parseDoc(html, rootComponentLoader) {
1246
- const element = Parser_1.parseHTML(html);
1247
- return rootComponentLoader.read(element, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
1248
- return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
1249
- });
1250
- }
1251
- parse(html, rootSlot) {
1252
- const element = Parser_1.parseHTML(html);
1253
- return this.readFormats(element, rootSlot);
1254
- }
1255
- readComponent(el, slot) {
1256
- if (el.nodeType === Node.ELEMENT_NODE) {
1257
- if (el.tagName === 'BR') {
1258
- slot.insert('\n');
1259
- return;
1260
- }
1261
- for (const t of this.componentLoaders) {
1262
- if (t.match(el)) {
1263
- const result = t.read(el, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
1264
- return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
1265
- });
1266
- if (result instanceof Slot) {
1267
- result.toDelta().forEach(i => slot.insert(i.insert, i.formats));
1268
- return;
1269
- }
1270
- slot.insert(result);
1271
- return;
1272
- }
1273
- }
1274
- this.readFormats(el, slot);
1275
- }
1276
- else if (el.nodeType === Node.TEXT_NODE) {
1277
- const textContent = el.textContent;
1278
- if (/^\s*[\r\n]+\s*$/.test(textContent)) {
1279
- return;
1280
- }
1281
- slot.insert(textContent);
1282
- }
1283
- }
1284
- readFormats(el, slot) {
1285
- const formats = this.formatLoaders.filter(f => {
1286
- return f.match(el);
1287
- }).map(f => {
1288
- return f.read(el);
1289
- });
1290
- const startIndex = slot.index;
1291
- Array.from(el.childNodes).forEach(child => {
1292
- this.readComponent(child, slot);
1293
- });
1294
- const endIndex = slot.index;
1295
- this.applyFormats(slot, formats.map(i => {
1296
- return {
1297
- formatter: i.formatter,
1298
- value: i.value,
1299
- startIndex,
1300
- endIndex
1301
- };
1302
- }));
1303
- slot.retain(endIndex);
1304
- return slot;
1305
- }
1306
- readSlot(childSlot, slotRootElement, slotContentElement) {
1307
- this.attributeLoaders.filter(a => {
1308
- return a.match(slotRootElement);
1309
- }).forEach(a => {
1310
- const r = a.read(slotRootElement);
1311
- childSlot.setAttribute(r.attribute, r.value);
1312
- });
1313
- this.readFormats(slotContentElement, childSlot);
1314
- return childSlot;
1315
- }
1316
- applyFormats(slot, formatItems) {
1317
- slot.background(() => {
1318
- formatItems.forEach(i => {
1319
- slot.retain(i.startIndex);
1320
- slot.retain(i.endIndex - i.startIndex, i.formatter, i.value);
1321
- });
1322
- });
1323
- }
1324
- };
1325
- Parser = Parser_1 = __decorate([
1326
- Injectable(),
1327
- __param(0, Inject(EDITOR_OPTIONS)),
1328
- __metadata("design:paramtypes", [Object, Injector])
1219
+ var Parser_1;
1220
+ let Parser = Parser_1 = class Parser {
1221
+ static parseHTML(html) {
1222
+ return new DOMParser().parseFromString(html, 'text/html').body;
1223
+ }
1224
+ constructor(options, injector) {
1225
+ var _a;
1226
+ this.options = options;
1227
+ this.injector = injector;
1228
+ const componentLoaders = [
1229
+ ...(options.componentLoaders || [])
1230
+ ];
1231
+ const formatLoaders = [
1232
+ ...(options.formatLoaders || [])
1233
+ ];
1234
+ const attributeLoaders = [
1235
+ ...(options.attributeLoaders || [])
1236
+ ];
1237
+ (_a = options.imports) === null || _a === void 0 ? void 0 : _a.forEach(i => {
1238
+ componentLoaders.push(...(i.componentLoaders || []));
1239
+ formatLoaders.push(...(i.formatLoaders || []));
1240
+ });
1241
+ this.componentLoaders = componentLoaders;
1242
+ this.formatLoaders = formatLoaders;
1243
+ this.attributeLoaders = attributeLoaders;
1244
+ }
1245
+ parseDoc(html, rootComponentLoader) {
1246
+ const element = Parser_1.parseHTML(html);
1247
+ return rootComponentLoader.read(element, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
1248
+ return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
1249
+ });
1250
+ }
1251
+ parse(html, rootSlot) {
1252
+ const element = Parser_1.parseHTML(html);
1253
+ return this.readFormats(element, rootSlot);
1254
+ }
1255
+ readComponent(el, slot) {
1256
+ if (el.nodeType === Node.ELEMENT_NODE) {
1257
+ if (el.tagName === 'BR') {
1258
+ slot.insert('\n');
1259
+ return;
1260
+ }
1261
+ for (const t of this.componentLoaders) {
1262
+ if (t.match(el)) {
1263
+ const result = t.read(el, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
1264
+ return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
1265
+ });
1266
+ if (result instanceof Slot) {
1267
+ result.toDelta().forEach(i => slot.insert(i.insert, i.formats));
1268
+ return;
1269
+ }
1270
+ slot.insert(result);
1271
+ return;
1272
+ }
1273
+ }
1274
+ this.readFormats(el, slot);
1275
+ }
1276
+ else if (el.nodeType === Node.TEXT_NODE) {
1277
+ const textContent = el.textContent;
1278
+ if (/^\s*[\r\n]+\s*$/.test(textContent)) {
1279
+ return;
1280
+ }
1281
+ slot.insert(textContent);
1282
+ }
1283
+ }
1284
+ readFormats(el, slot) {
1285
+ const formats = this.formatLoaders.filter(f => {
1286
+ return f.match(el);
1287
+ }).map(f => {
1288
+ return f.read(el);
1289
+ });
1290
+ const startIndex = slot.index;
1291
+ Array.from(el.childNodes).forEach(child => {
1292
+ this.readComponent(child, slot);
1293
+ });
1294
+ const endIndex = slot.index;
1295
+ this.applyFormats(slot, formats.map(i => {
1296
+ return {
1297
+ formatter: i.formatter,
1298
+ value: i.value,
1299
+ startIndex,
1300
+ endIndex
1301
+ };
1302
+ }));
1303
+ slot.retain(endIndex);
1304
+ return slot;
1305
+ }
1306
+ readSlot(childSlot, slotRootElement, slotContentElement) {
1307
+ this.attributeLoaders.filter(a => {
1308
+ return a.match(slotRootElement);
1309
+ }).forEach(a => {
1310
+ const r = a.read(slotRootElement);
1311
+ childSlot.setAttribute(r.attribute, r.value);
1312
+ });
1313
+ this.readFormats(slotContentElement, childSlot);
1314
+ return childSlot;
1315
+ }
1316
+ applyFormats(slot, formatItems) {
1317
+ slot.background(() => {
1318
+ formatItems.forEach(i => {
1319
+ slot.retain(i.startIndex);
1320
+ slot.retain(i.endIndex - i.startIndex, i.formatter, i.value);
1321
+ });
1322
+ });
1323
+ }
1324
+ };
1325
+ Parser = Parser_1 = __decorate([
1326
+ Injectable(),
1327
+ __param(0, Inject(EDITOR_OPTIONS)),
1328
+ __metadata("design:paramtypes", [Object, Injector])
1329
1329
  ], Parser);
1330
1330
 
1331
- const iframeHTML = `
1332
- <!DOCTYPE html>
1333
- <html>
1334
- <head>
1335
- <meta charset="UTF-8">
1336
- <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
1337
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
1338
- <title>Textbus</title>
1339
- <style>
1340
- html {position: fixed; left:0; overflow: hidden}
1341
- html, body{height: 100%;width:100%}
1342
- body{margin:0; overflow: hidden}
1343
- textarea{width: 2000px;height: 100%;opacity: 0; padding: 0; outline: none; border: none; position: absolute; left:0; top:0;}
1344
- </style>
1345
- </head>
1346
- <body>
1347
- </body>
1348
- </html>
1349
- `;
1350
- class ExperimentalCaret {
1351
- get rect() {
1352
- return this.caret.getBoundingClientRect();
1353
- }
1354
- set display(v) {
1355
- this._display = v;
1356
- this.caret.style.visibility = v ? 'visible' : 'hidden';
1357
- }
1358
- get display() {
1359
- return this._display;
1360
- }
1361
- constructor(scheduler, editorMask) {
1362
- this.scheduler = scheduler;
1363
- this.editorMask = editorMask;
1364
- this.compositionState = null;
1365
- this.timer = null;
1366
- this.oldPosition = null;
1367
- this._display = true;
1368
- this.flashing = true;
1369
- this.subs = [];
1370
- this.positionChangeEvent = new Subject();
1371
- this.styleChangeEvent = new Subject();
1372
- this.oldRange = null;
1373
- this.isFixed = false;
1374
- this.compositionElement = createElement('span', {
1375
- styles: {
1376
- textDecoration: 'underline'
1377
- }
1378
- });
1379
- this.onPositionChange = this.positionChangeEvent.pipe(distinctUntilChanged());
1380
- this.onStyleChange = this.styleChangeEvent.asObservable();
1381
- this.elementRef = createElement('div', {
1382
- styles: {
1383
- position: 'absolute',
1384
- width: '2px',
1385
- pointerEvents: 'none'
1386
- },
1387
- children: [
1388
- this.caret = createElement('span', {
1389
- styles: {
1390
- width: '100%',
1391
- height: '100%',
1392
- position: 'absolute',
1393
- left: 0,
1394
- top: 0
1395
- }
1396
- })
1397
- ]
1398
- });
1399
- this.subs.push(fromEvent(document, 'mousedown').subscribe(() => {
1400
- this.flashing = false;
1401
- }), fromEvent(document, 'mouseup').subscribe(() => {
1402
- this.flashing = true;
1403
- }));
1404
- this.editorMask.appendChild(this.elementRef);
1405
- }
1406
- refresh(isFixedCaret = false) {
1407
- this.isFixed = isFixedCaret;
1408
- if (this.oldRange) {
1409
- this.show(this.oldRange, false);
1410
- }
1411
- this.isFixed = false;
1412
- }
1413
- show(range, restart) {
1414
- const oldRect = this.elementRef.getBoundingClientRect();
1415
- this.oldPosition = {
1416
- top: oldRect.top,
1417
- left: oldRect.left,
1418
- height: oldRect.height
1419
- };
1420
- this.oldRange = range;
1421
- if (restart || this.scheduler.lastChangesHasLocalUpdate) {
1422
- clearTimeout(this.timer);
1423
- }
1424
- this.updateCursorPosition(range);
1425
- if (range.collapsed) {
1426
- if (restart || this.scheduler.lastChangesHasLocalUpdate) {
1427
- this.display = true;
1428
- const toggleShowHide = () => {
1429
- this.display = !this.display || !this.flashing;
1430
- this.timer = setTimeout(toggleShowHide, 400);
1431
- };
1432
- clearTimeout(this.timer);
1433
- this.timer = setTimeout(toggleShowHide, 400);
1434
- }
1435
- }
1436
- else {
1437
- this.display = false;
1438
- clearTimeout(this.timer);
1439
- }
1440
- }
1441
- hide() {
1442
- this.display = false;
1443
- clearTimeout(this.timer);
1444
- this.positionChangeEvent.next(null);
1445
- }
1446
- destroy() {
1447
- clearTimeout(this.timer);
1448
- this.subs.forEach(i => i.unsubscribe());
1449
- }
1450
- correctScrollTop(scroller) {
1451
- this.subs.forEach(i => i.unsubscribe());
1452
- this.subs = [];
1453
- const scheduler = this.scheduler;
1454
- let docIsChanged = true;
1455
- function limitPosition(position) {
1456
- const { top, bottom } = scroller.getLimit();
1457
- const caretTop = position.top;
1458
- if (caretTop + position.height > bottom) {
1459
- const offset = caretTop - bottom + position.height;
1460
- scroller.setOffset(offset);
1461
- }
1462
- else if (position.top < top) {
1463
- scroller.setOffset(-(top - position.top));
1464
- }
1465
- }
1466
- let isPressed = false;
1467
- this.subs.push(scroller.onScroll.subscribe(() => {
1468
- if (this.oldPosition) {
1469
- const rect = this.rect;
1470
- this.oldPosition.top = rect.top;
1471
- this.oldPosition.left = rect.left;
1472
- this.oldPosition.height = rect.height;
1473
- }
1474
- }), fromEvent(document, 'mousedown', true).subscribe(() => {
1475
- isPressed = true;
1476
- }), fromEvent(document, 'mouseup', true).subscribe(() => {
1477
- isPressed = false;
1478
- }), scheduler.onDocChange.subscribe(() => {
1479
- docIsChanged = true;
1480
- }), this.onPositionChange.subscribe(position => {
1481
- if (position) {
1482
- if (docIsChanged) {
1483
- if (scheduler.lastChangesHasLocalUpdate) {
1484
- limitPosition(position);
1485
- }
1486
- else if (this.oldPosition) {
1487
- const offset = Math.floor(position.top - this.oldPosition.top);
1488
- scroller.setOffset(offset);
1489
- }
1490
- }
1491
- else if (!isPressed) {
1492
- if (this.isFixed && this.oldPosition) {
1493
- const offset = Math.floor(position.top - this.oldPosition.top);
1494
- scroller.setOffset(offset);
1495
- }
1496
- else {
1497
- limitPosition(position);
1498
- }
1499
- }
1500
- }
1501
- docIsChanged = false;
1502
- }));
1503
- }
1504
- updateCursorPosition(nativeRange) {
1505
- const startContainer = nativeRange.startContainer;
1506
- const node = (startContainer.nodeType === Node.ELEMENT_NODE ? startContainer : startContainer.parentNode);
1507
- if ((node === null || node === void 0 ? void 0 : node.nodeType) !== Node.ELEMENT_NODE) {
1508
- this.positionChangeEvent.next(null);
1509
- return;
1510
- }
1511
- if (this.compositionState) {
1512
- const compositionElement = this.compositionElement;
1513
- compositionElement.innerText = this.compositionState.data;
1514
- nativeRange = nativeRange.cloneRange();
1515
- nativeRange.insertNode(compositionElement);
1516
- nativeRange.selectNodeContents(compositionElement);
1517
- nativeRange.collapse();
1518
- }
1519
- const rect = getLayoutRectByRange(nativeRange);
1520
- const { fontSize, lineHeight, color } = getComputedStyle(node);
1521
- let height;
1522
- if (isNaN(+lineHeight)) {
1523
- const f = parseFloat(lineHeight);
1524
- if (isNaN(f)) {
1525
- height = parseFloat(fontSize);
1526
- }
1527
- else {
1528
- height = f;
1529
- }
1530
- }
1531
- else {
1532
- height = parseFloat(fontSize) * parseFloat(lineHeight);
1533
- }
1534
- const boxHeight = Math.floor(Math.max(height, rect.height));
1535
- // const boxHeight = Math.floor(height)
1536
- let rectTop = rect.top;
1537
- if (rect.height < height) {
1538
- rectTop -= (height - rect.height) / 2;
1539
- }
1540
- rectTop = Math.floor(rectTop);
1541
- const containerRect = this.editorMask.getBoundingClientRect();
1542
- const top = Math.floor(rectTop - containerRect.top);
1543
- const left = Math.floor(rect.left - containerRect.left);
1544
- Object.assign(this.elementRef.style, {
1545
- left: left + 'px',
1546
- top: top + 'px',
1547
- height: boxHeight + 'px',
1548
- lineHeight: boxHeight + 'px',
1549
- fontSize
1550
- });
1551
- this.caret.style.backgroundColor = color;
1552
- this.styleChangeEvent.next({
1553
- height: boxHeight + 'px',
1554
- lineHeight: boxHeight + 'px',
1555
- fontSize
1556
- });
1557
- this.positionChangeEvent.next({
1558
- left,
1559
- top: rectTop,
1560
- height: boxHeight
1561
- });
1562
- }
1563
- }
1564
- /**
1565
- * Textbus PC 端输入实现
1566
- */
1567
- let MagicInput = class MagicInput extends Input {
1568
- set disabled(b) {
1569
- this._disabled = b;
1570
- if (b && this.textarea) {
1571
- this.textarea.disabled = b;
1572
- }
1573
- }
1574
- get disabled() {
1575
- return this._disabled;
1576
- }
1577
- constructor(parser, keyboard, commander, selection, controller, scheduler, injector) {
1578
- super();
1579
- this.parser = parser;
1580
- this.keyboard = keyboard;
1581
- this.commander = commander;
1582
- this.selection = selection;
1583
- this.controller = controller;
1584
- this.scheduler = scheduler;
1585
- this.injector = injector;
1586
- this.composition = false;
1587
- this.caret = new ExperimentalCaret(this.scheduler, this.injector.get(VIEW_MASK));
1588
- this.isSafari = isSafari();
1589
- this.isMac = isMac();
1590
- this.isWindows = isWindows();
1591
- this._disabled = false;
1592
- this.container = this.createEditableFrame();
1593
- this.subscription = new Subscription();
1594
- this.textarea = null;
1595
- this.isFocus = false;
1596
- this.nativeFocus = false;
1597
- this.isSougouPinYin = false; // 有 bug 版本搜狗拼音
1598
- this.onReady = new Promise(resolve => {
1599
- this.subscription.add(fromEvent(this.container, 'load').subscribe(() => {
1600
- const doc = this.container.contentDocument;
1601
- doc.open();
1602
- doc.write(iframeHTML);
1603
- doc.close();
1604
- this.doc = doc;
1605
- this.init();
1606
- resolve();
1607
- }), controller.onReadonlyStateChange.subscribe(() => {
1608
- if (controller.readonly) {
1609
- this.blur();
1610
- }
1611
- }));
1612
- });
1613
- this.caret.elementRef.append(this.container);
1614
- }
1615
- focus(range, restart) {
1616
- var _a;
1617
- if (!this.disabled) {
1618
- this.caret.show(range, restart);
1619
- }
1620
- if (this.controller.readonly) {
1621
- return;
1622
- }
1623
- if (!this.isFocus) {
1624
- (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1625
- setTimeout(() => {
1626
- var _a, _b, _c;
1627
- if (!this.nativeFocus && this.isFocus) {
1628
- this.subscription.unsubscribe();
1629
- (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1630
- this.subscription = new Subscription();
1631
- this.init();
1632
- (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1633
- }
1634
- });
1635
- }
1636
- this.isFocus = true;
1637
- }
1638
- blur() {
1639
- var _a;
1640
- this.caret.hide();
1641
- (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.blur();
1642
- this.isFocus = false;
1643
- }
1644
- destroy() {
1645
- this.caret.destroy();
1646
- this.subscription.unsubscribe();
1647
- }
1648
- init() {
1649
- const doc = this.doc;
1650
- const contentBody = doc.body;
1651
- const textarea = doc.createElement('textarea');
1652
- textarea.disabled = this.disabled;
1653
- contentBody.appendChild(textarea);
1654
- this.textarea = textarea;
1655
- this.subscription.add(fromEvent(textarea, 'blur').subscribe(() => {
1656
- this.isFocus = false;
1657
- this.nativeFocus = false;
1658
- this.caret.hide();
1659
- }), fromEvent(textarea, 'focus').subscribe(() => {
1660
- this.nativeFocus = true;
1661
- }), this.caret.onStyleChange.subscribe(style => {
1662
- Object.assign(textarea.style, style);
1663
- }));
1664
- this.handleInput(textarea);
1665
- this.handleShortcut(textarea);
1666
- this.handleDefaultActions(textarea);
1667
- }
1668
- handleDefaultActions(textarea) {
1669
- this.subscription.add(fromEvent(document, 'copy').subscribe(ev => {
1670
- const selection = this.selection;
1671
- if (!selection.isSelected) {
1672
- return;
1673
- }
1674
- if (selection.startSlot === selection.endSlot && selection.endOffset - selection.startOffset === 1) {
1675
- const content = selection.startSlot.getContentAtIndex(selection.startOffset);
1676
- if (typeof content === 'object') {
1677
- const clipboardData = ev.clipboardData;
1678
- const nativeSelection = document.getSelection();
1679
- const range = nativeSelection.getRangeAt(0);
1680
- const div = document.createElement('div');
1681
- const fragment = range.cloneContents();
1682
- div.append(fragment);
1683
- clipboardData.setData('text/html', div.innerHTML);
1684
- clipboardData.setData('text', div.innerText);
1685
- ev.preventDefault();
1686
- }
1687
- }
1688
- }), fromEvent(textarea, 'paste').subscribe(ev => {
1689
- const text = ev.clipboardData.getData('Text');
1690
- const files = Array.from(ev.clipboardData.files);
1691
- if (files.length) {
1692
- Promise.all(files.filter(i => {
1693
- return /image/i.test(i.type);
1694
- }).map(item => {
1695
- const reader = new FileReader();
1696
- return new Promise(resolve => {
1697
- reader.onload = (event) => {
1698
- resolve(event.target.result);
1699
- };
1700
- reader.readAsDataURL(item);
1701
- });
1702
- })).then(urls => {
1703
- const html = urls.map(i => {
1704
- return `<img src=${i}>`;
1705
- }).join('');
1706
- this.handlePaste(html, text);
1707
- });
1708
- ev.preventDefault();
1709
- return;
1710
- }
1711
- const div = this.doc.createElement('div');
1712
- div.style.cssText = 'width:1px; height:10px; overflow: hidden; position: fixed; left: 50%; top: 50%; opacity:0';
1713
- div.contentEditable = 'true';
1714
- this.doc.body.appendChild(div);
1715
- div.focus();
1716
- setTimeout(() => {
1717
- const html = div.innerHTML;
1718
- this.handlePaste(html, text);
1719
- this.doc.body.removeChild(div);
1720
- });
1721
- }));
1722
- }
1723
- handlePaste(html, text) {
1724
- const slot = this.parser.parse(html, new Slot([
1725
- ContentType.BlockComponent,
1726
- ContentType.InlineComponent,
1727
- ContentType.Text
1728
- ]));
1729
- this.commander.paste(slot, text);
1730
- }
1731
- handleShortcut(textarea) {
1732
- let isWriting = false;
1733
- let isIgnore = false;
1734
- this.subscription.add(fromEvent(textarea, 'compositionstart').subscribe(() => {
1735
- isWriting = true;
1736
- }), fromEvent(textarea, 'compositionend').subscribe(() => {
1737
- isWriting = false;
1738
- }), fromEvent(textarea, 'beforeinput').subscribe(ev => {
1739
- if (this.isSafari) {
1740
- if (ev.inputType === 'insertFromComposition') {
1741
- isIgnore = true;
1742
- }
1743
- }
1744
- }), fromEvent(textarea, 'keydown').pipe(filter(() => {
1745
- if (this.isSafari && isIgnore) {
1746
- isIgnore = false;
1747
- return false;
1748
- }
1749
- return !isWriting; // || !this.textarea.value
1750
- })).subscribe(ev => {
1751
- let key = ev.key;
1752
- const b = key === 'Process' && ev.code === 'Digit2';
1753
- if (b) {
1754
- key = '@';
1755
- this.isSougouPinYin = true;
1756
- ev.preventDefault();
1757
- }
1758
- const is = this.keyboard.execShortcut({
1759
- key: key,
1760
- altKey: ev.altKey,
1761
- shiftKey: ev.shiftKey,
1762
- ctrlKey: this.isMac ? ev.metaKey : ev.ctrlKey
1763
- });
1764
- if (is) {
1765
- ev.preventDefault();
1766
- }
1767
- }));
1768
- }
1769
- handleInput(textarea) {
1770
- this.subscription.add(fromEvent(textarea, 'compositionupdate').subscribe(ev => {
1771
- if (ev.data === ' ') {
1772
- // 处理搜狗五笔不符合 composition 事件预期,会意外跳光标的问题
1773
- return;
1774
- }
1775
- const slot = this.selection.startSlot;
1776
- this.caret.compositionState = {
1777
- slot,
1778
- data: ev.data
1779
- };
1780
- slot.changeMarker.forceMarkDirtied();
1781
- }), fromEvent(textarea, 'compositionend').subscribe(() => {
1782
- this.caret.compositionState = null;
1783
- }));
1784
- this.subscription.add(merge(fromEvent(textarea, 'beforeinput').pipe(filter(ev => {
1785
- ev.preventDefault();
1786
- if (this.isSafari) {
1787
- return ev.inputType === 'insertText' || ev.inputType === 'insertFromComposition';
1788
- }
1789
- return !ev.isComposing && !!ev.data;
1790
- }), map(ev => {
1791
- return ev.data;
1792
- })), this.isSafari ? new Observable() : fromEvent(textarea, 'compositionend').pipe(map(ev => {
1793
- ev.preventDefault();
1794
- textarea.value = '';
1795
- return ev.data;
1796
- }), filter(() => {
1797
- const b = this.isSougouPinYin;
1798
- this.isSougouPinYin = false;
1799
- return !b;
1800
- }))).subscribe(text => {
1801
- if (text) {
1802
- this.commander.write(text);
1803
- }
1804
- }));
1805
- }
1806
- createEditableFrame() {
1807
- return createElement('iframe', {
1808
- attrs: {
1809
- scrolling: 'no'
1810
- },
1811
- styles: {
1812
- border: 'none',
1813
- width: '100%',
1814
- display: 'block',
1815
- height: '100%',
1816
- position: 'relative',
1817
- top: this.isWindows ? '3px' : '0'
1818
- }
1819
- });
1820
- }
1821
- };
1822
- MagicInput = __decorate([
1823
- Injectable(),
1824
- __metadata("design:paramtypes", [Parser,
1825
- Keyboard,
1826
- Commander,
1827
- Selection,
1828
- Controller,
1829
- Scheduler,
1830
- Injector])
1331
+ const iframeHTML = `
1332
+ <!DOCTYPE html>
1333
+ <html>
1334
+ <head>
1335
+ <meta charset="UTF-8">
1336
+ <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
1337
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
1338
+ <title>Textbus</title>
1339
+ <style>
1340
+ html {position: fixed; left:0; overflow: hidden}
1341
+ html, body{height: 100%;width:100%}
1342
+ body{margin:0; overflow: hidden}
1343
+ textarea{width: 2000px;height: 100%;opacity: 0; padding: 0; outline: none; border: none; position: absolute; left:0; top:0;}
1344
+ </style>
1345
+ </head>
1346
+ <body>
1347
+ </body>
1348
+ </html>
1349
+ `;
1350
+ class ExperimentalCaret {
1351
+ get rect() {
1352
+ return this.caret.getBoundingClientRect();
1353
+ }
1354
+ set display(v) {
1355
+ this._display = v;
1356
+ this.caret.style.visibility = v ? 'visible' : 'hidden';
1357
+ }
1358
+ get display() {
1359
+ return this._display;
1360
+ }
1361
+ constructor(scheduler, editorMask) {
1362
+ this.scheduler = scheduler;
1363
+ this.editorMask = editorMask;
1364
+ this.compositionState = null;
1365
+ this.compositionElement = createElement('span', {
1366
+ styles: {
1367
+ textDecoration: 'underline'
1368
+ }
1369
+ });
1370
+ this.timer = null;
1371
+ this.oldPosition = null;
1372
+ this._display = true;
1373
+ this.flashing = true;
1374
+ this.subs = [];
1375
+ this.positionChangeEvent = new Subject();
1376
+ this.styleChangeEvent = new Subject();
1377
+ this.oldRange = null;
1378
+ this.isFixed = false;
1379
+ this.onPositionChange = this.positionChangeEvent.pipe(distinctUntilChanged());
1380
+ this.onStyleChange = this.styleChangeEvent.asObservable();
1381
+ this.elementRef = createElement('div', {
1382
+ styles: {
1383
+ position: 'absolute',
1384
+ width: '2px',
1385
+ pointerEvents: 'none'
1386
+ },
1387
+ children: [
1388
+ this.caret = createElement('span', {
1389
+ styles: {
1390
+ width: '100%',
1391
+ height: '100%',
1392
+ position: 'absolute',
1393
+ left: 0,
1394
+ top: 0
1395
+ }
1396
+ })
1397
+ ]
1398
+ });
1399
+ this.subs.push(fromEvent(document, 'mousedown').subscribe(() => {
1400
+ this.flashing = false;
1401
+ }), fromEvent(document, 'mouseup').subscribe(() => {
1402
+ this.flashing = true;
1403
+ }));
1404
+ this.editorMask.appendChild(this.elementRef);
1405
+ }
1406
+ refresh(isFixedCaret = false) {
1407
+ this.isFixed = isFixedCaret;
1408
+ if (this.oldRange) {
1409
+ this.show(this.oldRange, false);
1410
+ }
1411
+ this.isFixed = false;
1412
+ }
1413
+ show(range, restart) {
1414
+ const oldRect = this.elementRef.getBoundingClientRect();
1415
+ this.oldPosition = {
1416
+ top: oldRect.top,
1417
+ left: oldRect.left,
1418
+ height: oldRect.height
1419
+ };
1420
+ this.oldRange = range;
1421
+ if (restart || this.scheduler.lastChangesHasLocalUpdate) {
1422
+ clearTimeout(this.timer);
1423
+ }
1424
+ this.updateCursorPosition(range);
1425
+ if (range.collapsed) {
1426
+ if (restart || this.scheduler.lastChangesHasLocalUpdate) {
1427
+ this.display = true;
1428
+ const toggleShowHide = () => {
1429
+ this.display = !this.display || !this.flashing;
1430
+ this.timer = setTimeout(toggleShowHide, 400);
1431
+ };
1432
+ clearTimeout(this.timer);
1433
+ this.timer = setTimeout(toggleShowHide, 400);
1434
+ }
1435
+ }
1436
+ else {
1437
+ this.display = false;
1438
+ clearTimeout(this.timer);
1439
+ }
1440
+ }
1441
+ hide() {
1442
+ this.display = false;
1443
+ clearTimeout(this.timer);
1444
+ this.positionChangeEvent.next(null);
1445
+ }
1446
+ destroy() {
1447
+ clearTimeout(this.timer);
1448
+ this.subs.forEach(i => i.unsubscribe());
1449
+ }
1450
+ correctScrollTop(scroller) {
1451
+ this.subs.forEach(i => i.unsubscribe());
1452
+ this.subs = [];
1453
+ const scheduler = this.scheduler;
1454
+ let docIsChanged = true;
1455
+ function limitPosition(position) {
1456
+ const { top, bottom } = scroller.getLimit();
1457
+ const caretTop = position.top;
1458
+ if (caretTop + position.height > bottom) {
1459
+ const offset = caretTop - bottom + position.height;
1460
+ scroller.setOffset(offset);
1461
+ }
1462
+ else if (position.top < top) {
1463
+ scroller.setOffset(-(top - position.top));
1464
+ }
1465
+ }
1466
+ let isPressed = false;
1467
+ this.subs.push(scroller.onScroll.subscribe(() => {
1468
+ if (this.oldPosition) {
1469
+ const rect = this.rect;
1470
+ this.oldPosition.top = rect.top;
1471
+ this.oldPosition.left = rect.left;
1472
+ this.oldPosition.height = rect.height;
1473
+ }
1474
+ }), fromEvent(document, 'mousedown', true).subscribe(() => {
1475
+ isPressed = true;
1476
+ }), fromEvent(document, 'mouseup', true).subscribe(() => {
1477
+ isPressed = false;
1478
+ }), scheduler.onDocChange.subscribe(() => {
1479
+ docIsChanged = true;
1480
+ }), this.onPositionChange.subscribe(position => {
1481
+ if (position) {
1482
+ if (docIsChanged) {
1483
+ if (scheduler.lastChangesHasLocalUpdate) {
1484
+ limitPosition(position);
1485
+ }
1486
+ else if (this.oldPosition) {
1487
+ const offset = Math.floor(position.top - this.oldPosition.top);
1488
+ scroller.setOffset(offset);
1489
+ }
1490
+ }
1491
+ else if (!isPressed) {
1492
+ if (this.isFixed && this.oldPosition) {
1493
+ const offset = Math.floor(position.top - this.oldPosition.top);
1494
+ scroller.setOffset(offset);
1495
+ }
1496
+ else {
1497
+ limitPosition(position);
1498
+ }
1499
+ }
1500
+ }
1501
+ docIsChanged = false;
1502
+ }));
1503
+ }
1504
+ updateCursorPosition(nativeRange) {
1505
+ const startContainer = nativeRange.startContainer;
1506
+ const node = (startContainer.nodeType === Node.ELEMENT_NODE ? startContainer : startContainer.parentNode);
1507
+ if ((node === null || node === void 0 ? void 0 : node.nodeType) !== Node.ELEMENT_NODE) {
1508
+ this.positionChangeEvent.next(null);
1509
+ return;
1510
+ }
1511
+ if (this.compositionState) {
1512
+ const compositionElement = this.compositionElement;
1513
+ compositionElement.innerText = this.compositionState.data;
1514
+ nativeRange = nativeRange.cloneRange();
1515
+ nativeRange.insertNode(compositionElement);
1516
+ nativeRange.selectNodeContents(compositionElement);
1517
+ nativeRange.collapse();
1518
+ }
1519
+ const rect = getLayoutRectByRange(nativeRange);
1520
+ const { fontSize, lineHeight, color } = getComputedStyle(node);
1521
+ let height;
1522
+ if (isNaN(+lineHeight)) {
1523
+ const f = parseFloat(lineHeight);
1524
+ if (isNaN(f)) {
1525
+ height = parseFloat(fontSize);
1526
+ }
1527
+ else {
1528
+ height = f;
1529
+ }
1530
+ }
1531
+ else {
1532
+ height = parseFloat(fontSize) * parseFloat(lineHeight);
1533
+ }
1534
+ const boxHeight = Math.floor(Math.max(height, rect.height));
1535
+ // const boxHeight = Math.floor(height)
1536
+ let rectTop = rect.top;
1537
+ if (rect.height < height) {
1538
+ rectTop -= (height - rect.height) / 2;
1539
+ }
1540
+ rectTop = Math.floor(rectTop);
1541
+ const containerRect = this.editorMask.getBoundingClientRect();
1542
+ const top = Math.floor(rectTop - containerRect.top);
1543
+ const left = Math.floor(rect.left - containerRect.left);
1544
+ Object.assign(this.elementRef.style, {
1545
+ left: left + 'px',
1546
+ top: top + 'px',
1547
+ height: boxHeight + 'px',
1548
+ lineHeight: boxHeight + 'px',
1549
+ fontSize
1550
+ });
1551
+ this.caret.style.backgroundColor = color;
1552
+ this.styleChangeEvent.next({
1553
+ height: boxHeight + 'px',
1554
+ lineHeight: boxHeight + 'px',
1555
+ fontSize
1556
+ });
1557
+ this.positionChangeEvent.next({
1558
+ left,
1559
+ top: rectTop,
1560
+ height: boxHeight
1561
+ });
1562
+ }
1563
+ }
1564
+ /**
1565
+ * Textbus PC 端输入实现
1566
+ */
1567
+ let MagicInput = class MagicInput extends Input {
1568
+ set disabled(b) {
1569
+ this._disabled = b;
1570
+ if (b && this.textarea) {
1571
+ this.textarea.disabled = b;
1572
+ }
1573
+ }
1574
+ get disabled() {
1575
+ return this._disabled;
1576
+ }
1577
+ constructor(parser, keyboard, commander, selection, controller, scheduler, injector) {
1578
+ super();
1579
+ this.parser = parser;
1580
+ this.keyboard = keyboard;
1581
+ this.commander = commander;
1582
+ this.selection = selection;
1583
+ this.controller = controller;
1584
+ this.scheduler = scheduler;
1585
+ this.injector = injector;
1586
+ this.composition = false;
1587
+ this.caret = new ExperimentalCaret(this.scheduler, this.injector.get(VIEW_MASK));
1588
+ this.isSafari = isSafari();
1589
+ this.isMac = isMac();
1590
+ this.isWindows = isWindows();
1591
+ this._disabled = false;
1592
+ this.container = this.createEditableFrame();
1593
+ this.subscription = new Subscription();
1594
+ this.textarea = null;
1595
+ this.isFocus = false;
1596
+ this.nativeFocus = false;
1597
+ this.isSougouPinYin = false; // 有 bug 版本搜狗拼音
1598
+ this.onReady = new Promise(resolve => {
1599
+ this.subscription.add(fromEvent(this.container, 'load').subscribe(() => {
1600
+ const doc = this.container.contentDocument;
1601
+ doc.open();
1602
+ doc.write(iframeHTML);
1603
+ doc.close();
1604
+ this.doc = doc;
1605
+ this.init();
1606
+ resolve();
1607
+ }), controller.onReadonlyStateChange.subscribe(() => {
1608
+ if (controller.readonly) {
1609
+ this.blur();
1610
+ }
1611
+ }));
1612
+ });
1613
+ this.caret.elementRef.append(this.container);
1614
+ }
1615
+ focus(range, restart) {
1616
+ var _a;
1617
+ if (!this.disabled) {
1618
+ this.caret.show(range, restart);
1619
+ }
1620
+ if (this.controller.readonly) {
1621
+ return;
1622
+ }
1623
+ if (!this.isFocus) {
1624
+ (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1625
+ setTimeout(() => {
1626
+ var _a, _b, _c;
1627
+ if (!this.nativeFocus && this.isFocus) {
1628
+ this.subscription.unsubscribe();
1629
+ (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1630
+ this.subscription = new Subscription();
1631
+ this.init();
1632
+ (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1633
+ }
1634
+ });
1635
+ }
1636
+ this.isFocus = true;
1637
+ }
1638
+ blur() {
1639
+ var _a;
1640
+ this.caret.hide();
1641
+ (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.blur();
1642
+ this.isFocus = false;
1643
+ }
1644
+ destroy() {
1645
+ this.caret.destroy();
1646
+ this.subscription.unsubscribe();
1647
+ }
1648
+ init() {
1649
+ const doc = this.doc;
1650
+ const contentBody = doc.body;
1651
+ const textarea = doc.createElement('textarea');
1652
+ textarea.disabled = this.disabled;
1653
+ contentBody.appendChild(textarea);
1654
+ this.textarea = textarea;
1655
+ this.subscription.add(fromEvent(textarea, 'blur').subscribe(() => {
1656
+ this.isFocus = false;
1657
+ this.nativeFocus = false;
1658
+ this.caret.hide();
1659
+ }), fromEvent(textarea, 'focus').subscribe(() => {
1660
+ this.nativeFocus = true;
1661
+ }), this.caret.onStyleChange.subscribe(style => {
1662
+ Object.assign(textarea.style, style);
1663
+ }));
1664
+ this.handleInput(textarea);
1665
+ this.handleShortcut(textarea);
1666
+ this.handleDefaultActions(textarea);
1667
+ }
1668
+ handleDefaultActions(textarea) {
1669
+ this.subscription.add(fromEvent(document, 'copy').subscribe(ev => {
1670
+ const selection = this.selection;
1671
+ if (!selection.isSelected) {
1672
+ return;
1673
+ }
1674
+ if (selection.startSlot === selection.endSlot && selection.endOffset - selection.startOffset === 1) {
1675
+ const content = selection.startSlot.getContentAtIndex(selection.startOffset);
1676
+ if (typeof content === 'object') {
1677
+ const clipboardData = ev.clipboardData;
1678
+ const nativeSelection = document.getSelection();
1679
+ const range = nativeSelection.getRangeAt(0);
1680
+ const div = document.createElement('div');
1681
+ const fragment = range.cloneContents();
1682
+ div.append(fragment);
1683
+ clipboardData.setData('text/html', div.innerHTML);
1684
+ clipboardData.setData('text', div.innerText);
1685
+ ev.preventDefault();
1686
+ }
1687
+ }
1688
+ }), fromEvent(textarea, 'paste').subscribe(ev => {
1689
+ const text = ev.clipboardData.getData('Text');
1690
+ const files = Array.from(ev.clipboardData.files);
1691
+ if (files.length) {
1692
+ Promise.all(files.filter(i => {
1693
+ return /image/i.test(i.type);
1694
+ }).map(item => {
1695
+ const reader = new FileReader();
1696
+ return new Promise(resolve => {
1697
+ reader.onload = (event) => {
1698
+ resolve(event.target.result);
1699
+ };
1700
+ reader.readAsDataURL(item);
1701
+ });
1702
+ })).then(urls => {
1703
+ const html = urls.map(i => {
1704
+ return `<img src=${i}>`;
1705
+ }).join('');
1706
+ this.handlePaste(html, text);
1707
+ });
1708
+ ev.preventDefault();
1709
+ return;
1710
+ }
1711
+ const div = this.doc.createElement('div');
1712
+ div.style.cssText = 'width:1px; height:10px; overflow: hidden; position: fixed; left: 50%; top: 50%; opacity:0';
1713
+ div.contentEditable = 'true';
1714
+ this.doc.body.appendChild(div);
1715
+ div.focus();
1716
+ setTimeout(() => {
1717
+ const html = div.innerHTML;
1718
+ this.handlePaste(html, text);
1719
+ this.doc.body.removeChild(div);
1720
+ });
1721
+ }));
1722
+ }
1723
+ handlePaste(html, text) {
1724
+ const slot = this.parser.parse(html, new Slot([
1725
+ ContentType.BlockComponent,
1726
+ ContentType.InlineComponent,
1727
+ ContentType.Text
1728
+ ]));
1729
+ this.commander.paste(slot, text);
1730
+ }
1731
+ handleShortcut(textarea) {
1732
+ let isWriting = false;
1733
+ let isIgnore = false;
1734
+ this.subscription.add(fromEvent(textarea, 'compositionstart').subscribe(() => {
1735
+ isWriting = true;
1736
+ }), fromEvent(textarea, 'compositionend').subscribe(() => {
1737
+ isWriting = false;
1738
+ }), fromEvent(textarea, 'beforeinput').subscribe(ev => {
1739
+ if (this.isSafari) {
1740
+ if (ev.inputType === 'insertFromComposition') {
1741
+ isIgnore = true;
1742
+ }
1743
+ }
1744
+ }), fromEvent(textarea, 'keydown').pipe(filter(() => {
1745
+ if (this.isSafari && isIgnore) {
1746
+ isIgnore = false;
1747
+ return false;
1748
+ }
1749
+ return !isWriting; // || !this.textarea.value
1750
+ })).subscribe(ev => {
1751
+ let key = ev.key;
1752
+ const b = key === 'Process' && ev.code === 'Digit2';
1753
+ if (b) {
1754
+ key = '@';
1755
+ this.isSougouPinYin = true;
1756
+ ev.preventDefault();
1757
+ }
1758
+ const is = this.keyboard.execShortcut({
1759
+ key: key,
1760
+ altKey: ev.altKey,
1761
+ shiftKey: ev.shiftKey,
1762
+ ctrlKey: this.isMac ? ev.metaKey : ev.ctrlKey
1763
+ });
1764
+ if (is) {
1765
+ ev.preventDefault();
1766
+ }
1767
+ }));
1768
+ }
1769
+ handleInput(textarea) {
1770
+ let startIndex = 0;
1771
+ this.subscription.add(fromEvent(textarea, 'compositionstart').subscribe(() => {
1772
+ startIndex = this.selection.startOffset;
1773
+ }), fromEvent(textarea, 'compositionupdate').subscribe(ev => {
1774
+ if (ev.data === ' ') {
1775
+ // 处理搜狗五笔不符合 composition 事件预期,会意外跳光标的问题
1776
+ return;
1777
+ }
1778
+ this.caret.compositionState = {
1779
+ slot: this.selection.startSlot,
1780
+ index: startIndex,
1781
+ data: ev.data
1782
+ };
1783
+ this.caret.refresh(true);
1784
+ }), fromEvent(textarea, 'compositionend').subscribe(() => {
1785
+ var _a;
1786
+ this.caret.compositionState = null;
1787
+ (_a = this.caret.compositionElement.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.caret.compositionElement);
1788
+ }));
1789
+ this.subscription.add(merge(fromEvent(textarea, 'beforeinput').pipe(filter(ev => {
1790
+ ev.preventDefault();
1791
+ if (this.isSafari) {
1792
+ return ev.inputType === 'insertText' || ev.inputType === 'insertFromComposition';
1793
+ }
1794
+ return !ev.isComposing && !!ev.data;
1795
+ }), map(ev => {
1796
+ return ev.data;
1797
+ })), this.isSafari ? new Observable() : fromEvent(textarea, 'compositionend').pipe(map(ev => {
1798
+ ev.preventDefault();
1799
+ textarea.value = '';
1800
+ return ev.data;
1801
+ }), filter(() => {
1802
+ const b = this.isSougouPinYin;
1803
+ this.isSougouPinYin = false;
1804
+ return !b;
1805
+ }))).subscribe(text => {
1806
+ if (text) {
1807
+ this.commander.write(text);
1808
+ }
1809
+ }));
1810
+ }
1811
+ createEditableFrame() {
1812
+ return createElement('iframe', {
1813
+ attrs: {
1814
+ scrolling: 'no'
1815
+ },
1816
+ styles: {
1817
+ border: 'none',
1818
+ width: '100%',
1819
+ display: 'block',
1820
+ height: '100%',
1821
+ position: 'relative',
1822
+ top: this.isWindows ? '3px' : '0'
1823
+ }
1824
+ });
1825
+ }
1826
+ };
1827
+ MagicInput = __decorate([
1828
+ Injectable(),
1829
+ __metadata("design:paramtypes", [Parser,
1830
+ Keyboard,
1831
+ Commander,
1832
+ Selection,
1833
+ Controller,
1834
+ Scheduler,
1835
+ Injector])
1831
1836
  ], MagicInput);
1832
1837
 
1833
- class NativeCaret {
1834
- set nativeRange(range) {
1835
- this._nativeRange = range;
1836
- if (range) {
1837
- const r = range.cloneRange();
1838
- r.collapse(true);
1839
- const rect = r.getBoundingClientRect();
1840
- this.positionChangeEvent.next({
1841
- left: rect.left,
1842
- top: rect.top,
1843
- height: rect.height
1844
- });
1845
- }
1846
- else {
1847
- this.positionChangeEvent.next(null);
1848
- }
1849
- }
1850
- get nativeRange() {
1851
- return this._nativeRange;
1852
- }
1853
- get rect() {
1854
- if (this.nativeRange) {
1855
- const range = this.nativeRange.cloneRange();
1856
- range.collapse(true);
1857
- return range.getBoundingClientRect();
1858
- }
1859
- return {
1860
- left: 0,
1861
- top: 0,
1862
- width: 0,
1863
- height: 0
1864
- };
1865
- }
1866
- constructor(scheduler) {
1867
- this.scheduler = scheduler;
1868
- this.oldPosition = null;
1869
- this._nativeRange = null;
1870
- this.subs = [];
1871
- this.positionChangeEvent = new Subject();
1872
- this.onPositionChange = this.positionChangeEvent.pipe(distinctUntilChanged());
1873
- }
1874
- refresh() {
1875
- //
1876
- }
1877
- correctScrollTop(scroller) {
1878
- this.destroy();
1879
- const scheduler = this.scheduler;
1880
- let docIsChanged = true;
1881
- function limitPosition(position) {
1882
- const { top, bottom } = scroller.getLimit();
1883
- const caretTop = position.top;
1884
- if (caretTop + position.height > bottom) {
1885
- const offset = caretTop - bottom + position.height;
1886
- scroller.setOffset(offset);
1887
- }
1888
- else if (position.top < top) {
1889
- scroller.setOffset(-(top - position.top));
1890
- }
1891
- }
1892
- let isPressed = false;
1893
- this.subs.push(scroller.onScroll.subscribe(() => {
1894
- if (this.oldPosition) {
1895
- const rect = this.rect;
1896
- this.oldPosition.top = rect.top;
1897
- this.oldPosition.left = rect.left;
1898
- this.oldPosition.height = rect.height;
1899
- }
1900
- }), fromEvent(document, 'mousedown', true).subscribe(() => {
1901
- isPressed = true;
1902
- }), fromEvent(document, 'mouseup', true).subscribe(() => {
1903
- isPressed = false;
1904
- }), scheduler.onDocChange.subscribe(() => {
1905
- docIsChanged = true;
1906
- }), this.onPositionChange.subscribe(position => {
1907
- if (position) {
1908
- if (docIsChanged) {
1909
- if (scheduler.lastChangesHasLocalUpdate) {
1910
- limitPosition(position);
1911
- }
1912
- else if (this.oldPosition) {
1913
- const offset = Math.floor(position.top - this.oldPosition.top);
1914
- scroller.setOffset(offset);
1915
- }
1916
- }
1917
- else if (!isPressed) {
1918
- if (this.oldPosition) {
1919
- const offset = Math.floor(position.top - this.oldPosition.top);
1920
- scroller.setOffset(offset);
1921
- }
1922
- else {
1923
- limitPosition(position);
1924
- }
1925
- }
1926
- }
1927
- docIsChanged = false;
1928
- }));
1929
- }
1930
- destroy() {
1931
- this.subs.forEach(i => i.unsubscribe());
1932
- this.subs = [];
1933
- }
1934
- }
1935
- let NativeInput = class NativeInput extends Input {
1936
- set disabled(b) {
1937
- this._disabled = b;
1938
- if (b && !this.controller.readonly) {
1939
- this.documentView.contentEditable = b ? 'false' : 'true';
1940
- }
1941
- }
1942
- get disabled() {
1943
- return this._disabled;
1944
- }
1945
- constructor(injector, parser, scheduler, selection, keyboard, commander, controller) {
1946
- super();
1947
- this.injector = injector;
1948
- this.parser = parser;
1949
- this.scheduler = scheduler;
1950
- this.selection = selection;
1951
- this.keyboard = keyboard;
1952
- this.commander = commander;
1953
- this.controller = controller;
1954
- this.caret = new NativeCaret(this.scheduler);
1955
- this.composition = false;
1956
- this.onReady = Promise.resolve();
1957
- this._disabled = false;
1958
- this.nativeSelection = document.getSelection();
1959
- this.subscription = new Subscription();
1960
- this.nativeRange = null;
1961
- this.isSafari = isSafari();
1962
- this.isMac = isMac();
1963
- this.isSougouPinYin = false; // 有 bug 版本搜狗拼音
1964
- this.documentView = injector.get(VIEW_DOCUMENT);
1965
- if (!controller.readonly) {
1966
- this.documentView.contentEditable = 'true';
1967
- }
1968
- this.subscription.add(controller.onReadonlyStateChange.subscribe(() => {
1969
- this.documentView.contentEditable = controller.readonly ? 'false' : 'true';
1970
- }));
1971
- this.handleShortcut(this.documentView);
1972
- this.handleInput(this.documentView);
1973
- this.handleDefaultActions(this.documentView);
1974
- }
1975
- focus(nativeRange) {
1976
- if (this.controller.readonly) {
1977
- return;
1978
- }
1979
- this.caret.nativeRange = nativeRange;
1980
- this.nativeRange = nativeRange;
1981
- }
1982
- blur() {
1983
- if (this.nativeRange && this.nativeSelection.rangeCount > 0) {
1984
- const current = this.nativeSelection.getRangeAt(0);
1985
- if (current === this.nativeRange) {
1986
- this.nativeSelection.removeAllRanges();
1987
- this.nativeRange = null;
1988
- return;
1989
- }
1990
- }
1991
- }
1992
- destroy() {
1993
- this.caret.destroy();
1994
- this.subscription.unsubscribe();
1995
- }
1996
- handleDefaultActions(textarea) {
1997
- this.subscription.add(fromEvent(document, 'copy').subscribe(ev => {
1998
- const selection = this.selection;
1999
- if (!selection.isSelected) {
2000
- return;
2001
- }
2002
- if (selection.startSlot === selection.endSlot && selection.endOffset - selection.startOffset === 1) {
2003
- const content = selection.startSlot.getContentAtIndex(selection.startOffset);
2004
- if (typeof content === 'object') {
2005
- const clipboardData = ev.clipboardData;
2006
- const nativeSelection = document.getSelection();
2007
- const range = nativeSelection.getRangeAt(0);
2008
- const div = document.createElement('div');
2009
- const fragment = range.cloneContents();
2010
- div.append(fragment);
2011
- clipboardData.setData('text/html', div.innerHTML);
2012
- clipboardData.setData('text', div.innerText);
2013
- ev.preventDefault();
2014
- }
2015
- }
2016
- }), fromEvent(textarea, 'paste').subscribe(ev => {
2017
- const text = ev.clipboardData.getData('Text');
2018
- const files = Array.from(ev.clipboardData.files);
2019
- if (files.length) {
2020
- Promise.all(files.filter(i => {
2021
- return /image/i.test(i.type);
2022
- }).map(item => {
2023
- const reader = new FileReader();
2024
- return new Promise(resolve => {
2025
- reader.onload = (event) => {
2026
- resolve(event.target.result);
2027
- };
2028
- reader.readAsDataURL(item);
2029
- });
2030
- })).then(urls => {
2031
- const html = urls.map(i => {
2032
- return `<img src=${i}>`;
2033
- }).join('');
2034
- this.handlePaste(html, text);
2035
- });
2036
- ev.preventDefault();
2037
- return;
2038
- }
2039
- const div = document.createElement('div');
2040
- div.style.cssText = 'width:1px; height:10px; overflow: hidden; position: fixed; left: 50%; top: 50%; opacity:0';
2041
- div.contentEditable = 'true';
2042
- document.body.appendChild(div);
2043
- div.focus();
2044
- setTimeout(() => {
2045
- const html = div.innerHTML;
2046
- this.handlePaste(html, text);
2047
- document.body.removeChild(div);
2048
- });
2049
- }));
2050
- }
2051
- handlePaste(html, text) {
2052
- const slot = this.parser.parse(html, new Slot([
2053
- ContentType.BlockComponent,
2054
- ContentType.InlineComponent,
2055
- ContentType.Text
2056
- ]));
2057
- this.commander.paste(slot, text);
2058
- }
2059
- handleShortcut(input) {
2060
- let isWriting = false;
2061
- let isIgnore = false;
2062
- this.subscription.add(fromEvent(input, 'compositionstart').subscribe(() => {
2063
- isWriting = true;
2064
- }), fromEvent(input, 'compositionend').subscribe(() => {
2065
- isWriting = false;
2066
- }), fromEvent(input, 'beforeinput').subscribe(ev => {
2067
- if (this.isSafari) {
2068
- if (ev.inputType === 'insertFromComposition') {
2069
- isIgnore = true;
2070
- }
2071
- }
2072
- }), fromEvent(input, 'keydown').pipe(filter(() => {
2073
- if (this.isSafari && isIgnore) {
2074
- isIgnore = false;
2075
- return false;
2076
- }
2077
- return !isWriting; // || !this.textarea.value
2078
- })).subscribe(ev => {
2079
- let key = ev.key;
2080
- const b = key === 'Process' && ev.code === 'Digit2';
2081
- if (b) {
2082
- key = '@';
2083
- this.isSougouPinYin = true;
2084
- ev.preventDefault();
2085
- }
2086
- const is = this.keyboard.execShortcut({
2087
- key: key,
2088
- altKey: ev.altKey,
2089
- shiftKey: ev.shiftKey,
2090
- ctrlKey: this.isMac ? ev.metaKey : ev.ctrlKey
2091
- });
2092
- if (is) {
2093
- ev.preventDefault();
2094
- }
2095
- }));
2096
- }
2097
- handleInput(input) {
2098
- this.subscription.add(fromEvent(input, 'compositionstart').subscribe(() => {
2099
- this.composition = true;
2100
- }), merge(fromEvent(input, 'beforeinput').pipe(filter(ev => {
2101
- ev.preventDefault();
2102
- if (this.isSafari) {
2103
- return ev.inputType === 'insertText' || ev.inputType === 'insertFromComposition';
2104
- }
2105
- return !ev.isComposing && !!ev.data;
2106
- }), map(ev => {
2107
- return ev.data;
2108
- })), this.isSafari ? new Observable() : fromEvent(input, 'compositionend').pipe(map(ev => {
2109
- ev.preventDefault();
2110
- return ev.data;
2111
- }), filter(() => {
2112
- const b = this.isSougouPinYin;
2113
- this.isSougouPinYin = false;
2114
- return !b;
2115
- }))).subscribe(text => {
2116
- this.composition = false;
2117
- if (text) {
2118
- this.commander.write(text);
2119
- }
2120
- }));
2121
- }
2122
- };
2123
- NativeInput = __decorate([
2124
- Injectable(),
2125
- __metadata("design:paramtypes", [Injector,
2126
- Parser,
2127
- Scheduler,
2128
- Selection,
2129
- Keyboard,
2130
- Commander,
2131
- Controller])
1838
+ class NativeCaret {
1839
+ set nativeRange(range) {
1840
+ this._nativeRange = range;
1841
+ if (range) {
1842
+ const r = range.cloneRange();
1843
+ r.collapse(true);
1844
+ const rect = r.getBoundingClientRect();
1845
+ this.positionChangeEvent.next({
1846
+ left: rect.left,
1847
+ top: rect.top,
1848
+ height: rect.height
1849
+ });
1850
+ }
1851
+ else {
1852
+ this.positionChangeEvent.next(null);
1853
+ }
1854
+ }
1855
+ get nativeRange() {
1856
+ return this._nativeRange;
1857
+ }
1858
+ get rect() {
1859
+ if (this.nativeRange) {
1860
+ const range = this.nativeRange.cloneRange();
1861
+ range.collapse(true);
1862
+ return range.getBoundingClientRect();
1863
+ }
1864
+ return {
1865
+ left: 0,
1866
+ top: 0,
1867
+ width: 0,
1868
+ height: 0
1869
+ };
1870
+ }
1871
+ constructor(scheduler) {
1872
+ this.scheduler = scheduler;
1873
+ this.oldPosition = null;
1874
+ this._nativeRange = null;
1875
+ this.subs = [];
1876
+ this.positionChangeEvent = new Subject();
1877
+ this.onPositionChange = this.positionChangeEvent.pipe(distinctUntilChanged());
1878
+ }
1879
+ refresh() {
1880
+ //
1881
+ }
1882
+ correctScrollTop(scroller) {
1883
+ this.destroy();
1884
+ const scheduler = this.scheduler;
1885
+ let docIsChanged = true;
1886
+ function limitPosition(position) {
1887
+ const { top, bottom } = scroller.getLimit();
1888
+ const caretTop = position.top;
1889
+ if (caretTop + position.height > bottom) {
1890
+ const offset = caretTop - bottom + position.height;
1891
+ scroller.setOffset(offset);
1892
+ }
1893
+ else if (position.top < top) {
1894
+ scroller.setOffset(-(top - position.top));
1895
+ }
1896
+ }
1897
+ let isPressed = false;
1898
+ this.subs.push(scroller.onScroll.subscribe(() => {
1899
+ if (this.oldPosition) {
1900
+ const rect = this.rect;
1901
+ this.oldPosition.top = rect.top;
1902
+ this.oldPosition.left = rect.left;
1903
+ this.oldPosition.height = rect.height;
1904
+ }
1905
+ }), fromEvent(document, 'mousedown', true).subscribe(() => {
1906
+ isPressed = true;
1907
+ }), fromEvent(document, 'mouseup', true).subscribe(() => {
1908
+ isPressed = false;
1909
+ }), scheduler.onDocChange.subscribe(() => {
1910
+ docIsChanged = true;
1911
+ }), this.onPositionChange.subscribe(position => {
1912
+ if (position) {
1913
+ if (docIsChanged) {
1914
+ if (scheduler.lastChangesHasLocalUpdate) {
1915
+ limitPosition(position);
1916
+ }
1917
+ else if (this.oldPosition) {
1918
+ const offset = Math.floor(position.top - this.oldPosition.top);
1919
+ scroller.setOffset(offset);
1920
+ }
1921
+ }
1922
+ else if (!isPressed) {
1923
+ if (this.oldPosition) {
1924
+ const offset = Math.floor(position.top - this.oldPosition.top);
1925
+ scroller.setOffset(offset);
1926
+ }
1927
+ else {
1928
+ limitPosition(position);
1929
+ }
1930
+ }
1931
+ }
1932
+ docIsChanged = false;
1933
+ }));
1934
+ }
1935
+ destroy() {
1936
+ this.subs.forEach(i => i.unsubscribe());
1937
+ this.subs = [];
1938
+ }
1939
+ }
1940
+ let NativeInput = class NativeInput extends Input {
1941
+ set disabled(b) {
1942
+ this._disabled = b;
1943
+ if (b && !this.controller.readonly) {
1944
+ this.documentView.contentEditable = b ? 'false' : 'true';
1945
+ }
1946
+ }
1947
+ get disabled() {
1948
+ return this._disabled;
1949
+ }
1950
+ constructor(injector, parser, scheduler, selection, keyboard, commander, controller) {
1951
+ super();
1952
+ this.injector = injector;
1953
+ this.parser = parser;
1954
+ this.scheduler = scheduler;
1955
+ this.selection = selection;
1956
+ this.keyboard = keyboard;
1957
+ this.commander = commander;
1958
+ this.controller = controller;
1959
+ this.caret = new NativeCaret(this.scheduler);
1960
+ this.composition = false;
1961
+ this.onReady = Promise.resolve();
1962
+ this._disabled = false;
1963
+ this.nativeSelection = document.getSelection();
1964
+ this.subscription = new Subscription();
1965
+ this.nativeRange = null;
1966
+ this.isSafari = isSafari();
1967
+ this.isMac = isMac();
1968
+ this.isSougouPinYin = false; // 有 bug 版本搜狗拼音
1969
+ this.documentView = injector.get(VIEW_DOCUMENT);
1970
+ if (!controller.readonly) {
1971
+ this.documentView.contentEditable = 'true';
1972
+ }
1973
+ this.subscription.add(controller.onReadonlyStateChange.subscribe(() => {
1974
+ this.documentView.contentEditable = controller.readonly ? 'false' : 'true';
1975
+ }));
1976
+ this.handleShortcut(this.documentView);
1977
+ this.handleInput(this.documentView);
1978
+ this.handleDefaultActions(this.documentView);
1979
+ }
1980
+ focus(nativeRange) {
1981
+ if (this.controller.readonly) {
1982
+ return;
1983
+ }
1984
+ this.caret.nativeRange = nativeRange;
1985
+ this.nativeRange = nativeRange;
1986
+ }
1987
+ blur() {
1988
+ if (this.nativeRange && this.nativeSelection.rangeCount > 0) {
1989
+ const current = this.nativeSelection.getRangeAt(0);
1990
+ if (current === this.nativeRange) {
1991
+ this.nativeSelection.removeAllRanges();
1992
+ this.nativeRange = null;
1993
+ return;
1994
+ }
1995
+ }
1996
+ }
1997
+ destroy() {
1998
+ this.caret.destroy();
1999
+ this.subscription.unsubscribe();
2000
+ }
2001
+ handleDefaultActions(textarea) {
2002
+ this.subscription.add(fromEvent(document, 'copy').subscribe(ev => {
2003
+ const selection = this.selection;
2004
+ if (!selection.isSelected) {
2005
+ return;
2006
+ }
2007
+ if (selection.startSlot === selection.endSlot && selection.endOffset - selection.startOffset === 1) {
2008
+ const content = selection.startSlot.getContentAtIndex(selection.startOffset);
2009
+ if (typeof content === 'object') {
2010
+ const clipboardData = ev.clipboardData;
2011
+ const nativeSelection = document.getSelection();
2012
+ const range = nativeSelection.getRangeAt(0);
2013
+ const div = document.createElement('div');
2014
+ const fragment = range.cloneContents();
2015
+ div.append(fragment);
2016
+ clipboardData.setData('text/html', div.innerHTML);
2017
+ clipboardData.setData('text', div.innerText);
2018
+ ev.preventDefault();
2019
+ }
2020
+ }
2021
+ }), fromEvent(textarea, 'paste').subscribe(ev => {
2022
+ const text = ev.clipboardData.getData('Text');
2023
+ const files = Array.from(ev.clipboardData.files);
2024
+ if (files.length) {
2025
+ Promise.all(files.filter(i => {
2026
+ return /image/i.test(i.type);
2027
+ }).map(item => {
2028
+ const reader = new FileReader();
2029
+ return new Promise(resolve => {
2030
+ reader.onload = (event) => {
2031
+ resolve(event.target.result);
2032
+ };
2033
+ reader.readAsDataURL(item);
2034
+ });
2035
+ })).then(urls => {
2036
+ const html = urls.map(i => {
2037
+ return `<img src=${i}>`;
2038
+ }).join('');
2039
+ this.handlePaste(html, text);
2040
+ });
2041
+ ev.preventDefault();
2042
+ return;
2043
+ }
2044
+ const div = document.createElement('div');
2045
+ div.style.cssText = 'width:1px; height:10px; overflow: hidden; position: fixed; left: 50%; top: 50%; opacity:0';
2046
+ div.contentEditable = 'true';
2047
+ document.body.appendChild(div);
2048
+ div.focus();
2049
+ setTimeout(() => {
2050
+ const html = div.innerHTML;
2051
+ this.handlePaste(html, text);
2052
+ document.body.removeChild(div);
2053
+ });
2054
+ }));
2055
+ }
2056
+ handlePaste(html, text) {
2057
+ const slot = this.parser.parse(html, new Slot([
2058
+ ContentType.BlockComponent,
2059
+ ContentType.InlineComponent,
2060
+ ContentType.Text
2061
+ ]));
2062
+ this.commander.paste(slot, text);
2063
+ }
2064
+ handleShortcut(input) {
2065
+ let isWriting = false;
2066
+ let isIgnore = false;
2067
+ this.subscription.add(fromEvent(input, 'compositionstart').subscribe(() => {
2068
+ isWriting = true;
2069
+ }), fromEvent(input, 'compositionend').subscribe(() => {
2070
+ isWriting = false;
2071
+ }), fromEvent(input, 'beforeinput').subscribe(ev => {
2072
+ if (this.isSafari) {
2073
+ if (ev.inputType === 'insertFromComposition') {
2074
+ isIgnore = true;
2075
+ }
2076
+ }
2077
+ }), fromEvent(input, 'keydown').pipe(filter(() => {
2078
+ if (this.isSafari && isIgnore) {
2079
+ isIgnore = false;
2080
+ return false;
2081
+ }
2082
+ return !isWriting; // || !this.textarea.value
2083
+ })).subscribe(ev => {
2084
+ let key = ev.key;
2085
+ const b = key === 'Process' && ev.code === 'Digit2';
2086
+ if (b) {
2087
+ key = '@';
2088
+ this.isSougouPinYin = true;
2089
+ ev.preventDefault();
2090
+ }
2091
+ const is = this.keyboard.execShortcut({
2092
+ key: key,
2093
+ altKey: ev.altKey,
2094
+ shiftKey: ev.shiftKey,
2095
+ ctrlKey: this.isMac ? ev.metaKey : ev.ctrlKey
2096
+ });
2097
+ if (is) {
2098
+ ev.preventDefault();
2099
+ }
2100
+ }));
2101
+ }
2102
+ handleInput(input) {
2103
+ this.subscription.add(fromEvent(input, 'compositionstart').subscribe(() => {
2104
+ this.composition = true;
2105
+ }), merge(fromEvent(input, 'beforeinput').pipe(filter(ev => {
2106
+ ev.preventDefault();
2107
+ if (this.isSafari) {
2108
+ return ev.inputType === 'insertText' || ev.inputType === 'insertFromComposition';
2109
+ }
2110
+ return !ev.isComposing && !!ev.data;
2111
+ }), map(ev => {
2112
+ return ev.data;
2113
+ })), this.isSafari ? new Observable() : fromEvent(input, 'compositionend').pipe(map(ev => {
2114
+ ev.preventDefault();
2115
+ return ev.data;
2116
+ }), filter(() => {
2117
+ const b = this.isSougouPinYin;
2118
+ this.isSougouPinYin = false;
2119
+ return !b;
2120
+ }))).subscribe(text => {
2121
+ this.composition = false;
2122
+ if (text) {
2123
+ this.commander.write(text);
2124
+ }
2125
+ }));
2126
+ }
2127
+ };
2128
+ NativeInput = __decorate([
2129
+ Injectable(),
2130
+ __metadata("design:paramtypes", [Injector,
2131
+ Parser,
2132
+ Scheduler,
2133
+ Selection,
2134
+ Keyboard,
2135
+ Commander,
2136
+ Controller])
2132
2137
  ], NativeInput);
2133
2138
 
2134
- var OutputTranslator_1;
2135
- /**
2136
- * HTML 输出转换器
2137
- */
2138
- let OutputTranslator = OutputTranslator_1 = class OutputTranslator {
2139
- constructor() {
2140
- this.singleTagTest = new RegExp(`^(${OutputTranslator_1.singleTags.join('|')})$`, 'i');
2141
- }
2142
- transform(vDom) {
2143
- return vDom.children.map(child => {
2144
- return this.vDomToHTMLString(child);
2145
- }).join('');
2146
- }
2147
- vDomToHTMLString(vDom) {
2148
- const xssFilter = OutputTranslator_1.simpleXSSFilter;
2149
- if (vDom instanceof VTextNode) {
2150
- return this.replaceEmpty(xssFilter.text(vDom.textContent), '&nbsp;');
2151
- }
2152
- const styles = Array.from(vDom.styles.keys()).filter(key => {
2153
- const v = vDom.styles.get(key);
2154
- return !(v === undefined || v === null || v === '');
2155
- }).map(key => {
2156
- const k = key.replace(/(?=[A-Z])/g, '-').toLowerCase();
2157
- return xssFilter.attrValue(`${k}:${vDom.styles.get(key)}`);
2158
- }).join(';');
2159
- const attrs = Array.from(vDom.attrs.keys()).filter(key => key !== 'ref' && vDom.attrs.get(key) !== false).map(k => {
2160
- const key = xssFilter.attrName(k);
2161
- const value = vDom.attrs.get(k);
2162
- return (value === true ? `${key}` : `${key}="${xssFilter.attrValue(`${value}`)}"`);
2163
- });
2164
- if (styles) {
2165
- attrs.push(`style="${styles}"`);
2166
- }
2167
- if (vDom.classes && vDom.classes.size) {
2168
- attrs.push(`class="${xssFilter.attrValue(Array.from(vDom.classes).join(' '))}"`);
2169
- }
2170
- let attrStr = attrs.join(' ');
2171
- attrStr = attrStr ? ' ' + attrStr : '';
2172
- if (this.singleTagTest.test(vDom.tagName)) {
2173
- return `<${vDom.tagName}${attrStr}>`;
2174
- }
2175
- const childHTML = vDom.children.map(child => {
2176
- return this.vDomToHTMLString(child);
2177
- }).join('');
2178
- return [
2179
- `<${vDom.tagName}${attrStr}>`,
2180
- childHTML,
2181
- `</${vDom.tagName}>`
2182
- ].join('');
2183
- }
2184
- replaceEmpty(s, target) {
2185
- return s.replace(/\s\s+/g, str => {
2186
- return ' ' + Array.from({
2187
- length: str.length - 1
2188
- }).fill(target).join('');
2189
- }).replace(/^\s|\s$/g, target);
2190
- }
2191
- };
2192
- OutputTranslator.singleTags = 'br,img,hr'.split(',');
2193
- OutputTranslator.simpleXSSFilter = {
2194
- text(text) {
2195
- return text.replace(/[><&]/g, str => {
2196
- return {
2197
- '<': '&lt;',
2198
- '>': '&gt;',
2199
- '&': '&amp;'
2200
- }[str];
2201
- });
2202
- },
2203
- attrName(text) {
2204
- return text.replace(/[><"'&]/g, str => {
2205
- return {
2206
- '<': '&lt;',
2207
- '>': '&gt;',
2208
- '"': '&quot;',
2209
- '\'': '&#x27;',
2210
- '&': '&amp;'
2211
- }[str];
2212
- });
2213
- },
2214
- attrValue(text) {
2215
- return text.replace(/["']/g, str => {
2216
- return {
2217
- '"': '&quot;',
2218
- '\'': '&#x27;'
2219
- }[str];
2220
- });
2221
- }
2222
- };
2223
- OutputTranslator = OutputTranslator_1 = __decorate([
2224
- Injectable()
2139
+ var OutputTranslator_1;
2140
+ /**
2141
+ * HTML 输出转换器
2142
+ */
2143
+ let OutputTranslator = OutputTranslator_1 = class OutputTranslator {
2144
+ constructor() {
2145
+ this.singleTagTest = new RegExp(`^(${OutputTranslator_1.singleTags.join('|')})$`, 'i');
2146
+ }
2147
+ transform(vDom) {
2148
+ return vDom.children.map(child => {
2149
+ return this.vDomToHTMLString(child);
2150
+ }).join('');
2151
+ }
2152
+ vDomToHTMLString(vDom) {
2153
+ const xssFilter = OutputTranslator_1.simpleXSSFilter;
2154
+ if (vDom instanceof VTextNode) {
2155
+ return this.replaceEmpty(xssFilter.text(vDom.textContent), '&nbsp;');
2156
+ }
2157
+ const styles = Array.from(vDom.styles.keys()).filter(key => {
2158
+ const v = vDom.styles.get(key);
2159
+ return !(v === undefined || v === null || v === '');
2160
+ }).map(key => {
2161
+ const k = key.replace(/(?=[A-Z])/g, '-').toLowerCase();
2162
+ return xssFilter.attrValue(`${k}:${vDom.styles.get(key)}`);
2163
+ }).join(';');
2164
+ const attrs = Array.from(vDom.attrs.keys()).filter(key => key !== 'ref' && vDom.attrs.get(key) !== false).map(k => {
2165
+ const key = xssFilter.attrName(k);
2166
+ const value = vDom.attrs.get(k);
2167
+ return (value === true ? `${key}` : `${key}="${xssFilter.attrValue(`${value}`)}"`);
2168
+ });
2169
+ if (styles) {
2170
+ attrs.push(`style="${styles}"`);
2171
+ }
2172
+ if (vDom.classes && vDom.classes.size) {
2173
+ attrs.push(`class="${xssFilter.attrValue(Array.from(vDom.classes).join(' '))}"`);
2174
+ }
2175
+ let attrStr = attrs.join(' ');
2176
+ attrStr = attrStr ? ' ' + attrStr : '';
2177
+ if (this.singleTagTest.test(vDom.tagName)) {
2178
+ return `<${vDom.tagName}${attrStr}>`;
2179
+ }
2180
+ const childHTML = vDom.children.map(child => {
2181
+ return this.vDomToHTMLString(child);
2182
+ }).join('');
2183
+ return [
2184
+ `<${vDom.tagName}${attrStr}>`,
2185
+ childHTML,
2186
+ `</${vDom.tagName}>`
2187
+ ].join('');
2188
+ }
2189
+ replaceEmpty(s, target) {
2190
+ return s.replace(/\s\s+/g, str => {
2191
+ return ' ' + Array.from({
2192
+ length: str.length - 1
2193
+ }).fill(target).join('');
2194
+ }).replace(/^\s|\s$/g, target);
2195
+ }
2196
+ };
2197
+ OutputTranslator.singleTags = 'br,img,hr'.split(',');
2198
+ OutputTranslator.simpleXSSFilter = {
2199
+ text(text) {
2200
+ return text.replace(/[><&]/g, str => {
2201
+ return {
2202
+ '<': '&lt;',
2203
+ '>': '&gt;',
2204
+ '&': '&amp;'
2205
+ }[str];
2206
+ });
2207
+ },
2208
+ attrName(text) {
2209
+ return text.replace(/[><"'&]/g, str => {
2210
+ return {
2211
+ '<': '&lt;',
2212
+ '>': '&gt;',
2213
+ '"': '&quot;',
2214
+ '\'': '&#x27;',
2215
+ '&': '&amp;'
2216
+ }[str];
2217
+ });
2218
+ },
2219
+ attrValue(text) {
2220
+ return text.replace(/["']/g, str => {
2221
+ return {
2222
+ '"': '&quot;',
2223
+ '\'': '&#x27;'
2224
+ }[str];
2225
+ });
2226
+ }
2227
+ };
2228
+ OutputTranslator = OutputTranslator_1 = __decorate([
2229
+ Injectable()
2225
2230
  ], OutputTranslator);
2226
2231
 
2227
- const editorError = makeError('CoreEditor');
2228
- /**
2229
- * Textbus PC 端编辑器
2230
- */
2231
- class Viewer extends Starter {
2232
- get readonly() {
2233
- return this.controller.readonly;
2234
- }
2235
- set readonly(b) {
2236
- this.controller.readonly = b;
2237
- }
2238
- isFocus() {
2239
- return this._isFocus;
2240
- }
2241
- constructor(rootComponent, rootComponentLoader, options = {}) {
2242
- const id = 'textbus-' + Number((Math.random() + '').substring(2)).toString(16);
2243
- const { doc, mask, wrapper } = Viewer.createLayout(id, options.minHeight);
2244
- const staticProviders = [{
2245
- provide: EDITOR_OPTIONS,
2246
- useValue: options
2247
- }, {
2248
- provide: VIEW_CONTAINER,
2249
- useValue: wrapper
2250
- }, {
2251
- provide: VIEW_DOCUMENT,
2252
- useValue: doc
2253
- }, {
2254
- provide: VIEW_MASK,
2255
- useValue: mask
2256
- }, {
2257
- provide: NativeRenderer,
2258
- useExisting: DomRenderer
2259
- }, {
2260
- provide: NativeSelectionBridge,
2261
- useExisting: SelectionBridge
2262
- }, {
2263
- provide: Input,
2264
- useClass: options.useContentEditable ? NativeInput : MagicInput
2265
- }, {
2266
- provide: Viewer,
2267
- useFactory: () => this
2268
- }];
2269
- super(Object.assign(Object.assign({}, options), { plugins: options.plugins || [], providers: [
2270
- ...(options.providers || []),
2271
- ...staticProviders,
2272
- DomRenderer,
2273
- Parser,
2274
- SelectionBridge,
2275
- OutputTranslator,
2276
- CollaborateCursor
2277
- ], setup: options.setup }));
2278
- this.rootComponent = rootComponent;
2279
- this.rootComponentLoader = rootComponentLoader;
2280
- this.options = options;
2281
- /** 编辑器是否已销毁 */
2282
- this.destroyed = false;
2283
- /** 编辑器是否已准备好 */
2284
- this.isReady = false;
2285
- this.changeEvent = new Subject();
2286
- this.subs = [];
2287
- this._isFocus = false;
2288
- this.resourceNodes = [];
2289
- this.focusEvent = new Subject();
2290
- this.blurEvent = new Subject();
2291
- this.saveEvent = new Subject();
2292
- this.styleSheet = '';
2293
- this.scripts = [];
2294
- this.links = [];
2295
- this.id = id;
2296
- this.workbench = wrapper;
2297
- this.onChange = this.changeEvent.asObservable();
2298
- this.onFocus = this.focusEvent.asObservable();
2299
- this.onBlur = this.blurEvent.asObservable();
2300
- this.onSave = this.saveEvent.asObservable();
2301
- this.controller = this.get(Controller);
2302
- }
2303
- /**
2304
- * 初始化编辑器
2305
- * @param host 编辑器容器
2306
- */
2307
- mount(host) {
2308
- const _super = Object.create(null, {
2309
- mount: { get: () => super.mount }
2310
- });
2311
- return __awaiter(this, void 0, void 0, function* () {
2312
- if (this.destroyed) {
2313
- throw editorError('the editor instance is destroyed!');
2314
- }
2315
- if (this.destroyed) {
2316
- return this;
2317
- }
2318
- const parser = this.get(Parser);
2319
- const registry = this.get(Registry);
2320
- const doc = this.get(VIEW_DOCUMENT);
2321
- this.initDefaultShortcut();
2322
- let component;
2323
- const content = this.options.content;
2324
- if (content) {
2325
- if (typeof content === 'string') {
2326
- component = parser.parseDoc(content, this.rootComponentLoader);
2327
- }
2328
- else {
2329
- component = registry.createComponentByFactory(content, this.rootComponent);
2330
- }
2331
- }
2332
- else {
2333
- component = this.rootComponent.createInstance(this);
2334
- }
2335
- this.initDocStyleSheetsAndScripts(this.options);
2336
- host.appendChild(this.workbench);
2337
- yield _super.mount.call(this, doc, component);
2338
- const renderer = this.get(Renderer);
2339
- const input = this.get(Input);
2340
- this.subs.push(renderer.onViewUpdated.subscribe(() => {
2341
- this.changeEvent.next();
2342
- }), input.caret.onPositionChange.pipe(map(p => !!p), distinctUntilChanged()).subscribe(b => {
2343
- if (b) {
2344
- this._isFocus = true;
2345
- this.focusEvent.next();
2346
- }
2347
- else {
2348
- this._isFocus = false;
2349
- this.blurEvent.next();
2350
- }
2351
- }));
2352
- this.isReady = true;
2353
- if (this.options.autoFocus) {
2354
- input.onReady.then(() => {
2355
- this.focus();
2356
- });
2357
- }
2358
- return this;
2359
- });
2360
- }
2361
- /**
2362
- * 获取焦点
2363
- */
2364
- focus() {
2365
- this.guardReady();
2366
- const selection = this.get(Selection);
2367
- const rootComponentRef = this.get(RootComponentRef);
2368
- if (selection.commonAncestorSlot) {
2369
- selection.restore();
2370
- return;
2371
- }
2372
- const location = selection.findFirstPosition(rootComponentRef.component.slots.get(0));
2373
- selection.setPosition(location.slot, location.offset);
2374
- selection.restore();
2375
- }
2376
- /**
2377
- * 取消编辑器焦点
2378
- */
2379
- blur() {
2380
- if (this.isReady) {
2381
- const selection = this.get(Selection);
2382
- selection.unSelect();
2383
- selection.restore();
2384
- }
2385
- }
2386
- /**
2387
- * 获取编辑器所有资源
2388
- */
2389
- getResources() {
2390
- var _a;
2391
- return {
2392
- styleSheets: ((_a = this.options) === null || _a === void 0 ? void 0 : _a.styleSheets) || [],
2393
- styleSheet: this.styleSheet,
2394
- links: this.links,
2395
- scripts: this.scripts
2396
- };
2397
- }
2398
- /**
2399
- * 获取 HTML 格式的内容
2400
- */
2401
- getHTML() {
2402
- this.guardReady();
2403
- const outputRenderer = this.get(OutputRenderer);
2404
- const outputTranslator = this.get(OutputTranslator);
2405
- const vDom = outputRenderer.render();
2406
- return outputTranslator.transform(vDom);
2407
- }
2408
- /**
2409
- * 获取 JSON 格式的内容
2410
- */
2411
- getJSON() {
2412
- this.guardReady();
2413
- const rootComponentRef = this.get(RootComponentRef);
2414
- return rootComponentRef.component.toJSON();
2415
- }
2416
- /**
2417
- * 销毁编辑器
2418
- */
2419
- destroy() {
2420
- var _a;
2421
- if (this.destroyed) {
2422
- return;
2423
- }
2424
- this.destroyed = true;
2425
- this.subs.forEach(i => i.unsubscribe());
2426
- const types = [
2427
- Input
2428
- ];
2429
- types.forEach(i => {
2430
- this.get(i).destroy();
2431
- });
2432
- super.destroy();
2433
- (_a = this.workbench.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.workbench);
2434
- this.resourceNodes.forEach(node => {
2435
- var _a;
2436
- (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
2437
- });
2438
- }
2439
- /**
2440
- * 替换编辑的内容
2441
- * @param content
2442
- */
2443
- replaceContent(content) {
2444
- this.guardReady();
2445
- const parser = this.get(Parser);
2446
- const registry = this.get(Registry);
2447
- const rootComponentRef = this.get(RootComponentRef);
2448
- const selection = this.get(Selection);
2449
- const rootComponentLoader = this.rootComponentLoader;
2450
- let component;
2451
- if (typeof content === 'string') {
2452
- component = parser.parseDoc(content, rootComponentLoader);
2453
- }
2454
- else {
2455
- component = registry.createComponentByFactory(content, this.rootComponent);
2456
- }
2457
- selection.unSelect();
2458
- rootComponentRef.component.slots.clean();
2459
- rootComponentRef.component.slots.push(...component.slots.toArray());
2460
- invokeListener(component, 'onDestroy');
2461
- }
2462
- guardReady() {
2463
- if (this.destroyed) {
2464
- throw editorError('the editor instance is destroyed!');
2465
- }
2466
- if (!this.isReady) {
2467
- throw editorError('please wait for the editor to initialize before getting the content!');
2468
- }
2469
- }
2470
- initDefaultShortcut() {
2471
- const selection = this.get(Selection);
2472
- const keyboard = this.get(Keyboard);
2473
- const history = this.get(History);
2474
- const commander = this.get(Commander);
2475
- keyboard.addShortcut({
2476
- keymap: {
2477
- key: 's',
2478
- ctrlKey: true
2479
- },
2480
- action: () => {
2481
- this.saveEvent.next();
2482
- }
2483
- });
2484
- keyboard.addShortcut({
2485
- keymap: {
2486
- key: 'Enter'
2487
- },
2488
- action: () => {
2489
- commander.break();
2490
- }
2491
- });
2492
- keyboard.addShortcut({
2493
- keymap: {
2494
- key: 'Enter',
2495
- shiftKey: true
2496
- },
2497
- action: () => {
2498
- const startOffset = selection.startOffset;
2499
- const startSlot = selection.startSlot;
2500
- const isToEnd = startOffset === startSlot.length || startSlot.isEmpty;
2501
- const content = isToEnd ? '\n\n' : '\n';
2502
- const isInserted = commander.insert(content);
2503
- if (isInserted && isToEnd) {
2504
- selection.setPosition(startSlot, startOffset + 1);
2505
- }
2506
- }
2507
- });
2508
- keyboard.addShortcut({
2509
- keymap: {
2510
- key: ['Delete', 'Backspace']
2511
- },
2512
- action: (key) => {
2513
- commander.delete(key === 'Backspace');
2514
- }
2515
- });
2516
- keyboard.addShortcut({
2517
- keymap: {
2518
- key: ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']
2519
- },
2520
- action: (key) => {
2521
- switch (key) {
2522
- case 'ArrowLeft':
2523
- selection.toPrevious();
2524
- break;
2525
- case 'ArrowRight':
2526
- selection.toNext();
2527
- break;
2528
- case 'ArrowUp':
2529
- selection.toPreviousLine();
2530
- break;
2531
- case 'ArrowDown':
2532
- selection.toNextLine();
2533
- break;
2534
- }
2535
- }
2536
- });
2537
- keyboard.addShortcut({
2538
- keymap: {
2539
- key: ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'],
2540
- shiftKey: true
2541
- },
2542
- action: (key) => {
2543
- switch (key) {
2544
- case 'ArrowLeft':
2545
- selection.wrapToBefore();
2546
- break;
2547
- case 'ArrowRight':
2548
- selection.wrapToAfter();
2549
- break;
2550
- case 'ArrowUp':
2551
- selection.wrapToPreviousLine();
2552
- break;
2553
- case 'ArrowDown':
2554
- selection.wrapToNextLine();
2555
- break;
2556
- }
2557
- }
2558
- });
2559
- keyboard.addShortcut({
2560
- keymap: {
2561
- key: 'Tab'
2562
- },
2563
- action: () => {
2564
- commander.insert(' ');
2565
- }
2566
- });
2567
- keyboard.addShortcut({
2568
- keymap: {
2569
- key: 'a',
2570
- ctrlKey: true
2571
- },
2572
- action: () => {
2573
- selection.selectAll();
2574
- }
2575
- });
2576
- keyboard.addShortcut({
2577
- keymap: {
2578
- key: 'c',
2579
- ctrlKey: true
2580
- },
2581
- action: () => {
2582
- commander.copy();
2583
- }
2584
- });
2585
- keyboard.addShortcut({
2586
- keymap: {
2587
- key: 'x',
2588
- ctrlKey: true
2589
- },
2590
- action: () => {
2591
- commander.cut();
2592
- }
2593
- });
2594
- keyboard.addShortcut({
2595
- keymap: {
2596
- key: 'z',
2597
- ctrlKey: true
2598
- },
2599
- action: () => {
2600
- history.back();
2601
- }
2602
- });
2603
- keyboard.addShortcut({
2604
- keymap: {
2605
- key: 'z',
2606
- ctrlKey: true,
2607
- shiftKey: true
2608
- },
2609
- action: () => {
2610
- history.forward();
2611
- }
2612
- });
2613
- }
2614
- initDocStyleSheetsAndScripts(options) {
2615
- var _a;
2616
- const loaders = [];
2617
- (_a = options.imports) === null || _a === void 0 ? void 0 : _a.forEach(module => {
2618
- loaders.push(...(module.componentLoaders || []));
2619
- });
2620
- loaders.push(...(options.componentLoaders || []));
2621
- const resources = loaders.filter(i => i.resources).map(i => i.resources);
2622
- const docStyles = [];
2623
- const editModeStyles = [];
2624
- resources.forEach(metadata => {
2625
- var _a, _b;
2626
- if (Array.isArray(metadata.links)) {
2627
- this.links.push(...metadata.links);
2628
- }
2629
- docStyles.push(((_a = metadata.styles) === null || _a === void 0 ? void 0 : _a.join('')) || '');
2630
- editModeStyles.push(((_b = metadata.editModeStyles) === null || _b === void 0 ? void 0 : _b.join('')) || '');
2631
- });
2632
- this.links.forEach(link => {
2633
- const linkEle = document.createElement('link');
2634
- Object.assign(linkEle, link);
2635
- this.resourceNodes.push(linkEle);
2636
- document.head.appendChild(linkEle);
2637
- });
2638
- const styleEl = document.createElement('style');
2639
- docStyles.push(...(options.styleSheets || []));
2640
- editModeStyles.push(`#${this.id} *::selection{background-color: rgba(18, 150, 219, .4); color:inherit}`, ...(options.editingStyleSheets || []));
2641
- this.styleSheet = Viewer.cssMin(docStyles.join(''));
2642
- styleEl.innerHTML = this.styleSheet + Viewer.cssMin(editModeStyles.join(''));
2643
- this.resourceNodes.push(styleEl);
2644
- document.head.append(styleEl);
2645
- resources.filter(i => { var _a; return (_a = i.scripts) === null || _a === void 0 ? void 0 : _a.length; }).map(i => i.scripts).flat().forEach(src => {
2646
- if (src) {
2647
- const script = document.createElement('script');
2648
- script.src = src;
2649
- this.scripts.push(src);
2650
- document.head.appendChild(script);
2651
- this.resourceNodes.push(script);
2652
- }
2653
- });
2654
- }
2655
- static createLayout(id, minHeight = '100%') {
2656
- const doc = createElement('div', {
2657
- styles: {
2658
- cursor: 'text',
2659
- wordBreak: 'break-all',
2660
- boxSizing: 'border-box',
2661
- minHeight,
2662
- flex: 1,
2663
- outline: 'none'
2664
- },
2665
- attrs: {
2666
- 'data-textbus-view': VIEW_DOCUMENT,
2667
- },
2668
- props: {
2669
- id
2670
- }
2671
- });
2672
- const mask = createElement('div', {
2673
- attrs: {
2674
- 'data-textbus-view': VIEW_MASK,
2675
- },
2676
- styles: {
2677
- position: 'absolute',
2678
- left: 0,
2679
- right: 0,
2680
- top: 0,
2681
- bottom: 0,
2682
- zIndex: 1,
2683
- pointerEvents: 'none',
2684
- overflow: 'hidden'
2685
- }
2686
- });
2687
- const wrapper = createElement('div', {
2688
- attrs: {
2689
- 'data-textbus-view': VIEW_CONTAINER,
2690
- },
2691
- styles: {
2692
- display: 'flex',
2693
- minHeight: '100%',
2694
- position: 'relative',
2695
- flexDirection: 'column'
2696
- },
2697
- children: [doc, mask]
2698
- });
2699
- return {
2700
- wrapper,
2701
- doc,
2702
- mask
2703
- };
2704
- }
2705
- static cssMin(str) {
2706
- return str
2707
- .replace(/\s*(?=[>{}:;,[])/g, '')
2708
- .replace(/([>{}:;,])\s*/g, '$1')
2709
- .replace(/;}/g, '}').replace(/\s+/, ' ').trim();
2710
- }
2232
+ const editorError = makeError('CoreEditor');
2233
+ /**
2234
+ * Textbus PC 端编辑器
2235
+ */
2236
+ class Viewer extends Starter {
2237
+ get readonly() {
2238
+ return this.controller.readonly;
2239
+ }
2240
+ set readonly(b) {
2241
+ this.controller.readonly = b;
2242
+ }
2243
+ isFocus() {
2244
+ return this._isFocus;
2245
+ }
2246
+ constructor(rootComponent, rootComponentLoader, options = {}) {
2247
+ const id = 'textbus-' + Number((Math.random() + '').substring(2)).toString(16);
2248
+ const { doc, mask, wrapper } = Viewer.createLayout(id, options.minHeight);
2249
+ const staticProviders = [{
2250
+ provide: EDITOR_OPTIONS,
2251
+ useValue: options
2252
+ }, {
2253
+ provide: VIEW_CONTAINER,
2254
+ useValue: wrapper
2255
+ }, {
2256
+ provide: VIEW_DOCUMENT,
2257
+ useValue: doc
2258
+ }, {
2259
+ provide: VIEW_MASK,
2260
+ useValue: mask
2261
+ }, {
2262
+ provide: NativeRenderer,
2263
+ useExisting: DomRenderer
2264
+ }, {
2265
+ provide: NativeSelectionBridge,
2266
+ useExisting: SelectionBridge
2267
+ }, {
2268
+ provide: Input,
2269
+ useClass: options.useContentEditable ? NativeInput : MagicInput
2270
+ }, {
2271
+ provide: Viewer,
2272
+ useFactory: () => this
2273
+ }];
2274
+ super(Object.assign(Object.assign({}, options), { plugins: options.plugins || [], providers: [
2275
+ ...(options.providers || []),
2276
+ ...staticProviders,
2277
+ DomRenderer,
2278
+ Parser,
2279
+ SelectionBridge,
2280
+ OutputTranslator,
2281
+ CollaborateCursor
2282
+ ], setup: options.setup }));
2283
+ this.rootComponent = rootComponent;
2284
+ this.rootComponentLoader = rootComponentLoader;
2285
+ this.options = options;
2286
+ /** 编辑器是否已销毁 */
2287
+ this.destroyed = false;
2288
+ /** 编辑器是否已准备好 */
2289
+ this.isReady = false;
2290
+ this.changeEvent = new Subject();
2291
+ this.subs = [];
2292
+ this._isFocus = false;
2293
+ this.resourceNodes = [];
2294
+ this.focusEvent = new Subject();
2295
+ this.blurEvent = new Subject();
2296
+ this.saveEvent = new Subject();
2297
+ this.styleSheet = '';
2298
+ this.scripts = [];
2299
+ this.links = [];
2300
+ this.id = id;
2301
+ this.workbench = wrapper;
2302
+ this.onChange = this.changeEvent.asObservable();
2303
+ this.onFocus = this.focusEvent.asObservable();
2304
+ this.onBlur = this.blurEvent.asObservable();
2305
+ this.onSave = this.saveEvent.asObservable();
2306
+ this.controller = this.get(Controller);
2307
+ }
2308
+ /**
2309
+ * 初始化编辑器
2310
+ * @param host 编辑器容器
2311
+ */
2312
+ mount(host) {
2313
+ const _super = Object.create(null, {
2314
+ mount: { get: () => super.mount }
2315
+ });
2316
+ return __awaiter(this, void 0, void 0, function* () {
2317
+ if (this.destroyed) {
2318
+ throw editorError('the editor instance is destroyed!');
2319
+ }
2320
+ if (this.destroyed) {
2321
+ return this;
2322
+ }
2323
+ const parser = this.get(Parser);
2324
+ const registry = this.get(Registry);
2325
+ const doc = this.get(VIEW_DOCUMENT);
2326
+ this.initDefaultShortcut();
2327
+ let component;
2328
+ const content = this.options.content;
2329
+ if (content) {
2330
+ if (typeof content === 'string') {
2331
+ component = parser.parseDoc(content, this.rootComponentLoader);
2332
+ }
2333
+ else {
2334
+ component = registry.createComponentByFactory(content, this.rootComponent);
2335
+ }
2336
+ }
2337
+ else {
2338
+ component = this.rootComponent.createInstance(this);
2339
+ }
2340
+ this.initDocStyleSheetsAndScripts(this.options);
2341
+ host.appendChild(this.workbench);
2342
+ yield _super.mount.call(this, doc, component);
2343
+ const renderer = this.get(Renderer);
2344
+ const input = this.get(Input);
2345
+ this.subs.push(renderer.onViewUpdated.subscribe(() => {
2346
+ this.changeEvent.next();
2347
+ }), input.caret.onPositionChange.pipe(map(p => !!p), distinctUntilChanged()).subscribe(b => {
2348
+ if (b) {
2349
+ this._isFocus = true;
2350
+ this.focusEvent.next();
2351
+ }
2352
+ else {
2353
+ this._isFocus = false;
2354
+ this.blurEvent.next();
2355
+ }
2356
+ }));
2357
+ this.isReady = true;
2358
+ if (this.options.autoFocus) {
2359
+ input.onReady.then(() => {
2360
+ this.focus();
2361
+ });
2362
+ }
2363
+ return this;
2364
+ });
2365
+ }
2366
+ /**
2367
+ * 获取焦点
2368
+ */
2369
+ focus() {
2370
+ this.guardReady();
2371
+ const selection = this.get(Selection);
2372
+ const rootComponentRef = this.get(RootComponentRef);
2373
+ if (selection.commonAncestorSlot) {
2374
+ selection.restore();
2375
+ return;
2376
+ }
2377
+ const location = selection.findFirstPosition(rootComponentRef.component.slots.get(0));
2378
+ selection.setPosition(location.slot, location.offset);
2379
+ selection.restore();
2380
+ }
2381
+ /**
2382
+ * 取消编辑器焦点
2383
+ */
2384
+ blur() {
2385
+ if (this.isReady) {
2386
+ const selection = this.get(Selection);
2387
+ selection.unSelect();
2388
+ selection.restore();
2389
+ }
2390
+ }
2391
+ /**
2392
+ * 获取编辑器所有资源
2393
+ */
2394
+ getResources() {
2395
+ var _a;
2396
+ return {
2397
+ styleSheets: ((_a = this.options) === null || _a === void 0 ? void 0 : _a.styleSheets) || [],
2398
+ styleSheet: this.styleSheet,
2399
+ links: this.links,
2400
+ scripts: this.scripts
2401
+ };
2402
+ }
2403
+ /**
2404
+ * 获取 HTML 格式的内容
2405
+ */
2406
+ getHTML() {
2407
+ this.guardReady();
2408
+ const outputRenderer = this.get(OutputRenderer);
2409
+ const outputTranslator = this.get(OutputTranslator);
2410
+ const vDom = outputRenderer.render();
2411
+ return outputTranslator.transform(vDom);
2412
+ }
2413
+ /**
2414
+ * 获取 JSON 格式的内容
2415
+ */
2416
+ getJSON() {
2417
+ this.guardReady();
2418
+ const rootComponentRef = this.get(RootComponentRef);
2419
+ return rootComponentRef.component.toJSON();
2420
+ }
2421
+ /**
2422
+ * 销毁编辑器
2423
+ */
2424
+ destroy() {
2425
+ var _a;
2426
+ if (this.destroyed) {
2427
+ return;
2428
+ }
2429
+ this.destroyed = true;
2430
+ this.subs.forEach(i => i.unsubscribe());
2431
+ const types = [
2432
+ Input
2433
+ ];
2434
+ types.forEach(i => {
2435
+ this.get(i).destroy();
2436
+ });
2437
+ super.destroy();
2438
+ (_a = this.workbench.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.workbench);
2439
+ this.resourceNodes.forEach(node => {
2440
+ var _a;
2441
+ (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
2442
+ });
2443
+ }
2444
+ /**
2445
+ * 替换编辑的内容
2446
+ * @param content
2447
+ */
2448
+ replaceContent(content) {
2449
+ this.guardReady();
2450
+ const parser = this.get(Parser);
2451
+ const registry = this.get(Registry);
2452
+ const rootComponentRef = this.get(RootComponentRef);
2453
+ const selection = this.get(Selection);
2454
+ const rootComponentLoader = this.rootComponentLoader;
2455
+ let component;
2456
+ if (typeof content === 'string') {
2457
+ component = parser.parseDoc(content, rootComponentLoader);
2458
+ }
2459
+ else {
2460
+ component = registry.createComponentByFactory(content, this.rootComponent);
2461
+ }
2462
+ selection.unSelect();
2463
+ rootComponentRef.component.slots.clean();
2464
+ rootComponentRef.component.slots.push(...component.slots.toArray());
2465
+ invokeListener(component, 'onDestroy');
2466
+ }
2467
+ guardReady() {
2468
+ if (this.destroyed) {
2469
+ throw editorError('the editor instance is destroyed!');
2470
+ }
2471
+ if (!this.isReady) {
2472
+ throw editorError('please wait for the editor to initialize before getting the content!');
2473
+ }
2474
+ }
2475
+ initDefaultShortcut() {
2476
+ const selection = this.get(Selection);
2477
+ const keyboard = this.get(Keyboard);
2478
+ const history = this.get(History);
2479
+ const commander = this.get(Commander);
2480
+ keyboard.addShortcut({
2481
+ keymap: {
2482
+ key: 's',
2483
+ ctrlKey: true
2484
+ },
2485
+ action: () => {
2486
+ this.saveEvent.next();
2487
+ }
2488
+ });
2489
+ keyboard.addShortcut({
2490
+ keymap: {
2491
+ key: 'Enter'
2492
+ },
2493
+ action: () => {
2494
+ commander.break();
2495
+ }
2496
+ });
2497
+ keyboard.addShortcut({
2498
+ keymap: {
2499
+ key: 'Enter',
2500
+ shiftKey: true
2501
+ },
2502
+ action: () => {
2503
+ const startOffset = selection.startOffset;
2504
+ const startSlot = selection.startSlot;
2505
+ const isToEnd = startOffset === startSlot.length || startSlot.isEmpty;
2506
+ const content = isToEnd ? '\n\n' : '\n';
2507
+ const isInserted = commander.insert(content);
2508
+ if (isInserted && isToEnd) {
2509
+ selection.setPosition(startSlot, startOffset + 1);
2510
+ }
2511
+ }
2512
+ });
2513
+ keyboard.addShortcut({
2514
+ keymap: {
2515
+ key: ['Delete', 'Backspace']
2516
+ },
2517
+ action: (key) => {
2518
+ commander.delete(key === 'Backspace');
2519
+ }
2520
+ });
2521
+ keyboard.addShortcut({
2522
+ keymap: {
2523
+ key: ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']
2524
+ },
2525
+ action: (key) => {
2526
+ switch (key) {
2527
+ case 'ArrowLeft':
2528
+ selection.toPrevious();
2529
+ break;
2530
+ case 'ArrowRight':
2531
+ selection.toNext();
2532
+ break;
2533
+ case 'ArrowUp':
2534
+ selection.toPreviousLine();
2535
+ break;
2536
+ case 'ArrowDown':
2537
+ selection.toNextLine();
2538
+ break;
2539
+ }
2540
+ }
2541
+ });
2542
+ keyboard.addShortcut({
2543
+ keymap: {
2544
+ key: ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'],
2545
+ shiftKey: true
2546
+ },
2547
+ action: (key) => {
2548
+ switch (key) {
2549
+ case 'ArrowLeft':
2550
+ selection.wrapToBefore();
2551
+ break;
2552
+ case 'ArrowRight':
2553
+ selection.wrapToAfter();
2554
+ break;
2555
+ case 'ArrowUp':
2556
+ selection.wrapToPreviousLine();
2557
+ break;
2558
+ case 'ArrowDown':
2559
+ selection.wrapToNextLine();
2560
+ break;
2561
+ }
2562
+ }
2563
+ });
2564
+ keyboard.addShortcut({
2565
+ keymap: {
2566
+ key: 'Tab'
2567
+ },
2568
+ action: () => {
2569
+ commander.insert(' ');
2570
+ }
2571
+ });
2572
+ keyboard.addShortcut({
2573
+ keymap: {
2574
+ key: 'a',
2575
+ ctrlKey: true
2576
+ },
2577
+ action: () => {
2578
+ selection.selectAll();
2579
+ }
2580
+ });
2581
+ keyboard.addShortcut({
2582
+ keymap: {
2583
+ key: 'c',
2584
+ ctrlKey: true
2585
+ },
2586
+ action: () => {
2587
+ commander.copy();
2588
+ }
2589
+ });
2590
+ keyboard.addShortcut({
2591
+ keymap: {
2592
+ key: 'x',
2593
+ ctrlKey: true
2594
+ },
2595
+ action: () => {
2596
+ commander.cut();
2597
+ }
2598
+ });
2599
+ keyboard.addShortcut({
2600
+ keymap: {
2601
+ key: 'z',
2602
+ ctrlKey: true
2603
+ },
2604
+ action: () => {
2605
+ history.back();
2606
+ }
2607
+ });
2608
+ keyboard.addShortcut({
2609
+ keymap: {
2610
+ key: 'z',
2611
+ ctrlKey: true,
2612
+ shiftKey: true
2613
+ },
2614
+ action: () => {
2615
+ history.forward();
2616
+ }
2617
+ });
2618
+ }
2619
+ initDocStyleSheetsAndScripts(options) {
2620
+ var _a;
2621
+ const loaders = [];
2622
+ (_a = options.imports) === null || _a === void 0 ? void 0 : _a.forEach(module => {
2623
+ loaders.push(...(module.componentLoaders || []));
2624
+ });
2625
+ loaders.push(...(options.componentLoaders || []));
2626
+ const resources = loaders.filter(i => i.resources).map(i => i.resources);
2627
+ const docStyles = [];
2628
+ const editModeStyles = [];
2629
+ resources.forEach(metadata => {
2630
+ var _a, _b;
2631
+ if (Array.isArray(metadata.links)) {
2632
+ this.links.push(...metadata.links);
2633
+ }
2634
+ docStyles.push(((_a = metadata.styles) === null || _a === void 0 ? void 0 : _a.join('')) || '');
2635
+ editModeStyles.push(((_b = metadata.editModeStyles) === null || _b === void 0 ? void 0 : _b.join('')) || '');
2636
+ });
2637
+ this.links.forEach(link => {
2638
+ const linkEle = document.createElement('link');
2639
+ Object.assign(linkEle, link);
2640
+ this.resourceNodes.push(linkEle);
2641
+ document.head.appendChild(linkEle);
2642
+ });
2643
+ const styleEl = document.createElement('style');
2644
+ docStyles.push(...(options.styleSheets || []));
2645
+ editModeStyles.push(`#${this.id} *::selection{background-color: rgba(18, 150, 219, .4); color:inherit}`, ...(options.editingStyleSheets || []));
2646
+ this.styleSheet = Viewer.cssMin(docStyles.join(''));
2647
+ styleEl.innerHTML = this.styleSheet + Viewer.cssMin(editModeStyles.join(''));
2648
+ this.resourceNodes.push(styleEl);
2649
+ document.head.append(styleEl);
2650
+ resources.filter(i => { var _a; return (_a = i.scripts) === null || _a === void 0 ? void 0 : _a.length; }).map(i => i.scripts).flat().forEach(src => {
2651
+ if (src) {
2652
+ const script = document.createElement('script');
2653
+ script.src = src;
2654
+ this.scripts.push(src);
2655
+ document.head.appendChild(script);
2656
+ this.resourceNodes.push(script);
2657
+ }
2658
+ });
2659
+ }
2660
+ static createLayout(id, minHeight = '100%') {
2661
+ const doc = createElement('div', {
2662
+ styles: {
2663
+ cursor: 'text',
2664
+ wordBreak: 'break-all',
2665
+ boxSizing: 'border-box',
2666
+ minHeight,
2667
+ flex: 1,
2668
+ outline: 'none'
2669
+ },
2670
+ attrs: {
2671
+ 'data-textbus-view': VIEW_DOCUMENT,
2672
+ },
2673
+ props: {
2674
+ id
2675
+ }
2676
+ });
2677
+ const mask = createElement('div', {
2678
+ attrs: {
2679
+ 'data-textbus-view': VIEW_MASK,
2680
+ },
2681
+ styles: {
2682
+ position: 'absolute',
2683
+ left: 0,
2684
+ right: 0,
2685
+ top: 0,
2686
+ bottom: 0,
2687
+ zIndex: 1,
2688
+ pointerEvents: 'none',
2689
+ overflow: 'hidden'
2690
+ }
2691
+ });
2692
+ const wrapper = createElement('div', {
2693
+ attrs: {
2694
+ 'data-textbus-view': VIEW_CONTAINER,
2695
+ },
2696
+ styles: {
2697
+ display: 'flex',
2698
+ minHeight: '100%',
2699
+ position: 'relative',
2700
+ flexDirection: 'column'
2701
+ },
2702
+ children: [doc, mask]
2703
+ });
2704
+ return {
2705
+ wrapper,
2706
+ doc,
2707
+ mask
2708
+ };
2709
+ }
2710
+ static cssMin(str) {
2711
+ return str
2712
+ .replace(/\s*(?=[>{}:;,[])/g, '')
2713
+ .replace(/([>{}:;,])\s*/g, '$1')
2714
+ .replace(/;}/g, '}').replace(/\s+/, ' ').trim();
2715
+ }
2711
2716
  }
2712
2717
 
2713
2718
  export { CollaborateCursor, CollaborateSelectionAwarenessDelegate, DomRenderer, EDITOR_OPTIONS, Input, MagicInput, NativeInput, OutputTranslator, Parser, SelectionBridge, VIEW_CONTAINER, VIEW_DOCUMENT, VIEW_MASK, Viewer, createElement, createTextNode, getLayoutRectByRange, isMac, isSafari, isWindows };