@textbus/platform-browser 3.0.0-alpha.33 → 3.0.0-alpha.34

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