@textbus/platform-browser 5.1.6 → 5.2.1

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 DELETED
@@ -1,2925 +0,0 @@
1
- 'use strict';
2
-
3
- require('reflect-metadata');
4
- var core$1 = require('@textbus/core');
5
- var stream = require('@tanbo/stream');
6
- var core = require('@viewfly/core');
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 getLayoutRectByRange(range) {
39
- let { startContainer, startOffset } = range;
40
- if (startContainer.nodeType === Node.TEXT_NODE) {
41
- if (startOffset > 0) {
42
- return range.getBoundingClientRect();
43
- }
44
- const parentNode = startContainer.parentNode;
45
- startOffset = Array.from(parentNode.childNodes).indexOf(startContainer);
46
- startContainer = parentNode;
47
- }
48
- const beforeNode = startContainer.childNodes[startOffset - 1];
49
- if (beforeNode) {
50
- if (beforeNode.nodeType === Node.ELEMENT_NODE && beforeNode.nodeName.toLowerCase() !== 'br') {
51
- const rect = beforeNode.getBoundingClientRect();
52
- return {
53
- left: rect.right,
54
- top: rect.top,
55
- width: range.collapsed ? 1 : rect.width,
56
- height: rect.height
57
- };
58
- }
59
- else if (beforeNode.nodeType === Node.TEXT_NODE) {
60
- const range2 = document.createRange();
61
- range2.setStart(beforeNode, beforeNode.textContent.length);
62
- range2.setEnd(beforeNode, beforeNode.textContent.length);
63
- const rect = range2.getBoundingClientRect();
64
- return {
65
- left: rect.right,
66
- top: rect.top,
67
- width: range.collapsed ? 1 : rect.width,
68
- height: rect.height
69
- };
70
- }
71
- }
72
- const offsetNode = startContainer.childNodes[startOffset];
73
- let isInsertBefore = false;
74
- if (!offsetNode) {
75
- const lastChild = startContainer.lastChild;
76
- if (lastChild && lastChild.nodeType === Node.ELEMENT_NODE) {
77
- const rect = lastChild.getBoundingClientRect();
78
- return {
79
- left: rect.right,
80
- top: rect.top,
81
- width: range.collapsed ? 1 : rect.width,
82
- height: rect.height
83
- };
84
- }
85
- }
86
- if (offsetNode) {
87
- if (offsetNode.nodeType === Node.ELEMENT_NODE && offsetNode.nodeName.toLowerCase() !== 'br') {
88
- const rect = offsetNode.getBoundingClientRect();
89
- return {
90
- left: rect.left,
91
- top: rect.top,
92
- width: range.collapsed ? 1 : rect.width,
93
- height: rect.height
94
- };
95
- }
96
- isInsertBefore = true;
97
- }
98
- const span = startContainer.ownerDocument.createElement('span');
99
- span.innerText = '\u200b';
100
- span.style.display = 'inline-block';
101
- if (isInsertBefore) {
102
- startContainer.insertBefore(span, offsetNode);
103
- }
104
- else {
105
- startContainer.appendChild(span);
106
- }
107
- const rect = span.getBoundingClientRect();
108
- startContainer.removeChild(span);
109
- return {
110
- left: rect.left,
111
- top: rect.top,
112
- width: range.collapsed ? 1 : rect.width,
113
- height: rect.height
114
- };
115
- }
116
-
117
- const isWindows = () => /win(dows|32|64)/i.test(navigator.userAgent);
118
- const isMac = () => /mac os/i.test(navigator.userAgent);
119
- const isSafari = () => /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
120
- const isFirefox = () => /Firefox/.test(navigator.userAgent);
121
- const isMobileBrowser = () => /Android|iPhone|iPad/.test(navigator.userAgent);
122
-
123
- /******************************************************************************
124
- Copyright (c) Microsoft Corporation.
125
-
126
- Permission to use, copy, modify, and/or distribute this software for any
127
- purpose with or without fee is hereby granted.
128
-
129
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
130
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
131
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
132
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
133
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
134
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
135
- PERFORMANCE OF THIS SOFTWARE.
136
- ***************************************************************************** */
137
- /* global Reflect, Promise, SuppressedError, Symbol */
138
-
139
-
140
- function __decorate(decorators, target, key, desc) {
141
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
142
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
143
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
144
- return c > 3 && r && Object.defineProperty(target, key, r), r;
145
- }
146
-
147
- function __param(paramIndex, decorator) {
148
- return function (target, key) { decorator(target, key, paramIndex); }
149
- }
150
-
151
- function __metadata(metadataKey, metadataValue) {
152
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
153
- }
154
-
155
- function __awaiter(thisArg, _arguments, P, generator) {
156
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
157
- return new (P || (P = Promise))(function (resolve, reject) {
158
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
159
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
160
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
161
- step((generator = generator.apply(thisArg, _arguments || [])).next());
162
- });
163
- }
164
-
165
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
166
- var e = new Error(message);
167
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
168
- };
169
-
170
- /**
171
- * 编辑器可选项依赖注入 token
172
- */
173
- const EDITOR_OPTIONS = new core.InjectionToken('EDITOR_OPTIONS');
174
- /**
175
- * 编辑器容器依赖注入 token
176
- */
177
- const VIEW_CONTAINER = new core.InjectionToken('VIEW_CONTAINER');
178
- /**
179
- * 编辑器容器依赖注入 token
180
- */
181
- const VIEW_DOCUMENT = new core.InjectionToken('VIEW_DOCUMENT');
182
- /**
183
- * 编辑器容器遮罩层 token
184
- */
185
- const VIEW_MASK = new core.InjectionToken('VIEW_MASK');
186
-
187
- var Parser_1;
188
- /**
189
- * 用于解析 HTML,并把 HTML 内容转换为 Textbus 可以支持的组件或插槽数据
190
- */
191
- exports.Parser = Parser_1 = class Parser {
192
- static parseHTML(html) {
193
- return new DOMParser().parseFromString(html, 'text/html').body;
194
- }
195
- constructor(options, textbus) {
196
- Object.defineProperty(this, "textbus", {
197
- enumerable: true,
198
- configurable: true,
199
- writable: true,
200
- value: textbus
201
- });
202
- Object.defineProperty(this, "componentLoaders", {
203
- enumerable: true,
204
- configurable: true,
205
- writable: true,
206
- value: void 0
207
- });
208
- Object.defineProperty(this, "formatLoaders", {
209
- enumerable: true,
210
- configurable: true,
211
- writable: true,
212
- value: void 0
213
- });
214
- Object.defineProperty(this, "attributeLoaders", {
215
- enumerable: true,
216
- configurable: true,
217
- writable: true,
218
- value: void 0
219
- });
220
- const componentLoaders = [
221
- ...(options.componentLoaders || [])
222
- ];
223
- const formatLoaders = [
224
- ...(options.formatLoaders || [])
225
- ];
226
- const attributeLoaders = [
227
- ...(options.attributeLoaders || [])
228
- ];
229
- // options.imports?.forEach(i => {
230
- // componentLoaders.push(...(i.componentLoaders || []))
231
- // formatLoaders.push(...(i.formatLoaders || []))
232
- // })
233
- this.componentLoaders = componentLoaders;
234
- this.formatLoaders = formatLoaders;
235
- this.attributeLoaders = attributeLoaders;
236
- }
237
- /**
238
- * 使用指定的组件加载器解析一段 HTML 字符串或 DOM 元素
239
- * @param html
240
- * @param rootComponentLoader
241
- */
242
- parseDoc(html, rootComponentLoader) {
243
- const element = typeof html === 'string' ? Parser_1.parseHTML(html) : html;
244
- return rootComponentLoader.read(element, this.textbus, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
245
- return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
246
- });
247
- }
248
- /**
249
- * 将一段 HTML 或 DOM 元素解析到指定插槽
250
- * @param html
251
- * @param rootSlot
252
- */
253
- parse(html, rootSlot) {
254
- const element = typeof html === 'string' ? Parser_1.parseHTML(html) : html;
255
- return this.readFormats(element, rootSlot);
256
- }
257
- readComponent(el, slot) {
258
- if (el.nodeType === Node.ELEMENT_NODE) {
259
- if (el.tagName === 'BR') {
260
- slot.insert('\n');
261
- return;
262
- }
263
- const schema = [...slot.schema];
264
- for (const t of this.componentLoaders) {
265
- if (t.match(el, schema)) {
266
- const result = t.read(el, this.textbus, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
267
- return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
268
- });
269
- if (!result) {
270
- return;
271
- }
272
- if (result instanceof core$1.Slot) {
273
- result.toDelta().forEach(i => slot.insert(i.insert, i.formats));
274
- return;
275
- }
276
- slot.insert(result);
277
- return;
278
- }
279
- }
280
- this.readFormats(el, slot);
281
- }
282
- else if (el.nodeType === Node.TEXT_NODE) {
283
- this.readText(slot, el);
284
- }
285
- }
286
- readText(slot, el) {
287
- const textContent = el.textContent;
288
- if (/^\s*[\r\n\u200b]+\s*$/.test(textContent)) {
289
- return;
290
- }
291
- slot.insert(textContent);
292
- }
293
- readFormats(el, slot) {
294
- const formats = this.formatLoaders.filter(f => {
295
- return f.match(el);
296
- }).map(f => {
297
- return f.read(el);
298
- });
299
- const startIndex = slot.index;
300
- let startNode = el.firstChild;
301
- while (startNode) {
302
- this.readComponent(startNode, slot);
303
- startNode = startNode.nextSibling;
304
- }
305
- const endIndex = slot.index;
306
- this.applyFormats(slot, formats.map(i => {
307
- return {
308
- formatter: i.formatter,
309
- value: i.value,
310
- startIndex,
311
- endIndex
312
- };
313
- }));
314
- slot.retain(endIndex);
315
- return slot;
316
- }
317
- readSlot(childSlot, slotRootElement, slotContentElement) {
318
- if (slotRootElement.nodeType === Node.ELEMENT_NODE) {
319
- this.attributeLoaders.filter(a => {
320
- return a.match(slotRootElement);
321
- }).forEach(a => {
322
- const r = a.read(slotRootElement);
323
- childSlot.setAttribute(r.attribute, r.value);
324
- });
325
- }
326
- if (slotContentElement.nodeType === Node.ELEMENT_NODE) {
327
- this.readFormats(slotContentElement, childSlot);
328
- }
329
- else {
330
- this.readText(childSlot, slotContentElement);
331
- }
332
- return childSlot;
333
- }
334
- applyFormats(slot, formatItems) {
335
- slot.background(() => {
336
- formatItems.forEach(i => {
337
- slot.retain(i.startIndex);
338
- slot.retain(i.endIndex - i.startIndex, i.formatter, i.value);
339
- });
340
- });
341
- }
342
- };
343
- exports.Parser = Parser_1 = __decorate([
344
- core.Injectable(),
345
- __param(0, core.Inject(EDITOR_OPTIONS)),
346
- __metadata("design:paramtypes", [Object, core$1.Textbus])
347
- ], exports.Parser);
348
-
349
- class Input {
350
- }
351
-
352
- class DomAdapter extends core$1.Adapter {
353
- constructor() {
354
- super(...arguments);
355
- Object.defineProperty(this, "onViewUpdated", {
356
- enumerable: true,
357
- configurable: true,
358
- writable: true,
359
- value: new stream.Subject()
360
- });
361
- Object.defineProperty(this, "host", {
362
- enumerable: true,
363
- configurable: true,
364
- writable: true,
365
- value: createElement('div', {
366
- styles: {
367
- cursor: 'text',
368
- wordBreak: 'break-all',
369
- boxSizing: 'border-box',
370
- flex: 1,
371
- outline: 'none'
372
- },
373
- attrs: {
374
- 'data-textbus-view': VIEW_DOCUMENT,
375
- },
376
- props: {
377
- id: 'textbus-' + Number((Math.random() + '').substring(2)).toString(16)
378
- }
379
- })
380
- });
381
- }
382
- }
383
-
384
- /**
385
- * Textbus PC 端选区桥接实现
386
- */
387
- exports.SelectionBridge = class SelectionBridge {
388
- constructor(config, textbus, controller, selection, rootComponentRef, input, scheduler, domAdapter) {
389
- Object.defineProperty(this, "config", {
390
- enumerable: true,
391
- configurable: true,
392
- writable: true,
393
- value: config
394
- });
395
- Object.defineProperty(this, "selection", {
396
- enumerable: true,
397
- configurable: true,
398
- writable: true,
399
- value: selection
400
- });
401
- Object.defineProperty(this, "rootComponentRef", {
402
- enumerable: true,
403
- configurable: true,
404
- writable: true,
405
- value: rootComponentRef
406
- });
407
- Object.defineProperty(this, "input", {
408
- enumerable: true,
409
- configurable: true,
410
- writable: true,
411
- value: input
412
- });
413
- Object.defineProperty(this, "scheduler", {
414
- enumerable: true,
415
- configurable: true,
416
- writable: true,
417
- value: scheduler
418
- });
419
- Object.defineProperty(this, "domAdapter", {
420
- enumerable: true,
421
- configurable: true,
422
- writable: true,
423
- value: domAdapter
424
- });
425
- Object.defineProperty(this, "onSelectionChange", {
426
- enumerable: true,
427
- configurable: true,
428
- writable: true,
429
- value: void 0
430
- });
431
- Object.defineProperty(this, "nativeSelection", {
432
- enumerable: true,
433
- configurable: true,
434
- writable: true,
435
- value: document.getSelection()
436
- });
437
- Object.defineProperty(this, "syncSelectionFromNativeSelectionChange", {
438
- enumerable: true,
439
- configurable: true,
440
- writable: true,
441
- value: true
442
- });
443
- Object.defineProperty(this, "selectionChangeEvent", {
444
- enumerable: true,
445
- configurable: true,
446
- writable: true,
447
- value: new stream.Subject()
448
- });
449
- Object.defineProperty(this, "subs", {
450
- enumerable: true,
451
- configurable: true,
452
- writable: true,
453
- value: []
454
- });
455
- Object.defineProperty(this, "sub", {
456
- enumerable: true,
457
- configurable: true,
458
- writable: true,
459
- value: void 0
460
- });
461
- Object.defineProperty(this, "connector", {
462
- enumerable: true,
463
- configurable: true,
464
- writable: true,
465
- value: null
466
- });
467
- Object.defineProperty(this, "ignoreSelectionChange", {
468
- enumerable: true,
469
- configurable: true,
470
- writable: true,
471
- value: false
472
- });
473
- Object.defineProperty(this, "changeFromUser", {
474
- enumerable: true,
475
- configurable: true,
476
- writable: true,
477
- value: false
478
- });
479
- Object.defineProperty(this, "docContainer", {
480
- enumerable: true,
481
- configurable: true,
482
- writable: true,
483
- value: void 0
484
- });
485
- Object.defineProperty(this, "cacheCaretPositionTimer", {
486
- enumerable: true,
487
- configurable: true,
488
- writable: true,
489
- value: void 0
490
- });
491
- Object.defineProperty(this, "oldCaretPosition", {
492
- enumerable: true,
493
- configurable: true,
494
- writable: true,
495
- value: void 0
496
- });
497
- this.docContainer = textbus.get(VIEW_DOCUMENT);
498
- this.onSelectionChange = this.selectionChangeEvent.asObservable().pipe(stream.filter(() => {
499
- return !controller.readonly;
500
- }));
501
- this.sub = this.onSelectionChange.subscribe((r) => {
502
- if (r) {
503
- input.focus(r, this.changeFromUser);
504
- }
505
- else {
506
- input.blur();
507
- }
508
- });
509
- this.sub.add(stream.fromEvent(document, 'focusin').subscribe(ev => {
510
- let target = ev.target;
511
- if (/^(input|textarea|select)$/i.test(target.nodeName)) {
512
- if (target.tagName.toLowerCase() === 'input' && /^(range|date)$/.test(target.type)) {
513
- return;
514
- }
515
- this.ignoreSelectionChange = true;
516
- return;
517
- }
518
- if (!config.useContentEditable) {
519
- while (target) {
520
- if (target.contentEditable === 'true') {
521
- this.ignoreSelectionChange = true;
522
- return;
523
- }
524
- target = target.parentNode;
525
- }
526
- }
527
- }));
528
- this.sub.add(stream.fromEvent(document, 'focusout').subscribe(() => {
529
- this.ignoreSelectionChange = false;
530
- }));
531
- }
532
- connect(connector) {
533
- this.disConnect();
534
- this.connector = connector;
535
- this.syncSelection(connector);
536
- this.listen(connector);
537
- }
538
- disConnect() {
539
- this.connector = null;
540
- this.unListen();
541
- }
542
- getRect(location) {
543
- const { focus, anchor } = this.getPositionByRange({
544
- focusOffset: location.offset,
545
- anchorOffset: location.offset,
546
- focusSlot: location.slot,
547
- anchorSlot: location.slot
548
- });
549
- if (!focus || !anchor) {
550
- return null;
551
- }
552
- const nativeRange = document.createRange();
553
- nativeRange.setStart(focus.node, focus.offset);
554
- nativeRange.collapse();
555
- return getLayoutRectByRange(nativeRange);
556
- }
557
- restore(abstractSelection, fromLocal) {
558
- this.changeFromUser = fromLocal;
559
- if (this.ignoreSelectionChange || !this.connector) {
560
- return;
561
- }
562
- this.unListen();
563
- if (!abstractSelection) {
564
- this.nativeSelection.removeAllRanges();
565
- this.selectionChangeEvent.next(null);
566
- this.listen(this.connector);
567
- return;
568
- }
569
- const { focus, anchor } = this.getPositionByRange(abstractSelection);
570
- if (!focus || !anchor) {
571
- this.nativeSelection.removeAllRanges();
572
- this.selectionChangeEvent.next(null);
573
- this.listen(this.connector);
574
- return;
575
- }
576
- function tryOffset(position) {
577
- if (!position.node) {
578
- return;
579
- }
580
- if (position.node.nodeType === Node.TEXT_NODE) {
581
- const len = position.node.textContent.length;
582
- if (position.offset > len) {
583
- position.offset = len;
584
- }
585
- }
586
- else if (position.node.nodeType === Node.ELEMENT_NODE) {
587
- const len = position.node.childNodes.length;
588
- if (position.offset > len) {
589
- position.offset = len;
590
- }
591
- }
592
- }
593
- try {
594
- tryOffset(focus);
595
- tryOffset(anchor);
596
- this.nativeSelection.setBaseAndExtent(anchor.node, anchor.offset, focus.node, focus.offset);
597
- }
598
- catch (e) {
599
- setTimeout(() => {
600
- throw e;
601
- });
602
- }
603
- if (this.nativeSelection.rangeCount) {
604
- const nativeRange = this.nativeSelection.getRangeAt(0);
605
- this.selectionChangeEvent.next(nativeRange);
606
- }
607
- else {
608
- this.selectionChangeEvent.next(null);
609
- }
610
- // hack start 浏览器会触发上面选区更改事件
611
- const bind = () => {
612
- if (this.connector) {
613
- this.listen(this.connector);
614
- }
615
- };
616
- if (fromLocal) {
617
- Promise.resolve().then(bind);
618
- return;
619
- }
620
- if (typeof requestIdleCallback === 'function') {
621
- requestIdleCallback(bind);
622
- }
623
- else {
624
- setTimeout(bind, 30);
625
- }
626
- // hack end
627
- }
628
- destroy() {
629
- this.subs.forEach(i => i.unsubscribe());
630
- this.sub.unsubscribe();
631
- }
632
- getPositionByRange(abstractSelection) {
633
- let focus;
634
- let anchor;
635
- try {
636
- focus = this.findSelectedNodeAndOffset(abstractSelection.focusSlot, abstractSelection.focusOffset);
637
- anchor = focus;
638
- if (abstractSelection.anchorSlot !== abstractSelection.focusSlot ||
639
- abstractSelection.anchorOffset !== abstractSelection.focusOffset) {
640
- anchor = this.findSelectedNodeAndOffset(abstractSelection.anchorSlot, abstractSelection.anchorOffset);
641
- }
642
- return {
643
- focus,
644
- anchor
645
- };
646
- }
647
- catch (e) {
648
- return {
649
- focus: null,
650
- anchor: null
651
- };
652
- }
653
- }
654
- getPreviousLinePositionByCurrent(position) {
655
- return this.getLinePosition(position, false);
656
- }
657
- getNextLinePositionByCurrent(position) {
658
- return this.getLinePosition(position, true);
659
- }
660
- getLinePosition(currentPosition, toNext) {
661
- clearTimeout(this.cacheCaretPositionTimer);
662
- let p;
663
- if (this.oldCaretPosition) {
664
- p = toNext ?
665
- this.getNextLinePositionByOffset(currentPosition, this.oldCaretPosition.left) :
666
- this.getPreviousLinePositionByOffset(currentPosition, this.oldCaretPosition.left);
667
- }
668
- else {
669
- this.oldCaretPosition = this.getRect(currentPosition);
670
- p = toNext ?
671
- this.getNextLinePositionByOffset(currentPosition, this.oldCaretPosition.left) :
672
- this.getPreviousLinePositionByOffset(currentPosition, this.oldCaretPosition.left);
673
- }
674
- this.cacheCaretPositionTimer = setTimeout(() => {
675
- this.oldCaretPosition = null;
676
- }, 3000);
677
- return p;
678
- }
679
- /**
680
- * 获取选区向上移动一行的位置。
681
- * @param currentPosition
682
- * @param startLeft 参考位置。
683
- */
684
- getPreviousLinePositionByOffset(currentPosition, startLeft) {
685
- let isToPrevLine = false;
686
- let loopCount = 0;
687
- let minLeft = startLeft;
688
- let focusSlot = currentPosition.slot;
689
- let focusOffset = currentPosition.offset;
690
- let minTop = this.getRect({
691
- slot: focusSlot,
692
- offset: focusOffset
693
- }).top;
694
- let position;
695
- let oldPosition;
696
- let oldLeft = 0;
697
- while (true) {
698
- loopCount++;
699
- position = this.selection.getPreviousPositionByPosition(focusSlot, focusOffset);
700
- focusSlot = position.slot;
701
- focusOffset = position.offset;
702
- const rect2 = this.getRect(position);
703
- if (!isToPrevLine) {
704
- if (rect2.left > minLeft || rect2.top + rect2.height <= minTop) {
705
- isToPrevLine = true;
706
- }
707
- else if (rect2.left === minLeft && rect2.top === minTop) {
708
- return position;
709
- }
710
- minLeft = rect2.left;
711
- minTop = rect2.top;
712
- // oldPosition = position
713
- }
714
- if (isToPrevLine) {
715
- if (rect2.left <= startLeft) {
716
- return position;
717
- }
718
- if (oldPosition) {
719
- if (rect2.left >= oldLeft) {
720
- return oldPosition;
721
- }
722
- }
723
- oldLeft = rect2.left;
724
- oldPosition = position;
725
- }
726
- if (loopCount > 10000) {
727
- break;
728
- }
729
- }
730
- return position || {
731
- offset: 0,
732
- slot: focusSlot
733
- };
734
- }
735
- /**
736
- * 获取选区向下移动一行的位置。
737
- * @param currentPosition
738
- * @param startLeft 参考位置。
739
- */
740
- getNextLinePositionByOffset(currentPosition, startLeft) {
741
- let isToNextLine = false;
742
- let loopCount = 0;
743
- let maxRight = startLeft;
744
- let focusSlot = currentPosition.slot;
745
- let focusOffset = currentPosition.offset;
746
- const rect = this.getRect({
747
- slot: focusSlot,
748
- offset: focusOffset
749
- });
750
- let minTop = rect.top;
751
- let oldPosition;
752
- let oldLeft = 0;
753
- while (true) {
754
- loopCount++;
755
- const position = this.selection.getNextPositionByPosition(focusSlot, focusOffset);
756
- focusSlot = position.slot;
757
- focusOffset = position.offset;
758
- const rect2 = this.getRect(position);
759
- if (!isToNextLine) {
760
- if (rect2.left < maxRight || rect2.top >= minTop + rect.height) {
761
- isToNextLine = true;
762
- }
763
- else if (rect2.left === maxRight && rect2.top === minTop) {
764
- return position;
765
- }
766
- maxRight = rect2.left;
767
- minTop = rect2.top;
768
- oldPosition = position;
769
- }
770
- if (isToNextLine) {
771
- if (rect2.left > startLeft) {
772
- return oldPosition;
773
- }
774
- if (oldPosition) {
775
- if (rect2.left <= oldLeft) {
776
- return oldPosition;
777
- }
778
- }
779
- oldPosition = position;
780
- oldLeft = rect2.left;
781
- }
782
- if (loopCount > 10000) {
783
- break;
784
- }
785
- }
786
- return oldPosition || {
787
- offset: focusSlot.length,
788
- slot: focusSlot
789
- };
790
- }
791
- unListen() {
792
- this.subs.forEach(i => i.unsubscribe());
793
- this.subs = [];
794
- }
795
- listen(connector) {
796
- if (!this.config.useContentEditable) {
797
- const selection = this.nativeSelection;
798
- this.subs.push(stream.fromEvent(this.docContainer, 'mousedown').subscribe(ev => {
799
- if (this.ignoreSelectionChange || ev.button === 2) {
800
- return;
801
- }
802
- if (!ev.shiftKey) {
803
- selection.removeAllRanges();
804
- }
805
- }));
806
- }
807
- let isUpdating = false;
808
- this.subs.push(this.scheduler.onDocChange.subscribe(() => {
809
- isUpdating = true;
810
- }), this.scheduler.onDocChanged.pipe(stream.delay()).subscribe(() => {
811
- isUpdating = false;
812
- }), stream.fromEvent(document, 'selectionchange').subscribe(() => {
813
- if (isUpdating) {
814
- return;
815
- }
816
- if (this.syncSelectionFromNativeSelectionChange) {
817
- this.syncSelection(connector);
818
- }
819
- }));
820
- }
821
- syncSelection(connector) {
822
- var _a;
823
- const selection = this.nativeSelection;
824
- this.changeFromUser = true;
825
- if (this.ignoreSelectionChange ||
826
- this.input.composition ||
827
- selection.rangeCount === 0 ||
828
- !this.docContainer.contains(selection.anchorNode) ||
829
- this.rootComponentRef.component.slots.length === 0) {
830
- return;
831
- }
832
- const rawRange = selection.getRangeAt(0);
833
- const nativeRange = rawRange.cloneRange();
834
- const isFocusEnd = selection.focusNode === nativeRange.endContainer && selection.focusOffset === nativeRange.endOffset;
835
- const isFocusStart = selection.focusNode === nativeRange.startContainer && selection.focusOffset === nativeRange.startOffset;
836
- if (!this.docContainer.contains(selection.focusNode)) {
837
- if (isFocusEnd) {
838
- const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.at(0));
839
- if (!nativeNode) {
840
- return;
841
- }
842
- nativeRange.setEndAfter(nativeNode.lastChild);
843
- }
844
- else {
845
- const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.at(-1));
846
- if (!nativeNode) {
847
- return;
848
- }
849
- nativeRange.setStartBefore(nativeNode.firstChild);
850
- }
851
- }
852
- const startPosition = this.getCorrectedPosition(nativeRange.startContainer, nativeRange.startOffset, isFocusStart);
853
- const endPosition = nativeRange.collapsed ?
854
- startPosition :
855
- this.getCorrectedPosition(nativeRange.endContainer, nativeRange.endOffset, isFocusEnd);
856
- if ([Node.ELEMENT_NODE, Node.TEXT_NODE].includes((_a = nativeRange.commonAncestorContainer) === null || _a === void 0 ? void 0 : _a.nodeType) &&
857
- startPosition && endPosition) {
858
- const abstractSelection = connector.beforeChange(isFocusEnd ? {
859
- anchorSlot: startPosition.slot,
860
- anchorOffset: startPosition.offset,
861
- focusSlot: endPosition.slot,
862
- focusOffset: endPosition.offset
863
- } : {
864
- focusSlot: startPosition.slot,
865
- focusOffset: startPosition.offset,
866
- anchorSlot: endPosition.slot,
867
- anchorOffset: endPosition.offset
868
- });
869
- if (!abstractSelection) {
870
- this.selectionChangeEvent.next(null);
871
- connector.setSelection(null);
872
- return;
873
- }
874
- const { focus, anchor } = this.getPositionByRange(abstractSelection);
875
- if (focus && anchor) {
876
- let start = anchor;
877
- let end = focus;
878
- if (isFocusStart) {
879
- start = focus;
880
- end = anchor;
881
- }
882
- if (nativeRange.startContainer !== start.node || nativeRange.startOffset !== start.offset) {
883
- nativeRange.setStart(start.node, start.offset);
884
- }
885
- if (nativeRange.endContainer !== end.node || nativeRange.endOffset !== end.offset) {
886
- nativeRange.setEnd(end.node, end.offset);
887
- }
888
- connector.setSelection(abstractSelection);
889
- if (selection.isCollapsed && (rawRange.startContainer !== start.node ||
890
- rawRange.startOffset !== start.offset ||
891
- rawRange.endContainer !== end.node ||
892
- rawRange.endOffset !== end.offset)) {
893
- rawRange.setStart(start.node, start.offset);
894
- rawRange.setEnd(end.node, end.offset);
895
- }
896
- this.selectionChangeEvent.next(nativeRange);
897
- }
898
- else {
899
- connector.setSelection(null);
900
- }
901
- return;
902
- }
903
- connector.setSelection(null);
904
- }
905
- findSelectedNodeAndOffset(slot, offset) {
906
- const prev = slot.getContentAtIndex(offset - 1);
907
- const nodes = this.domAdapter.getNodesBySlot(slot);
908
- if (prev) {
909
- if (typeof prev !== 'string') {
910
- const nativeNode = this.domAdapter.getNativeNodeByComponent(prev);
911
- return {
912
- node: nativeNode.parentNode,
913
- offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode) + 1
914
- };
915
- }
916
- else if (prev === '\n') {
917
- for (const node of nodes) {
918
- if (node instanceof Text) {
919
- continue;
920
- }
921
- if (node.nodeName === 'BR') {
922
- const position = this.domAdapter.getLocationByNativeNode(node);
923
- if (position) {
924
- if (position.endIndex === offset) {
925
- const parentNode = node.parentNode;
926
- return {
927
- node: parentNode,
928
- offset: Array.from(parentNode.childNodes).indexOf(node) + 1
929
- };
930
- }
931
- }
932
- }
933
- }
934
- }
935
- }
936
- const current = slot.getContentAtIndex(offset);
937
- if (current && typeof current !== 'string') {
938
- const nativeNode = this.domAdapter.getNativeNodeByComponent(current);
939
- return {
940
- node: nativeNode.parentNode,
941
- offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode)
942
- };
943
- }
944
- for (const node of nodes) {
945
- if (node instanceof Element) {
946
- if (node.tagName === 'BR') {
947
- const position = this.domAdapter.getLocationByNativeNode(node);
948
- if (position) {
949
- if (position.startIndex === offset) {
950
- const parentNode = node.parentNode;
951
- return {
952
- node: parentNode,
953
- offset: Array.from(parentNode.childNodes).indexOf(node)
954
- };
955
- }
956
- }
957
- }
958
- continue;
959
- }
960
- const position = this.domAdapter.getLocationByNativeNode(node);
961
- if (position) {
962
- if (offset >= position.startIndex && offset <= position.endIndex) {
963
- return {
964
- node: node,
965
- offset: offset - position.startIndex
966
- };
967
- }
968
- }
969
- }
970
- return null;
971
- }
972
- getCorrectedPosition(node, offset, toAfter, excludeNodes = []) {
973
- excludeNodes.push(node);
974
- if (node.nodeType === Node.ELEMENT_NODE) {
975
- const containerPosition = this.domAdapter.getLocationByNativeNode(node);
976
- const childNode = node.childNodes[offset];
977
- if (childNode) {
978
- const childPosition = this.domAdapter.getLocationByNativeNode(childNode);
979
- if (childPosition) {
980
- if (containerPosition) {
981
- return {
982
- slot: childPosition.slot,
983
- offset: childPosition.startIndex
984
- };
985
- }
986
- return this.findFocusNode(childNode, toAfter, excludeNodes);
987
- }
988
- return this.findFocusNode(childNode, toAfter, excludeNodes);
989
- }
990
- const prevNode = node.childNodes[offset - 1];
991
- if (prevNode) {
992
- const prevPosition = this.domAdapter.getLocationByNativeNode(prevNode);
993
- if (prevPosition && containerPosition) {
994
- return {
995
- slot: prevPosition.slot,
996
- offset: prevPosition.endIndex
997
- };
998
- }
999
- }
1000
- if (containerPosition) {
1001
- return {
1002
- slot: containerPosition.slot,
1003
- offset: containerPosition.endIndex
1004
- };
1005
- }
1006
- const nextNode = toAfter ? node.nextSibling : node.previousSibling;
1007
- if (nextNode) {
1008
- return this.findFocusNode(nextNode, toAfter, excludeNodes);
1009
- }
1010
- return this.findFocusNodeByParent(node, toAfter, excludeNodes);
1011
- }
1012
- else if (node.nodeType === Node.TEXT_NODE) {
1013
- const containerPosition = this.domAdapter.getLocationByNativeNode(node);
1014
- if (containerPosition) {
1015
- return {
1016
- slot: containerPosition.slot,
1017
- offset: containerPosition.startIndex + offset
1018
- };
1019
- }
1020
- const nextNode = toAfter ? node.nextSibling : node.previousSibling;
1021
- if (nextNode) {
1022
- return this.findFocusNode(nextNode, toAfter, excludeNodes);
1023
- }
1024
- return this.findFocusNodeByParent(node, toAfter, excludeNodes);
1025
- }
1026
- return null;
1027
- }
1028
- findFocusNode(node, toAfter = false, excludeNodes = []) {
1029
- if (excludeNodes.includes(node)) {
1030
- const next = toAfter ? node.nextSibling : node.previousSibling;
1031
- if (next) {
1032
- return this.findFocusNode(next, toAfter, excludeNodes);
1033
- }
1034
- return this.findFocusNodeByParent(node, toAfter, excludeNodes);
1035
- }
1036
- excludeNodes.push(node);
1037
- const position = this.domAdapter.getLocationByNativeNode(node);
1038
- if (position) {
1039
- return {
1040
- slot: position.slot,
1041
- offset: toAfter ? position.startIndex : position.endIndex
1042
- };
1043
- }
1044
- const firstChild = toAfter ? node.firstChild : node.lastChild;
1045
- if (firstChild) {
1046
- return this.findFocusNode(firstChild, toAfter, excludeNodes);
1047
- }
1048
- const nextSibling = toAfter ? node.nextSibling : node.previousSibling;
1049
- if (nextSibling) {
1050
- return this.findFocusNode(nextSibling, toAfter, excludeNodes);
1051
- }
1052
- return this.findFocusNodeByParent(node, toAfter, excludeNodes);
1053
- }
1054
- findFocusNodeByParent(node, toAfter, excludeNodes) {
1055
- const parentNode = node.parentNode;
1056
- if (parentNode) {
1057
- const parentPosition = this.domAdapter.getLocationByNativeNode(parentNode);
1058
- if (parentPosition) {
1059
- return {
1060
- slot: parentPosition.slot,
1061
- offset: toAfter ? parentPosition.endIndex : parentPosition.startIndex
1062
- };
1063
- }
1064
- excludeNodes.push(node);
1065
- return this.findFocusNode(parentNode, toAfter, excludeNodes);
1066
- }
1067
- return null;
1068
- }
1069
- };
1070
- exports.SelectionBridge = __decorate([
1071
- core.Injectable(),
1072
- __param(0, core.Inject(EDITOR_OPTIONS)),
1073
- __metadata("design:paramtypes", [Object, core$1.Textbus,
1074
- core$1.Controller,
1075
- core$1.Selection,
1076
- core$1.RootComponentRef,
1077
- Input,
1078
- core$1.Scheduler,
1079
- DomAdapter])
1080
- ], exports.SelectionBridge);
1081
-
1082
- const iframeHTML = `
1083
- <!DOCTYPE html>
1084
- <html>
1085
- <head>
1086
- <meta charset="UTF-8">
1087
- <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
1088
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
1089
- <title>Textbus</title>
1090
- <style>
1091
- html {position: fixed; left:0; overflow: hidden}
1092
- html, body{height: 100%;width:100%}
1093
- body{margin:0; overflow: hidden}
1094
- textarea{width: 2000px;height: 100%;opacity: 0; padding: 0; outline: none; border: none; position: absolute; left:0; top:0;}
1095
- </style>
1096
- </head>
1097
- <body>
1098
- </body>
1099
- </html>
1100
- `;
1101
- class ExperimentalCaret {
1102
- get rect() {
1103
- return this.caret.getBoundingClientRect();
1104
- }
1105
- set display(v) {
1106
- this._display = v;
1107
- this.caret.style.visibility = v ? 'visible' : 'hidden';
1108
- }
1109
- get display() {
1110
- return this._display;
1111
- }
1112
- constructor(domRenderer, scheduler, editorMask) {
1113
- Object.defineProperty(this, "domRenderer", {
1114
- enumerable: true,
1115
- configurable: true,
1116
- writable: true,
1117
- value: domRenderer
1118
- });
1119
- Object.defineProperty(this, "scheduler", {
1120
- enumerable: true,
1121
- configurable: true,
1122
- writable: true,
1123
- value: scheduler
1124
- });
1125
- Object.defineProperty(this, "editorMask", {
1126
- enumerable: true,
1127
- configurable: true,
1128
- writable: true,
1129
- value: editorMask
1130
- });
1131
- Object.defineProperty(this, "onPositionChange", {
1132
- enumerable: true,
1133
- configurable: true,
1134
- writable: true,
1135
- value: void 0
1136
- });
1137
- Object.defineProperty(this, "onStyleChange", {
1138
- enumerable: true,
1139
- configurable: true,
1140
- writable: true,
1141
- value: void 0
1142
- });
1143
- Object.defineProperty(this, "elementRef", {
1144
- enumerable: true,
1145
- configurable: true,
1146
- writable: true,
1147
- value: void 0
1148
- });
1149
- Object.defineProperty(this, "changeFromSelf", {
1150
- enumerable: true,
1151
- configurable: true,
1152
- writable: true,
1153
- value: false
1154
- });
1155
- Object.defineProperty(this, "getLimit", {
1156
- enumerable: true,
1157
- configurable: true,
1158
- writable: true,
1159
- value: function () {
1160
- return {
1161
- top: 0,
1162
- bottom: document.documentElement.clientHeight
1163
- };
1164
- }
1165
- });
1166
- Object.defineProperty(this, "timer", {
1167
- enumerable: true,
1168
- configurable: true,
1169
- writable: true,
1170
- value: null
1171
- });
1172
- Object.defineProperty(this, "caret", {
1173
- enumerable: true,
1174
- configurable: true,
1175
- writable: true,
1176
- value: void 0
1177
- });
1178
- Object.defineProperty(this, "_display", {
1179
- enumerable: true,
1180
- configurable: true,
1181
- writable: true,
1182
- value: true
1183
- });
1184
- Object.defineProperty(this, "flashing", {
1185
- enumerable: true,
1186
- configurable: true,
1187
- writable: true,
1188
- value: true
1189
- });
1190
- Object.defineProperty(this, "subscription", {
1191
- enumerable: true,
1192
- configurable: true,
1193
- writable: true,
1194
- value: new stream.Subscription()
1195
- });
1196
- Object.defineProperty(this, "positionChangeEvent", {
1197
- enumerable: true,
1198
- configurable: true,
1199
- writable: true,
1200
- value: new stream.Subject()
1201
- });
1202
- Object.defineProperty(this, "styleChangeEvent", {
1203
- enumerable: true,
1204
- configurable: true,
1205
- writable: true,
1206
- value: new stream.Subject()
1207
- });
1208
- Object.defineProperty(this, "oldRange", {
1209
- enumerable: true,
1210
- configurable: true,
1211
- writable: true,
1212
- value: null
1213
- });
1214
- this.onPositionChange = this.positionChangeEvent.pipe(stream.distinctUntilChanged());
1215
- this.onStyleChange = this.styleChangeEvent.asObservable();
1216
- this.elementRef = createElement('div', {
1217
- styles: {
1218
- position: 'absolute',
1219
- width: '2px',
1220
- pointerEvents: 'none'
1221
- },
1222
- children: [
1223
- this.caret = createElement('span', {
1224
- styles: {
1225
- width: '100%',
1226
- height: '100%',
1227
- position: 'absolute',
1228
- left: 0,
1229
- top: 0
1230
- }
1231
- })
1232
- ]
1233
- });
1234
- this.subscription.add(stream.fromEvent(document, 'mousedown').subscribe(() => {
1235
- this.flashing = false;
1236
- }), stream.fromEvent(document, 'mouseup').subscribe(() => {
1237
- this.flashing = true;
1238
- }));
1239
- this.editorMask.appendChild(this.elementRef);
1240
- }
1241
- refresh() {
1242
- if (this.oldRange) {
1243
- this.show(this.oldRange, false);
1244
- }
1245
- }
1246
- show(range, restart) {
1247
- this.oldRange = range;
1248
- if (restart || this.scheduler.lastChangesHasLocalUpdate) {
1249
- clearTimeout(this.timer);
1250
- }
1251
- this.updateCursorPosition(range);
1252
- if (range.collapsed) {
1253
- if (restart || this.scheduler.lastChangesHasLocalUpdate) {
1254
- this.display = true;
1255
- const toggleShowHide = () => {
1256
- this.display = !this.display || !this.flashing;
1257
- this.timer = setTimeout(toggleShowHide, 400);
1258
- };
1259
- clearTimeout(this.timer);
1260
- this.timer = setTimeout(toggleShowHide, 400);
1261
- }
1262
- }
1263
- else {
1264
- this.display = false;
1265
- clearTimeout(this.timer);
1266
- }
1267
- }
1268
- hide() {
1269
- this.display = false;
1270
- clearTimeout(this.timer);
1271
- this.positionChangeEvent.next(null);
1272
- }
1273
- destroy() {
1274
- clearTimeout(this.timer);
1275
- // this.caret.
1276
- this.subscription.unsubscribe();
1277
- }
1278
- updateCursorPosition(nativeRange) {
1279
- const startContainer = nativeRange.startContainer;
1280
- const node = (startContainer.nodeType === Node.ELEMENT_NODE ? startContainer : startContainer.parentNode);
1281
- if ((node === null || node === void 0 ? void 0 : node.nodeType) !== Node.ELEMENT_NODE) {
1282
- this.positionChangeEvent.next(null);
1283
- return;
1284
- }
1285
- const compositionNode = this.domRenderer.compositionNode;
1286
- if (compositionNode) {
1287
- nativeRange = nativeRange.cloneRange();
1288
- nativeRange.selectNodeContents(compositionNode);
1289
- nativeRange.collapse();
1290
- }
1291
- const rect = getLayoutRectByRange(nativeRange);
1292
- const { fontSize, lineHeight, color, writingMode } = getComputedStyle(node);
1293
- let height;
1294
- if (isNaN(+lineHeight)) {
1295
- const f = parseFloat(lineHeight);
1296
- if (isNaN(f)) {
1297
- height = parseFloat(fontSize);
1298
- }
1299
- else {
1300
- height = f;
1301
- }
1302
- }
1303
- else {
1304
- height = parseFloat(fontSize) * parseFloat(lineHeight);
1305
- }
1306
- const boxHeight = Math.max(Math.floor(Math.max(height, rect.height)), 12);
1307
- // const boxHeight = Math.floor(height)
1308
- let rectTop = rect.top;
1309
- if (rect.height < height) {
1310
- rectTop -= (height - rect.height) / 2;
1311
- }
1312
- rectTop = Math.floor(rectTop);
1313
- const containerRect = this.editorMask.getBoundingClientRect();
1314
- const top = Math.floor(rectTop - containerRect.top);
1315
- const left = Math.floor(rect.left + rect.width / 2 - containerRect.left);
1316
- let rotate = 0;
1317
- if (nativeRange.collapsed) {
1318
- rotate = Math.round(Math.atan2(rect.width, rect.height) * 180 / Math.PI);
1319
- if (rotate !== 0) {
1320
- const hackEle = document.createElement('span');
1321
- // eslint-disable-next-line max-len
1322
- hackEle.style.cssText = 'display: inline-block; width: 10px; height: 10px; position: relative; contain: layout style size; writing-mode: inherit';
1323
- const pointEle = document.createElement('span');
1324
- pointEle.style.cssText = 'position: absolute; left: 0; top: 0; width:0;height:0';
1325
- hackEle.append(pointEle);
1326
- node.append(hackEle);
1327
- const p1 = pointEle.getBoundingClientRect();
1328
- pointEle.style.right = '0';
1329
- pointEle.style.left = '';
1330
- const p2 = pointEle.getBoundingClientRect();
1331
- const x = p1.x - p2.x;
1332
- const y = p1.y - p2.y;
1333
- rotate = Math.atan2(y, x) * 180 / Math.PI;
1334
- hackEle.remove();
1335
- }
1336
- }
1337
- if (writingMode === 'vertical-lr' || writingMode === 'vertical-rl') {
1338
- rotate += 90;
1339
- }
1340
- Object.assign(this.elementRef.style, {
1341
- left: left + 'px',
1342
- top: top + 'px',
1343
- height: boxHeight + 'px',
1344
- lineHeight: boxHeight + 'px',
1345
- fontSize,
1346
- transform: `rotate(${rotate}deg)`,
1347
- });
1348
- this.caret.style.backgroundColor = color === 'rgba(0, 0, 0, 0)' ? '#000' : color;
1349
- this.styleChangeEvent.next({
1350
- height: boxHeight + 'px',
1351
- lineHeight: boxHeight + 'px',
1352
- fontSize
1353
- });
1354
- this.positionChangeEvent.next({
1355
- left,
1356
- top: rectTop,
1357
- height: boxHeight
1358
- });
1359
- if (this.changeFromSelf) {
1360
- this.changeFromSelf = false;
1361
- const selfRect = this.elementRef.getBoundingClientRect();
1362
- const scrollContainer = this.getScrollContainer(startContainer);
1363
- const scrollRect = scrollContainer === document.documentElement ?
1364
- { top: 0, bottom: document.documentElement.clientHeight } :
1365
- scrollContainer.getBoundingClientRect();
1366
- const limit = this.getLimit();
1367
- const top = Math.max(limit.top, scrollRect.top);
1368
- const bottom = Math.min(limit.bottom, scrollRect.bottom);
1369
- if (selfRect.top < top) {
1370
- scrollContainer.scrollTop -= top - selfRect.top;
1371
- }
1372
- else if (selfRect.bottom > bottom) {
1373
- scrollContainer.scrollTop += selfRect.bottom - bottom;
1374
- }
1375
- }
1376
- }
1377
- getScrollContainer(container) {
1378
- while (container) {
1379
- if (container instanceof Element) {
1380
- const styles = getComputedStyle(container);
1381
- if (styles.overflow !== 'visible' || styles.overflowX !== 'visible' || styles.overflowY !== 'visible') {
1382
- return container;
1383
- }
1384
- }
1385
- container = container.parentNode;
1386
- }
1387
- return document.documentElement;
1388
- }
1389
- }
1390
- /**
1391
- * Textbus PC 端输入实现
1392
- */
1393
- exports.MagicInput = class MagicInput extends Input {
1394
- set disabled(b) {
1395
- this._disabled = b;
1396
- if (b && this.textarea) {
1397
- this.textarea.disabled = b;
1398
- }
1399
- }
1400
- get disabled() {
1401
- return this._disabled;
1402
- }
1403
- constructor(domAdapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
1404
- super();
1405
- Object.defineProperty(this, "domAdapter", {
1406
- enumerable: true,
1407
- configurable: true,
1408
- writable: true,
1409
- value: domAdapter
1410
- });
1411
- Object.defineProperty(this, "parser", {
1412
- enumerable: true,
1413
- configurable: true,
1414
- writable: true,
1415
- value: parser
1416
- });
1417
- Object.defineProperty(this, "keyboard", {
1418
- enumerable: true,
1419
- configurable: true,
1420
- writable: true,
1421
- value: keyboard
1422
- });
1423
- Object.defineProperty(this, "commander", {
1424
- enumerable: true,
1425
- configurable: true,
1426
- writable: true,
1427
- value: commander
1428
- });
1429
- Object.defineProperty(this, "selection", {
1430
- enumerable: true,
1431
- configurable: true,
1432
- writable: true,
1433
- value: selection
1434
- });
1435
- Object.defineProperty(this, "controller", {
1436
- enumerable: true,
1437
- configurable: true,
1438
- writable: true,
1439
- value: controller
1440
- });
1441
- Object.defineProperty(this, "scheduler", {
1442
- enumerable: true,
1443
- configurable: true,
1444
- writable: true,
1445
- value: scheduler
1446
- });
1447
- Object.defineProperty(this, "textbus", {
1448
- enumerable: true,
1449
- configurable: true,
1450
- writable: true,
1451
- value: textbus
1452
- });
1453
- Object.defineProperty(this, "composition", {
1454
- enumerable: true,
1455
- configurable: true,
1456
- writable: true,
1457
- value: false
1458
- });
1459
- Object.defineProperty(this, "onReady", {
1460
- enumerable: true,
1461
- configurable: true,
1462
- writable: true,
1463
- value: void 0
1464
- });
1465
- Object.defineProperty(this, "caret", {
1466
- enumerable: true,
1467
- configurable: true,
1468
- writable: true,
1469
- value: new ExperimentalCaret(this.domAdapter, this.scheduler, this.textbus.get(VIEW_MASK))
1470
- });
1471
- Object.defineProperty(this, "isSafari", {
1472
- enumerable: true,
1473
- configurable: true,
1474
- writable: true,
1475
- value: isSafari()
1476
- });
1477
- Object.defineProperty(this, "isFirefox", {
1478
- enumerable: true,
1479
- configurable: true,
1480
- writable: true,
1481
- value: isFirefox()
1482
- });
1483
- Object.defineProperty(this, "isMac", {
1484
- enumerable: true,
1485
- configurable: true,
1486
- writable: true,
1487
- value: isMac()
1488
- });
1489
- Object.defineProperty(this, "isWindows", {
1490
- enumerable: true,
1491
- configurable: true,
1492
- writable: true,
1493
- value: isWindows()
1494
- });
1495
- Object.defineProperty(this, "_disabled", {
1496
- enumerable: true,
1497
- configurable: true,
1498
- writable: true,
1499
- value: false
1500
- });
1501
- Object.defineProperty(this, "container", {
1502
- enumerable: true,
1503
- configurable: true,
1504
- writable: true,
1505
- value: this.createEditableFrame()
1506
- });
1507
- Object.defineProperty(this, "subscription", {
1508
- enumerable: true,
1509
- configurable: true,
1510
- writable: true,
1511
- value: new stream.Subscription()
1512
- });
1513
- Object.defineProperty(this, "doc", {
1514
- enumerable: true,
1515
- configurable: true,
1516
- writable: true,
1517
- value: void 0
1518
- });
1519
- Object.defineProperty(this, "textarea", {
1520
- enumerable: true,
1521
- configurable: true,
1522
- writable: true,
1523
- value: null
1524
- });
1525
- Object.defineProperty(this, "isFocus", {
1526
- enumerable: true,
1527
- configurable: true,
1528
- writable: true,
1529
- value: false
1530
- });
1531
- Object.defineProperty(this, "nativeFocus", {
1532
- enumerable: true,
1533
- configurable: true,
1534
- writable: true,
1535
- value: false
1536
- });
1537
- Object.defineProperty(this, "ignoreComposition", {
1538
- enumerable: true,
1539
- configurable: true,
1540
- writable: true,
1541
- value: false
1542
- }); // 有 bug 版本搜狗拼音
1543
- this.onReady = new Promise(resolve => {
1544
- this.subscription.add(stream.fromEvent(this.container, 'load').subscribe(() => {
1545
- const doc = this.container.contentDocument;
1546
- doc.open();
1547
- doc.write(iframeHTML);
1548
- doc.close();
1549
- this.doc = doc;
1550
- this.init();
1551
- resolve();
1552
- }), controller.onReadonlyStateChange.subscribe(() => {
1553
- if (controller.readonly) {
1554
- this.blur();
1555
- }
1556
- }));
1557
- });
1558
- this.caret.elementRef.append(this.container);
1559
- }
1560
- focus(range, restart) {
1561
- var _a;
1562
- if (!this.disabled) {
1563
- this.caret.show(range, restart);
1564
- }
1565
- if (this.controller.readonly) {
1566
- return;
1567
- }
1568
- if (!this.isFocus) {
1569
- (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1570
- setTimeout(() => {
1571
- if (!this.nativeFocus && this.isFocus) {
1572
- this.reInit();
1573
- }
1574
- });
1575
- }
1576
- this.isFocus = true;
1577
- }
1578
- blur() {
1579
- var _a;
1580
- this.caret.hide();
1581
- (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.blur();
1582
- this.isFocus = false;
1583
- }
1584
- destroy() {
1585
- this.caret.destroy();
1586
- this.subscription.unsubscribe();
1587
- }
1588
- reInit(delay = false) {
1589
- var _a, _b, _c;
1590
- this.subscription.unsubscribe();
1591
- (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1592
- this.subscription = new stream.Subscription();
1593
- this.init();
1594
- if (delay) {
1595
- setTimeout(() => {
1596
- var _a;
1597
- (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1598
- });
1599
- }
1600
- else {
1601
- (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1602
- }
1603
- }
1604
- init() {
1605
- const doc = this.doc;
1606
- const contentBody = doc.body;
1607
- const textarea = doc.createElement('textarea');
1608
- textarea.disabled = this.disabled;
1609
- contentBody.appendChild(textarea);
1610
- this.textarea = textarea;
1611
- this.subscription.add(stream.fromEvent(textarea, 'blur').subscribe(() => {
1612
- // if (this.isFocus) {
1613
- // this.isFocus = false
1614
- // this.reInit(true)
1615
- // }
1616
- this.isFocus = false;
1617
- this.nativeFocus = false;
1618
- this.caret.hide();
1619
- if (this.domAdapter.composition) {
1620
- const slot = this.domAdapter.composition.slot;
1621
- this.domAdapter.composition = null;
1622
- this.domAdapter.compositionNode = null;
1623
- slot.__changeMarker__.forceMarkDirtied();
1624
- }
1625
- }), stream.fromEvent(textarea, 'focus').subscribe(() => {
1626
- this.nativeFocus = true;
1627
- }), this.caret.onStyleChange.subscribe(style => {
1628
- Object.assign(textarea.style, style);
1629
- }));
1630
- this.handleInput(textarea);
1631
- this.handleShortcut(textarea);
1632
- this.handleDefaultActions(textarea);
1633
- }
1634
- handleDefaultActions(textarea) {
1635
- this.subscription.add(stream.fromEvent(isFirefox() ? textarea : document, 'copy').subscribe(ev => {
1636
- this.copyHandler(ev);
1637
- }), stream.fromEvent(textarea, 'paste').subscribe(ev => {
1638
- this.pasteHandler(ev);
1639
- }));
1640
- }
1641
- copyHandler(ev) {
1642
- const selection = this.selection;
1643
- if (!selection.isSelected) {
1644
- return;
1645
- }
1646
- if (selection.startSlot === selection.endSlot && selection.endOffset - selection.startOffset === 1) {
1647
- const content = selection.startSlot.getContentAtIndex(selection.startOffset);
1648
- if (typeof content === 'object') {
1649
- const clipboardData = ev.clipboardData;
1650
- const nativeSelection = document.getSelection();
1651
- const range = nativeSelection.getRangeAt(0);
1652
- const div = document.createElement('div');
1653
- const fragment = range.cloneContents();
1654
- div.append(fragment);
1655
- clipboardData.setData('text/html', div.innerHTML);
1656
- clipboardData.setData('text', div.innerText);
1657
- ev.preventDefault();
1658
- }
1659
- }
1660
- }
1661
- pasteHandler(ev) {
1662
- const text = ev.clipboardData.getData('Text');
1663
- const types = Array.from(ev.clipboardData.types || []);
1664
- const files = Array.from(ev.clipboardData.files);
1665
- if (types.every(type => type === 'Files') && files.length) {
1666
- Promise.all(files.filter(i => {
1667
- return /image/i.test(i.type);
1668
- }).map(item => {
1669
- const reader = new FileReader();
1670
- return new Promise(resolve => {
1671
- reader.onload = (event) => {
1672
- resolve(event.target.result);
1673
- };
1674
- reader.readAsDataURL(item);
1675
- });
1676
- })).then(urls => {
1677
- const html = urls.map(i => {
1678
- return `<img src=${i}>`;
1679
- }).join('');
1680
- this.paste(html, text);
1681
- });
1682
- ev.preventDefault();
1683
- return;
1684
- }
1685
- const div = this.doc.createElement('div');
1686
- div.style.cssText = 'width:1px; height:10px; overflow: hidden; position: fixed; left: 50%; top: 50%; opacity:0';
1687
- div.contentEditable = 'true';
1688
- this.doc.body.appendChild(div);
1689
- div.focus();
1690
- setTimeout(() => {
1691
- this.doc.body.removeChild(div);
1692
- div.style.cssText = '';
1693
- this.paste(div, text);
1694
- });
1695
- }
1696
- paste(dom, text) {
1697
- const slot = this.parser.parse(dom, new core$1.Slot([
1698
- core$1.ContentType.BlockComponent,
1699
- core$1.ContentType.InlineComponent,
1700
- core$1.ContentType.Text
1701
- ]));
1702
- this.commander.paste(slot, text);
1703
- }
1704
- handleShortcut(textarea) {
1705
- let isWriting = false;
1706
- let isIgnore = false;
1707
- this.subscription.add(stream.fromEvent(textarea, 'compositionstart').subscribe(() => {
1708
- isWriting = true;
1709
- }), stream.fromEvent(textarea, 'compositionend').subscribe(() => {
1710
- isWriting = false;
1711
- }), stream.fromEvent(textarea, 'beforeinput').subscribe(ev => {
1712
- this.ignoreComposition = false;
1713
- if (this.isSafari) {
1714
- if (ev.inputType === 'insertFromComposition') {
1715
- isIgnore = true;
1716
- }
1717
- }
1718
- }), stream.fromEvent(textarea, 'keydown').pipe(stream.filter(() => {
1719
- if (this.isSafari && isIgnore) {
1720
- isIgnore = false;
1721
- return false;
1722
- }
1723
- return !isWriting; // || !this.textarea.value
1724
- })).subscribe(ev => {
1725
- this.ignoreComposition = false;
1726
- let key = ev.key;
1727
- const keys = ')!@#$%^Z&*(';
1728
- const b = key === 'Process' && /Digit\d/.test(ev.code) && ev.shiftKey;
1729
- if (b) {
1730
- // 大小写锁定为大写 + 全角 + shift + 数字键,还存在问题
1731
- key = keys.charAt(+ev.code.substring(5));
1732
- ev.preventDefault();
1733
- }
1734
- this.caret.changeFromSelf = true;
1735
- const is = this.keyboard.execShortcut({
1736
- key: key,
1737
- altKey: ev.altKey,
1738
- shiftKey: ev.shiftKey,
1739
- modKey: this.isMac ? ev.metaKey : ev.ctrlKey,
1740
- agent: {
1741
- key: ev.key,
1742
- code: ev.code,
1743
- keyCode: ev.keyCode,
1744
- }
1745
- });
1746
- if (is) {
1747
- this.ignoreComposition = true;
1748
- ev.preventDefault();
1749
- }
1750
- else {
1751
- this.caret.changeFromSelf = false;
1752
- }
1753
- }));
1754
- }
1755
- handleInput(textarea) {
1756
- let startIndex = 0;
1757
- this.subscription.add(stream.fromEvent(textarea, 'compositionstart').pipe(stream.filter(() => {
1758
- return !this.ignoreComposition;
1759
- })).subscribe(() => {
1760
- if (!this.selection.isCollapsed) {
1761
- this.caret.changeFromSelf = true;
1762
- this.commander.delete();
1763
- }
1764
- this.composition = true;
1765
- startIndex = this.selection.startOffset;
1766
- const startSlot = this.selection.startSlot;
1767
- const event = new core$1.Event(startSlot, {
1768
- index: startIndex
1769
- });
1770
- core$1.invokeListener(startSlot.parent, 'onCompositionStart', event);
1771
- }), stream.fromEvent(textarea, 'compositionupdate').pipe(stream.filter(() => {
1772
- return !this.ignoreComposition;
1773
- })).pipe(stream.distinctUntilChanged((prev, next) => {
1774
- return prev.data !== next.data;
1775
- })).subscribe(ev => {
1776
- if (ev.data === ' ') {
1777
- // 处理搜狗五笔不符合 composition 事件预期,会意外跳光标的问题
1778
- return;
1779
- }
1780
- const startSlot = this.selection.startSlot;
1781
- this.domAdapter.composition = {
1782
- slot: startSlot,
1783
- text: ev.data,
1784
- offset: ev.data.length,
1785
- index: startIndex
1786
- };
1787
- this.caret.changeFromSelf = true;
1788
- this.caret.refresh();
1789
- const event = new core$1.Event(startSlot, {
1790
- index: startIndex,
1791
- data: ev.data
1792
- });
1793
- core$1.invokeListener(startSlot.parent, 'onCompositionUpdate', event);
1794
- startSlot.__changeMarker__.forceMarkDirtied();
1795
- }));
1796
- let isCompositionEnd = false;
1797
- this.subscription.add(stream.merge(stream.fromEvent(textarea, 'beforeinput').pipe(stream.filter(ev => {
1798
- ev.preventDefault();
1799
- if (this.isFirefox && ev.inputType === 'insertFromPaste') {
1800
- return false;
1801
- }
1802
- if (this.isSafari) {
1803
- isCompositionEnd = ev.inputType === 'insertFromComposition';
1804
- return ev.inputType === 'insertText' || ev.inputType === 'insertFromComposition';
1805
- }
1806
- return !ev.isComposing && !!ev.data;
1807
- }), stream.map(ev => {
1808
- return ev.data;
1809
- })), this.isSafari ? new stream.Observable() : stream.fromEvent(textarea, 'compositionend')
1810
- .pipe(stream.filter(() => {
1811
- return !this.ignoreComposition;
1812
- })).pipe(stream.map(ev => {
1813
- isCompositionEnd = true;
1814
- ev.preventDefault();
1815
- textarea.value = '';
1816
- return ev.data;
1817
- }))).subscribe(text => {
1818
- var _a;
1819
- this.composition = false;
1820
- this.domAdapter.composition = null;
1821
- if (text) {
1822
- this.caret.changeFromSelf = true;
1823
- this.commander.write(text);
1824
- }
1825
- else {
1826
- (_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.__changeMarker__.forceMarkDirtied();
1827
- }
1828
- if (isCompositionEnd) {
1829
- const startSlot = this.selection.startSlot;
1830
- if (startSlot) {
1831
- const event = new core$1.Event(startSlot, null);
1832
- core$1.invokeListener(startSlot.parent, 'onCompositionEnd', event);
1833
- }
1834
- }
1835
- isCompositionEnd = false;
1836
- }));
1837
- }
1838
- createEditableFrame() {
1839
- return createElement('iframe', {
1840
- attrs: {
1841
- scrolling: 'no'
1842
- },
1843
- styles: {
1844
- border: 'none',
1845
- width: '100%',
1846
- display: 'block',
1847
- height: '100%',
1848
- position: 'relative',
1849
- top: this.isWindows ? '3px' : '0'
1850
- }
1851
- });
1852
- }
1853
- };
1854
- exports.MagicInput = __decorate([
1855
- core.Injectable(),
1856
- __metadata("design:paramtypes", [DomAdapter,
1857
- exports.Parser,
1858
- core$1.Keyboard,
1859
- core$1.Commander,
1860
- core$1.Selection,
1861
- core$1.Controller,
1862
- core$1.Scheduler,
1863
- core$1.Textbus])
1864
- ], exports.MagicInput);
1865
-
1866
- /**
1867
- * 远程光标绘制范围计算代理类,可用于定制特定场景下的远程选区绘制,如表格有选区,不会遵守常见的文档流形式
1868
- */
1869
- class CollaborateSelectionAwarenessDelegate {
1870
- }
1871
- /**
1872
- * 协作光标绘制类
1873
- */
1874
- exports.CollaborateCursor = class CollaborateCursor {
1875
- constructor(textbus, nativeSelection, scheduler, selection, awarenessDelegate) {
1876
- Object.defineProperty(this, "nativeSelection", {
1877
- enumerable: true,
1878
- configurable: true,
1879
- writable: true,
1880
- value: nativeSelection
1881
- });
1882
- Object.defineProperty(this, "scheduler", {
1883
- enumerable: true,
1884
- configurable: true,
1885
- writable: true,
1886
- value: scheduler
1887
- });
1888
- Object.defineProperty(this, "selection", {
1889
- enumerable: true,
1890
- configurable: true,
1891
- writable: true,
1892
- value: selection
1893
- });
1894
- Object.defineProperty(this, "awarenessDelegate", {
1895
- enumerable: true,
1896
- configurable: true,
1897
- writable: true,
1898
- value: awarenessDelegate
1899
- });
1900
- Object.defineProperty(this, "host", {
1901
- enumerable: true,
1902
- configurable: true,
1903
- writable: true,
1904
- value: createElement('div', {
1905
- styles: {
1906
- position: 'absolute',
1907
- left: 0,
1908
- top: 0,
1909
- width: '100%',
1910
- height: '100%',
1911
- pointerEvents: 'none',
1912
- zIndex: 1
1913
- }
1914
- })
1915
- });
1916
- Object.defineProperty(this, "canvasContainer", {
1917
- enumerable: true,
1918
- configurable: true,
1919
- writable: true,
1920
- value: createElement('div', {
1921
- styles: {
1922
- position: 'absolute',
1923
- left: 0,
1924
- top: 0,
1925
- width: '100%',
1926
- height: '100%',
1927
- overflow: 'hidden'
1928
- }
1929
- })
1930
- });
1931
- Object.defineProperty(this, "canvas", {
1932
- enumerable: true,
1933
- configurable: true,
1934
- writable: true,
1935
- value: createElement('canvas', {
1936
- styles: {
1937
- position: 'absolute',
1938
- opacity: 0.5,
1939
- left: 0,
1940
- top: 0,
1941
- width: '100%',
1942
- height: document.documentElement.clientHeight + 'px',
1943
- pointerEvents: 'none',
1944
- }
1945
- })
1946
- });
1947
- Object.defineProperty(this, "context", {
1948
- enumerable: true,
1949
- configurable: true,
1950
- writable: true,
1951
- value: this.canvas.getContext('2d')
1952
- });
1953
- Object.defineProperty(this, "tooltips", {
1954
- enumerable: true,
1955
- configurable: true,
1956
- writable: true,
1957
- value: createElement('div', {
1958
- styles: {
1959
- position: 'absolute',
1960
- left: 0,
1961
- top: 0,
1962
- width: '100%',
1963
- height: '100%',
1964
- pointerEvents: 'none',
1965
- fontSize: '12px',
1966
- zIndex: 10
1967
- }
1968
- })
1969
- });
1970
- Object.defineProperty(this, "onRectsChange", {
1971
- enumerable: true,
1972
- configurable: true,
1973
- writable: true,
1974
- value: new stream.Subject()
1975
- });
1976
- Object.defineProperty(this, "subscription", {
1977
- enumerable: true,
1978
- configurable: true,
1979
- writable: true,
1980
- value: new stream.Subscription()
1981
- });
1982
- Object.defineProperty(this, "selectionCursors", {
1983
- enumerable: true,
1984
- configurable: true,
1985
- writable: true,
1986
- value: []
1987
- });
1988
- Object.defineProperty(this, "container", {
1989
- enumerable: true,
1990
- configurable: true,
1991
- writable: true,
1992
- value: void 0
1993
- });
1994
- Object.defineProperty(this, "ratio", {
1995
- enumerable: true,
1996
- configurable: true,
1997
- writable: true,
1998
- value: window.devicePixelRatio || 1
1999
- });
2000
- this.container = textbus.get(VIEW_CONTAINER);
2001
- this.canvasContainer.append(this.canvas);
2002
- this.host.append(this.canvasContainer, this.tooltips);
2003
- this.container.prepend(this.host);
2004
- this.subscription.add(this.onRectsChange.subscribe(rects => {
2005
- for (const rect of rects) {
2006
- this.context.fillStyle = rect.color;
2007
- this.context.beginPath();
2008
- this.context.rect(rect.left, rect.top, rect.width, rect.height);
2009
- this.context.fill();
2010
- this.context.closePath();
2011
- }
2012
- }), stream.fromEvent(window, 'resize').subscribe(() => {
2013
- this.canvas.style.height = document.documentElement.clientHeight + 'px';
2014
- this.refresh();
2015
- }), this.scheduler.onDocChanged.subscribe(() => {
2016
- this.refresh();
2017
- }));
2018
- }
2019
- /**
2020
- * 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
2021
- */
2022
- refresh() {
2023
- this.draw(this.selectionCursors);
2024
- }
2025
- destroy() {
2026
- this.subscription.unsubscribe();
2027
- }
2028
- /**
2029
- * 根据远程用户光标位置,绘制协作光标
2030
- * @param paths
2031
- */
2032
- draw(paths) {
2033
- this.selectionCursors = paths;
2034
- const containerRect = this.container.getBoundingClientRect();
2035
- this.canvas.style.top = containerRect.top * -1 + 'px';
2036
- this.canvas.width = this.canvas.offsetWidth * this.ratio;
2037
- this.canvas.height = this.canvas.offsetHeight * this.ratio;
2038
- this.context.scale(this.ratio, this.ratio);
2039
- this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
2040
- const users = [];
2041
- paths.filter(i => {
2042
- return i.selection.anchor.length && i.selection.focus.length;
2043
- }).forEach(item => {
2044
- const anchorPaths = [...item.selection.anchor];
2045
- const focusPaths = [...item.selection.focus];
2046
- const anchorOffset = anchorPaths.pop();
2047
- const anchorSlot = this.selection.findSlotByPaths(anchorPaths);
2048
- const focusOffset = focusPaths.pop();
2049
- const focusSlot = this.selection.findSlotByPaths(focusPaths);
2050
- if (!anchorSlot || !focusSlot) {
2051
- return;
2052
- }
2053
- const { focus, anchor } = this.nativeSelection.getPositionByRange({
2054
- focusOffset,
2055
- anchorOffset,
2056
- focusSlot,
2057
- anchorSlot
2058
- });
2059
- if (!focus || !anchor) {
2060
- return;
2061
- }
2062
- const nativeRange = document.createRange();
2063
- try {
2064
- nativeRange.setStart(anchor.node, anchor.offset);
2065
- nativeRange.setEnd(focus.node, focus.offset);
2066
- }
2067
- catch (e) {
2068
- return;
2069
- }
2070
- if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
2071
- nativeRange.setStart(focus.node, focus.offset);
2072
- nativeRange.setEnd(anchor.node, anchor.offset);
2073
- }
2074
- let rects = false;
2075
- if (this.awarenessDelegate) {
2076
- rects = this.awarenessDelegate.getRects({
2077
- focusOffset,
2078
- anchorOffset,
2079
- focusSlot,
2080
- anchorSlot
2081
- }, nativeRange, item);
2082
- }
2083
- if (!rects) {
2084
- rects = nativeRange.getClientRects();
2085
- }
2086
- const selectionRects = [];
2087
- for (let i = rects.length - 1; i >= 0; i--) {
2088
- const rect = rects[i];
2089
- selectionRects.push({
2090
- color: item.color,
2091
- username: item.username,
2092
- left: rect.left - containerRect.left,
2093
- top: rect.top,
2094
- width: rect.width,
2095
- height: rect.height,
2096
- });
2097
- }
2098
- this.onRectsChange.next(selectionRects);
2099
- const cursorRange = nativeRange.cloneRange();
2100
- cursorRange.setStart(focus.node, focus.offset);
2101
- cursorRange.collapse(true);
2102
- const cursorRect = getLayoutRectByRange(cursorRange);
2103
- const rect = {
2104
- username: item.username,
2105
- color: item.color,
2106
- left: cursorRect.left - containerRect.left,
2107
- top: cursorRect.top - containerRect.top,
2108
- width: 1,
2109
- height: cursorRect.height
2110
- };
2111
- if (rect.left < 0 || rect.top < 0 || rect.left > containerRect.width) {
2112
- return;
2113
- }
2114
- users.push(rect);
2115
- });
2116
- this.drawUserCursor(users);
2117
- }
2118
- drawUserCursor(rects) {
2119
- for (let i = 0; i < rects.length; i++) {
2120
- const rect = rects[i];
2121
- const { cursor, userTip, anchor } = this.getUserCursor(i);
2122
- Object.assign(cursor.style, {
2123
- left: rect.left + 'px',
2124
- top: rect.top + 'px',
2125
- width: rect.width + 'px',
2126
- height: rect.height + 'px',
2127
- background: rect.color,
2128
- display: 'block'
2129
- });
2130
- anchor.style.background = rect.color;
2131
- userTip.innerText = rect.username;
2132
- userTip.style.background = rect.color;
2133
- }
2134
- for (let i = rects.length; i < this.tooltips.children.length; i++) {
2135
- this.tooltips.removeChild(this.tooltips.children[i]);
2136
- }
2137
- }
2138
- getUserCursor(index) {
2139
- let child = this.tooltips.children[index];
2140
- if (child) {
2141
- const anchor = child.children[0];
2142
- return {
2143
- cursor: child,
2144
- anchor,
2145
- userTip: anchor.children[0]
2146
- };
2147
- }
2148
- const userTip = createElement('span', {
2149
- styles: {
2150
- position: 'absolute',
2151
- left: '50%',
2152
- transform: 'translateX(-50%)',
2153
- marginBottom: '2px',
2154
- bottom: '100%',
2155
- whiteSpace: 'nowrap',
2156
- color: '#fff',
2157
- boxShadow: '0 1px 2px rgba(0,0,0,.1)',
2158
- opacity: 0.8,
2159
- borderRadius: '3px',
2160
- padding: '3px 5px',
2161
- pointerEvents: 'none',
2162
- }
2163
- });
2164
- const anchor = createElement('span', {
2165
- styles: {
2166
- position: 'absolute',
2167
- top: '-2px',
2168
- left: '-2px',
2169
- width: '5px',
2170
- height: '5px',
2171
- borderRadius: '50%',
2172
- pointerEvents: 'auto',
2173
- pointer: 'cursor',
2174
- },
2175
- children: [userTip]
2176
- });
2177
- child = createElement('span', {
2178
- styles: {
2179
- position: 'absolute',
2180
- },
2181
- children: [
2182
- anchor
2183
- ]
2184
- });
2185
- this.tooltips.append(child);
2186
- return {
2187
- cursor: child,
2188
- anchor,
2189
- userTip
2190
- };
2191
- }
2192
- };
2193
- exports.CollaborateCursor = __decorate([
2194
- core.Injectable(),
2195
- __param(4, core.Optional()),
2196
- __metadata("design:paramtypes", [core$1.Textbus,
2197
- exports.SelectionBridge,
2198
- core$1.Scheduler,
2199
- core$1.Selection,
2200
- CollaborateSelectionAwarenessDelegate])
2201
- ], exports.CollaborateCursor);
2202
-
2203
- class NativeCaret {
2204
- set nativeRange(range) {
2205
- this._nativeRange = range;
2206
- if (range) {
2207
- const r = range.cloneRange();
2208
- r.collapse(true);
2209
- const rect = getLayoutRectByRange(r);
2210
- this.positionChangeEvent.next({
2211
- left: rect.left,
2212
- top: rect.top,
2213
- height: rect.height
2214
- });
2215
- }
2216
- else {
2217
- this.positionChangeEvent.next(null);
2218
- }
2219
- }
2220
- get nativeRange() {
2221
- return this._nativeRange;
2222
- }
2223
- get rect() {
2224
- if (this.nativeRange) {
2225
- const range = this.nativeRange.cloneRange();
2226
- range.collapse(true);
2227
- return getLayoutRectByRange(range);
2228
- }
2229
- return {
2230
- left: 0,
2231
- top: 0,
2232
- width: 0,
2233
- height: 0
2234
- };
2235
- }
2236
- constructor() {
2237
- Object.defineProperty(this, "onPositionChange", {
2238
- enumerable: true,
2239
- configurable: true,
2240
- writable: true,
2241
- value: void 0
2242
- });
2243
- Object.defineProperty(this, "_nativeRange", {
2244
- enumerable: true,
2245
- configurable: true,
2246
- writable: true,
2247
- value: null
2248
- });
2249
- Object.defineProperty(this, "subs", {
2250
- enumerable: true,
2251
- configurable: true,
2252
- writable: true,
2253
- value: []
2254
- });
2255
- Object.defineProperty(this, "positionChangeEvent", {
2256
- enumerable: true,
2257
- configurable: true,
2258
- writable: true,
2259
- value: new stream.Subject()
2260
- });
2261
- this.onPositionChange = this.positionChangeEvent.pipe(stream.distinctUntilChanged());
2262
- }
2263
- refresh() {
2264
- //
2265
- }
2266
- destroy() {
2267
- this.subs.forEach(i => i.unsubscribe());
2268
- this.subs = [];
2269
- }
2270
- }
2271
- exports.NativeInput = class NativeInput extends Input {
2272
- set disabled(b) {
2273
- this._disabled = b;
2274
- if (this.controller.readonly) {
2275
- this.documentView.contentEditable = 'false';
2276
- return;
2277
- }
2278
- this.documentView.contentEditable = b ? 'false' : 'true';
2279
- }
2280
- get disabled() {
2281
- return this._disabled;
2282
- }
2283
- constructor(textbus, parser, selection, keyboard, domAdapter, commander, controller) {
2284
- super();
2285
- Object.defineProperty(this, "parser", {
2286
- enumerable: true,
2287
- configurable: true,
2288
- writable: true,
2289
- value: parser
2290
- });
2291
- Object.defineProperty(this, "selection", {
2292
- enumerable: true,
2293
- configurable: true,
2294
- writable: true,
2295
- value: selection
2296
- });
2297
- Object.defineProperty(this, "keyboard", {
2298
- enumerable: true,
2299
- configurable: true,
2300
- writable: true,
2301
- value: keyboard
2302
- });
2303
- Object.defineProperty(this, "domAdapter", {
2304
- enumerable: true,
2305
- configurable: true,
2306
- writable: true,
2307
- value: domAdapter
2308
- });
2309
- Object.defineProperty(this, "commander", {
2310
- enumerable: true,
2311
- configurable: true,
2312
- writable: true,
2313
- value: commander
2314
- });
2315
- Object.defineProperty(this, "controller", {
2316
- enumerable: true,
2317
- configurable: true,
2318
- writable: true,
2319
- value: controller
2320
- });
2321
- Object.defineProperty(this, "caret", {
2322
- enumerable: true,
2323
- configurable: true,
2324
- writable: true,
2325
- value: new NativeCaret()
2326
- });
2327
- Object.defineProperty(this, "composition", {
2328
- enumerable: true,
2329
- configurable: true,
2330
- writable: true,
2331
- value: false
2332
- });
2333
- // compositionState: CompositionState | null = null
2334
- Object.defineProperty(this, "onReady", {
2335
- enumerable: true,
2336
- configurable: true,
2337
- writable: true,
2338
- value: Promise.resolve()
2339
- });
2340
- Object.defineProperty(this, "_disabled", {
2341
- enumerable: true,
2342
- configurable: true,
2343
- writable: true,
2344
- value: false
2345
- });
2346
- Object.defineProperty(this, "documentView", {
2347
- enumerable: true,
2348
- configurable: true,
2349
- writable: true,
2350
- value: void 0
2351
- });
2352
- Object.defineProperty(this, "nativeSelection", {
2353
- enumerable: true,
2354
- configurable: true,
2355
- writable: true,
2356
- value: document.getSelection()
2357
- });
2358
- Object.defineProperty(this, "subscription", {
2359
- enumerable: true,
2360
- configurable: true,
2361
- writable: true,
2362
- value: new stream.Subscription()
2363
- });
2364
- Object.defineProperty(this, "nativeRange", {
2365
- enumerable: true,
2366
- configurable: true,
2367
- writable: true,
2368
- value: null
2369
- });
2370
- Object.defineProperty(this, "isSafari", {
2371
- enumerable: true,
2372
- configurable: true,
2373
- writable: true,
2374
- value: isSafari()
2375
- });
2376
- Object.defineProperty(this, "isMac", {
2377
- enumerable: true,
2378
- configurable: true,
2379
- writable: true,
2380
- value: isMac()
2381
- });
2382
- Object.defineProperty(this, "isMobileBrowser", {
2383
- enumerable: true,
2384
- configurable: true,
2385
- writable: true,
2386
- value: isMobileBrowser()
2387
- });
2388
- Object.defineProperty(this, "ignoreComposition", {
2389
- enumerable: true,
2390
- configurable: true,
2391
- writable: true,
2392
- value: false
2393
- }); // 有 bug 版本搜狗拼音
2394
- this.documentView = textbus.get(VIEW_DOCUMENT);
2395
- if (!controller.readonly) {
2396
- this.documentView.contentEditable = 'true';
2397
- }
2398
- this.subscription.add(controller.onReadonlyStateChange.subscribe(() => {
2399
- this.documentView.contentEditable = controller.readonly ? 'false' : 'true';
2400
- }));
2401
- this.handleShortcut(this.documentView);
2402
- this.handleInput(this.documentView);
2403
- this.handleDefaultActions(this.documentView);
2404
- }
2405
- focus(nativeRange) {
2406
- if (this.controller.readonly) {
2407
- return;
2408
- }
2409
- this.caret.nativeRange = nativeRange;
2410
- this.nativeRange = nativeRange;
2411
- }
2412
- blur() {
2413
- if (this.nativeRange && this.nativeSelection.rangeCount > 0) {
2414
- const current = this.nativeSelection.getRangeAt(0);
2415
- if (current === this.nativeRange) {
2416
- this.nativeSelection.removeAllRanges();
2417
- this.nativeRange = null;
2418
- return;
2419
- }
2420
- }
2421
- }
2422
- destroy() {
2423
- this.caret.destroy();
2424
- this.subscription.unsubscribe();
2425
- }
2426
- handleDefaultActions(textarea) {
2427
- this.subscription.add(stream.fromEvent(isFirefox() ? textarea : document, 'copy').subscribe(ev => {
2428
- this.copyHandler(ev);
2429
- }), stream.fromEvent(textarea, 'paste').subscribe(ev => {
2430
- this.pasteHandler(ev);
2431
- }));
2432
- }
2433
- copyHandler(ev) {
2434
- const selection = this.selection;
2435
- if (!selection.isSelected) {
2436
- return;
2437
- }
2438
- if (selection.startSlot === selection.endSlot && selection.endOffset - selection.startOffset === 1) {
2439
- const content = selection.startSlot.getContentAtIndex(selection.startOffset);
2440
- if (typeof content === 'object') {
2441
- const clipboardData = ev.clipboardData;
2442
- const nativeSelection = document.getSelection();
2443
- const range = nativeSelection.getRangeAt(0);
2444
- const div = document.createElement('div');
2445
- const fragment = range.cloneContents();
2446
- div.append(fragment);
2447
- clipboardData.setData('text/html', div.innerHTML);
2448
- clipboardData.setData('text', div.innerText);
2449
- ev.preventDefault();
2450
- }
2451
- }
2452
- }
2453
- pasteHandler(ev) {
2454
- const text = ev.clipboardData.getData('Text');
2455
- const types = Array.from(ev.clipboardData.types || []);
2456
- const files = Array.from(ev.clipboardData.files);
2457
- if (types.every(type => type === 'Files') && files.length) {
2458
- Promise.all(files.filter(i => {
2459
- return /image/i.test(i.type);
2460
- }).map(item => {
2461
- const reader = new FileReader();
2462
- return new Promise(resolve => {
2463
- reader.onload = (event) => {
2464
- resolve(event.target.result);
2465
- };
2466
- reader.readAsDataURL(item);
2467
- });
2468
- })).then(urls => {
2469
- const html = urls.map(i => {
2470
- return `<img src=${i}>`;
2471
- }).join('');
2472
- this.paste(html, text);
2473
- });
2474
- ev.preventDefault();
2475
- return;
2476
- }
2477
- const div = document.createElement('div');
2478
- div.style.cssText = 'width:1px; height:10px; overflow: hidden; position: fixed; left: 50%; top: 50%; opacity:0';
2479
- div.contentEditable = 'true';
2480
- document.body.appendChild(div);
2481
- div.focus();
2482
- setTimeout(() => {
2483
- document.body.removeChild(div);
2484
- div.style.cssText = '';
2485
- this.paste(div, text);
2486
- });
2487
- }
2488
- paste(dom, text) {
2489
- const slot = this.parser.parse(dom, new core$1.Slot([
2490
- core$1.ContentType.BlockComponent,
2491
- core$1.ContentType.InlineComponent,
2492
- core$1.ContentType.Text
2493
- ]));
2494
- this.commander.paste(slot, text);
2495
- }
2496
- handleShortcut(input) {
2497
- let isWriting = false;
2498
- let isIgnore = false;
2499
- this.subscription.add(stream.fromEvent(input, 'compositionstart').subscribe(() => {
2500
- isWriting = true;
2501
- }), stream.fromEvent(input, 'compositionend').subscribe(() => {
2502
- isWriting = false;
2503
- }), stream.fromEvent(input, 'beforeinput').subscribe(ev => {
2504
- if (this.isSafari) {
2505
- if (ev.inputType === 'insertFromComposition') {
2506
- isIgnore = true;
2507
- }
2508
- }
2509
- }), stream.fromEvent(input, 'keydown').pipe(stream.filter(() => {
2510
- if (this.isSafari && isIgnore) {
2511
- isIgnore = false;
2512
- return false;
2513
- }
2514
- return !isWriting; // || !this.textarea.value
2515
- })).subscribe(ev => {
2516
- this.ignoreComposition = false;
2517
- let key = ev.key;
2518
- const keys = ')!@#$%^Z&*(';
2519
- const b = key === 'Process' && /Digit\d/.test(ev.code) && ev.shiftKey;
2520
- if (b) {
2521
- key = keys.charAt(+ev.code.substring(5));
2522
- ev.preventDefault();
2523
- }
2524
- const is = this.keyboard.execShortcut({
2525
- key: key,
2526
- altKey: ev.altKey,
2527
- shiftKey: ev.shiftKey,
2528
- modKey: this.isMac ? ev.metaKey : ev.ctrlKey,
2529
- agent: {
2530
- key: ev.key,
2531
- keyCode: ev.keyCode,
2532
- code: ev.code
2533
- }
2534
- });
2535
- if (is) {
2536
- this.ignoreComposition = true;
2537
- ev.preventDefault();
2538
- }
2539
- }));
2540
- }
2541
- handleInput(input) {
2542
- if (this.isMobileBrowser) {
2543
- this.handleMobileInput(input);
2544
- }
2545
- else {
2546
- this.handlePCInput(input);
2547
- }
2548
- }
2549
- handleMobileInput(input) {
2550
- let isCompositionStart = true;
2551
- let startIndex;
2552
- const compositionStart = () => {
2553
- this.composition = true;
2554
- startIndex = this.selection.startOffset;
2555
- const startSlot = this.selection.startSlot;
2556
- const event = new core$1.Event(startSlot, {
2557
- index: startIndex
2558
- });
2559
- core$1.invokeListener(startSlot.parent, 'onCompositionStart', event);
2560
- };
2561
- const compositionUpdate = (data) => {
2562
- const startSlot = this.selection.startSlot;
2563
- const event = new core$1.Event(startSlot, {
2564
- index: startIndex,
2565
- data
2566
- });
2567
- core$1.invokeListener(startSlot.parent, 'onCompositionUpdate', event);
2568
- };
2569
- const compositionEnd = (data) => {
2570
- this.composition = false;
2571
- if (data) {
2572
- this.commander.write(data);
2573
- }
2574
- const startSlot = this.selection.startSlot;
2575
- if (startSlot) {
2576
- const event = new core$1.Event(startSlot, null);
2577
- core$1.invokeListener(startSlot.parent, 'onCompositionEnd', event);
2578
- }
2579
- };
2580
- this.subscription.add(stream.fromEvent(input, 'compositionstart').subscribe(() => {
2581
- compositionStart();
2582
- }), stream.fromEvent(input, 'compositionupdate').subscribe(ev => {
2583
- compositionUpdate(ev.data);
2584
- }), stream.fromEvent(input, 'compositionend').subscribe(ev => {
2585
- compositionEnd(ev.data);
2586
- const startContainer = this.nativeSelection.focusNode;
2587
- if (startContainer instanceof Text && startContainer.textContent === ev.data) {
2588
- startContainer.remove();
2589
- }
2590
- }), stream.fromEvent(input, 'beforeinput').subscribe(ev => {
2591
- var _a;
2592
- switch (ev.inputType) {
2593
- case 'insertText':
2594
- if (ev.data) {
2595
- this.commander.write(ev.data);
2596
- ev.preventDefault();
2597
- }
2598
- break;
2599
- case 'insertCompositionText':
2600
- if (isCompositionStart) {
2601
- isCompositionStart = false;
2602
- compositionStart();
2603
- }
2604
- else {
2605
- compositionUpdate(ev.data || '');
2606
- }
2607
- break;
2608
- case 'deleteCompositionText':
2609
- this.composition = false;
2610
- break;
2611
- case 'deleteContentBackward': {
2612
- this.composition = false;
2613
- const range = ev.getTargetRanges()[0];
2614
- if (!range) {
2615
- break;
2616
- }
2617
- const location = this.domAdapter.getLocationByNativeNode(range.startContainer);
2618
- const startSlot = this.selection.startSlot;
2619
- if (startSlot) {
2620
- this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
2621
- this.commander.delete();
2622
- }
2623
- break;
2624
- }
2625
- case 'insertReplacementText': {
2626
- this.composition = false;
2627
- const range = ev.getTargetRanges()[0];
2628
- const location = this.domAdapter.getLocationByNativeNode(range.startContainer);
2629
- const startSlot = this.selection.startSlot;
2630
- this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
2631
- this.commander.delete();
2632
- const text = ((_a = ev.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData('text')) || ev.data || null;
2633
- if (text) {
2634
- this.commander.write(text);
2635
- }
2636
- break;
2637
- }
2638
- //
2639
- // case 'insertFromComposition': {
2640
- // compositionEnd(ev.data || '')
2641
- // break
2642
- // }
2643
- }
2644
- }));
2645
- }
2646
- handlePCInput(input) {
2647
- let startIndex = 0;
2648
- let isCompositionEnd = false;
2649
- this.subscription.add(stream.fromEvent(input, 'compositionstart').pipe(stream.filter(() => {
2650
- return !this.ignoreComposition;
2651
- })).subscribe(() => {
2652
- this.composition = true;
2653
- startIndex = this.selection.startOffset;
2654
- const startSlot = this.selection.startSlot;
2655
- const event = new core$1.Event(startSlot, {
2656
- index: startIndex
2657
- });
2658
- core$1.invokeListener(startSlot.parent, 'onCompositionStart', event);
2659
- }), stream.fromEvent(input, 'compositionupdate').pipe(stream.filter(() => {
2660
- return !this.ignoreComposition;
2661
- })).subscribe(ev => {
2662
- const startSlot = this.selection.startSlot;
2663
- const event = new core$1.Event(startSlot, {
2664
- index: startIndex,
2665
- data: ev.data
2666
- });
2667
- core$1.invokeListener(startSlot.parent, 'onCompositionUpdate', event);
2668
- }), stream.merge(stream.fromEvent(input, 'beforeinput').pipe(stream.map(ev => {
2669
- var _a;
2670
- ev.preventDefault();
2671
- if (ev.inputType === 'insertCompositionText') {
2672
- return null;
2673
- }
2674
- if (ev.inputType === 'insertReplacementText') {
2675
- const range = ev.getTargetRanges()[0];
2676
- const location = this.domAdapter.getLocationByNativeNode(range.startContainer);
2677
- const startSlot = this.selection.startSlot;
2678
- this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
2679
- this.commander.delete();
2680
- return ((_a = ev.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData('text')) || ev.data || null;
2681
- }
2682
- isCompositionEnd = ev.inputType === 'insertFromComposition';
2683
- if (isCompositionEnd && this.composition) {
2684
- return null;
2685
- }
2686
- if (this.isSafari) {
2687
- if (ev.inputType === 'insertText' || isCompositionEnd) {
2688
- return ev.data;
2689
- }
2690
- }
2691
- if (!ev.isComposing && !!ev.data) {
2692
- return ev.data;
2693
- }
2694
- return null;
2695
- }), stream.filter(text => {
2696
- return text;
2697
- })), this.isSafari ? new stream.Observable() :
2698
- stream.fromEvent(input, 'compositionend').pipe(stream.filter(() => {
2699
- return !this.ignoreComposition;
2700
- })).pipe(stream.filter(() => {
2701
- return this.composition;
2702
- }), stream.map(ev => {
2703
- isCompositionEnd = true;
2704
- ev.preventDefault();
2705
- return ev.data;
2706
- }), stream.filter(() => {
2707
- const b = this.ignoreComposition;
2708
- this.ignoreComposition = false;
2709
- return !b;
2710
- }))).subscribe(text => {
2711
- this.composition = false;
2712
- if (text) {
2713
- const startContainer = this.nativeSelection.focusNode;
2714
- if (startContainer instanceof Text && startContainer.textContent === text) {
2715
- startContainer.remove();
2716
- }
2717
- this.commander.write(text);
2718
- }
2719
- if (isCompositionEnd) {
2720
- const startSlot = this.selection.startSlot;
2721
- if (startSlot) {
2722
- const event = new core$1.Event(startSlot, null);
2723
- core$1.invokeListener(startSlot.parent, 'onCompositionEnd', event);
2724
- }
2725
- }
2726
- isCompositionEnd = false;
2727
- }));
2728
- }
2729
- };
2730
- exports.NativeInput = __decorate([
2731
- core.Injectable(),
2732
- __metadata("design:paramtypes", [core$1.Textbus,
2733
- exports.Parser,
2734
- core$1.Selection,
2735
- core$1.Keyboard,
2736
- DomAdapter,
2737
- core$1.Commander,
2738
- core$1.Controller])
2739
- ], exports.NativeInput);
2740
-
2741
- const browserErrorFn = core$1.makeError('BrowserModule');
2742
- class BrowserModule {
2743
- constructor(config) {
2744
- Object.defineProperty(this, "config", {
2745
- enumerable: true,
2746
- configurable: true,
2747
- writable: true,
2748
- value: config
2749
- });
2750
- Object.defineProperty(this, "providers", {
2751
- enumerable: true,
2752
- configurable: true,
2753
- writable: true,
2754
- value: void 0
2755
- });
2756
- Object.defineProperty(this, "workbench", {
2757
- enumerable: true,
2758
- configurable: true,
2759
- writable: true,
2760
- value: void 0
2761
- });
2762
- const { mask, wrapper } = BrowserModule.createLayout();
2763
- wrapper.prepend(config.adapter.host);
2764
- if (config.minHeight) {
2765
- config.adapter.host.style.minHeight = config.minHeight;
2766
- }
2767
- this.providers = [{
2768
- provide: EDITOR_OPTIONS,
2769
- useValue: config
2770
- }, {
2771
- provide: VIEW_CONTAINER,
2772
- useValue: wrapper
2773
- }, {
2774
- provide: VIEW_DOCUMENT,
2775
- useValue: config.adapter.host
2776
- }, {
2777
- provide: VIEW_MASK,
2778
- useValue: mask
2779
- }, {
2780
- provide: core$1.NativeSelectionBridge,
2781
- useExisting: exports.SelectionBridge
2782
- }, {
2783
- provide: Input,
2784
- useClass: config.useContentEditable ? exports.NativeInput : exports.MagicInput
2785
- }, {
2786
- provide: core$1.Adapter,
2787
- useValue: config.adapter
2788
- }, {
2789
- provide: DomAdapter,
2790
- useValue: config.adapter
2791
- }, {
2792
- provide: core$1.FocusManager,
2793
- useFactory: (input) => {
2794
- const focusEvent = new stream.Subject();
2795
- const blurEvent = new stream.Subject();
2796
- input.caret.onPositionChange.pipe(stream.map(p => !!p), stream.distinctUntilChanged()).subscribe(b => {
2797
- if (b) {
2798
- focusEvent.next();
2799
- }
2800
- else {
2801
- blurEvent.next();
2802
- }
2803
- });
2804
- return {
2805
- onFocus: focusEvent,
2806
- onBlur: blurEvent
2807
- };
2808
- },
2809
- deps: [Input]
2810
- },
2811
- exports.Parser,
2812
- exports.SelectionBridge,
2813
- exports.CollaborateCursor];
2814
- this.workbench = wrapper;
2815
- }
2816
- /**
2817
- * 解析 HTML 并返回一个组件实例
2818
- * @param html 要解析的 HTML
2819
- * @param rootComponentLoader 文档根组件加载器
2820
- * @param textbus
2821
- */
2822
- readDocumentByHTML(html, rootComponentLoader, textbus) {
2823
- const parser = textbus.get(exports.Parser);
2824
- const doc = parser.parseDoc(html, rootComponentLoader);
2825
- if (doc instanceof core$1.Component) {
2826
- return doc;
2827
- }
2828
- throw browserErrorFn('rootComponentLoader must return a component instance.');
2829
- }
2830
- /**
2831
- * 将组件数据解析到组件实例中
2832
- * @param data 要解析的 JSON 数据
2833
- * @param rootComponent 根组件
2834
- * @param textbus
2835
- */
2836
- readDocumentByComponentLiteral(data, rootComponent, textbus) {
2837
- const registry = textbus.get(core$1.Registry);
2838
- return registry.createComponentByFactory(data, rootComponent);
2839
- }
2840
- setup(textbus) {
2841
- return __awaiter(this, void 0, void 0, function* () {
2842
- const host = this.config.renderTo();
2843
- if (!(host instanceof HTMLElement)) {
2844
- throw browserErrorFn('view container is not a HTMLElement');
2845
- }
2846
- host.append(this.workbench);
2847
- yield textbus.get(Input).onReady;
2848
- return () => {
2849
- this.workbench.remove();
2850
- };
2851
- });
2852
- }
2853
- onAfterStartup(textbus) {
2854
- if (this.config.autoFocus) {
2855
- textbus.focus();
2856
- }
2857
- }
2858
- onDestroy(textbus) {
2859
- textbus.get(Input).destroy();
2860
- textbus.get(exports.SelectionBridge).destroy();
2861
- textbus.get(exports.CollaborateCursor).destroy();
2862
- }
2863
- static createLayout() {
2864
- const mask = createElement('div', {
2865
- attrs: {
2866
- 'data-textbus-view': VIEW_MASK,
2867
- },
2868
- styles: {
2869
- position: 'absolute',
2870
- left: 0,
2871
- right: 0,
2872
- top: 0,
2873
- bottom: 0,
2874
- pointerEvents: 'none',
2875
- // overflow: 'hidden'
2876
- }
2877
- });
2878
- const maskWrapper = createElement('div', {
2879
- styles: {
2880
- position: 'absolute',
2881
- left: 0,
2882
- right: 0,
2883
- top: 0,
2884
- bottom: 0,
2885
- margin: '0 -2px',
2886
- zIndex: 1,
2887
- pointerEvents: 'none',
2888
- overflow: 'hidden'
2889
- },
2890
- children: [mask]
2891
- });
2892
- const wrapper = createElement('div', {
2893
- attrs: {
2894
- 'data-textbus-view': VIEW_CONTAINER,
2895
- },
2896
- styles: {
2897
- display: 'flex',
2898
- minHeight: '100%',
2899
- position: 'relative',
2900
- flexDirection: 'column'
2901
- },
2902
- children: [maskWrapper]
2903
- });
2904
- return {
2905
- wrapper,
2906
- mask
2907
- };
2908
- }
2909
- }
2910
-
2911
- exports.BrowserModule = BrowserModule;
2912
- exports.CollaborateSelectionAwarenessDelegate = CollaborateSelectionAwarenessDelegate;
2913
- exports.DomAdapter = DomAdapter;
2914
- exports.EDITOR_OPTIONS = EDITOR_OPTIONS;
2915
- exports.Input = Input;
2916
- exports.VIEW_CONTAINER = VIEW_CONTAINER;
2917
- exports.VIEW_DOCUMENT = VIEW_DOCUMENT;
2918
- exports.VIEW_MASK = VIEW_MASK;
2919
- exports.createElement = createElement;
2920
- exports.getLayoutRectByRange = getLayoutRectByRange;
2921
- exports.isFirefox = isFirefox;
2922
- exports.isMac = isMac;
2923
- exports.isMobileBrowser = isMobileBrowser;
2924
- exports.isSafari = isSafari;
2925
- exports.isWindows = isWindows;