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