@textbus/platform-browser 4.0.0-alpha.32 → 4.0.0-alpha.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/collaborate-cursor.d.ts +1 -0
- package/bundles/dom-adapter.d.ts +9 -0
- package/bundles/index.esm.js +110 -57
- package/bundles/index.js +109 -56
- package/bundles/magic-input.d.ts +6 -6
- package/bundles/native-input.d.ts +1 -2
- package/bundles/types.d.ts +0 -7
- package/package.json +5 -5
@@ -36,6 +36,7 @@ export declare class CollaborateCursor {
|
|
36
36
|
private subscription;
|
37
37
|
private currentSelection;
|
38
38
|
private container;
|
39
|
+
private ratio;
|
39
40
|
constructor(textbus: Textbus, nativeSelection: SelectionBridge, scheduler: Scheduler, selection: Selection, userActivity: UserActivity, awarenessDelegate?: CollaborateSelectionAwarenessDelegate | undefined);
|
40
41
|
init(): void;
|
41
42
|
/**
|
package/bundles/dom-adapter.d.ts
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
import { Component, Slot, ViewAdapter, NodeLocation, VElement, VTextNode, Textbus } from '@textbus/core';
|
2
|
+
export interface CompositionState {
|
3
|
+
slot: Slot;
|
4
|
+
text: string;
|
5
|
+
offset: number;
|
6
|
+
index: number;
|
7
|
+
}
|
2
8
|
/**
|
3
9
|
* Textbus PC 端浏览器渲染能力桥接器抽象类,提供了 DOM 元素查询能力,具体渲染能力由各前端框架实现相应桥接
|
4
10
|
*/
|
5
11
|
export declare abstract class DomAdapter<ViewComponent, ViewElement> extends ViewAdapter {
|
6
12
|
private mount;
|
7
13
|
host: HTMLElement;
|
14
|
+
compositionNode: HTMLElement | null;
|
15
|
+
composition: CompositionState | null;
|
8
16
|
protected firstRending: boolean;
|
9
17
|
protected componentRootElementCaches: {
|
10
18
|
set: {
|
@@ -64,4 +72,5 @@ export declare abstract class DomAdapter<ViewComponent, ViewElement> extends Vie
|
|
64
72
|
* @param node
|
65
73
|
*/
|
66
74
|
getLocationByNativeNode(node: Node): NodeLocation | null;
|
75
|
+
protected insertCompositionByIndex(slot: Slot, vNode: VElement, composition: CompositionState, createCompositionNode: (composition: CompositionState) => VElement): void;
|
67
76
|
}
|
package/bundles/index.esm.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import 'reflect-metadata';
|
2
|
-
import { Slot, Textbus, ViewAdapter, createBidirectionalMapping, Component,
|
2
|
+
import { Slot, Textbus, ViewAdapter, createBidirectionalMapping, Component, VTextNode, VElement, Controller, Selection, RootComponentRef, ContentType, Event, invokeListener, Keyboard, Commander, Scheduler, makeError, NativeSelectionBridge, FocusManager, Registry } from '@textbus/core';
|
3
3
|
import { Subject, filter, fromEvent, Subscription, distinctUntilChanged, merge, map, Observable } from '@tanbo/stream';
|
4
4
|
import { InjectionToken, Injectable, Inject, Optional } from '@viewfly/core';
|
5
5
|
import { UserActivity } from '@textbus/collaborate';
|
@@ -323,6 +323,8 @@ class DomAdapter extends ViewAdapter {
|
|
323
323
|
id: 'textbus-' + Number((Math.random() + '').substring(2)).toString(16)
|
324
324
|
}
|
325
325
|
});
|
326
|
+
this.compositionNode = null;
|
327
|
+
this.composition = null;
|
326
328
|
this.firstRending = true;
|
327
329
|
this.componentRootElementCaches = createBidirectionalMapping(a => {
|
328
330
|
return a instanceof Component;
|
@@ -396,6 +398,70 @@ class DomAdapter extends ViewAdapter {
|
|
396
398
|
const rootVNode = this.slotRootVElementCaches.get(slot);
|
397
399
|
return getLocation(node, slotRootNode, rootVNode);
|
398
400
|
}
|
401
|
+
insertCompositionByIndex(slot, vNode, composition, createCompositionNode) {
|
402
|
+
const location = vNode.location;
|
403
|
+
const nodes = vNode.children;
|
404
|
+
if (location && location.slot === composition.slot) {
|
405
|
+
for (let i = 0; i < nodes.length; i++) {
|
406
|
+
const child = nodes[i];
|
407
|
+
if (child instanceof VTextNode) {
|
408
|
+
const childLocation = child.location;
|
409
|
+
if (childLocation) {
|
410
|
+
if (composition.index > childLocation.startIndex && composition.index <= childLocation.endIndex) {
|
411
|
+
const compositionNode = createCompositionNode(composition);
|
412
|
+
if (composition.index === childLocation.endIndex) {
|
413
|
+
nodes.splice(i + 1, 0, compositionNode);
|
414
|
+
break;
|
415
|
+
}
|
416
|
+
const splitIndex = composition.index - childLocation.startIndex;
|
417
|
+
const beforeNode = new VTextNode(child.textContent.slice(0, splitIndex));
|
418
|
+
beforeNode.location = {
|
419
|
+
slot: childLocation.slot,
|
420
|
+
startIndex: childLocation.startIndex,
|
421
|
+
endIndex: childLocation.startIndex + splitIndex
|
422
|
+
};
|
423
|
+
const afterNode = new VTextNode(child.textContent.slice(splitIndex));
|
424
|
+
afterNode.location = {
|
425
|
+
slot: childLocation.slot,
|
426
|
+
startIndex: composition.index,
|
427
|
+
endIndex: childLocation.endIndex
|
428
|
+
};
|
429
|
+
nodes.splice(i, 1, beforeNode, compositionNode, afterNode);
|
430
|
+
break;
|
431
|
+
}
|
432
|
+
else if (composition.index === 0 && childLocation.startIndex === 0) {
|
433
|
+
nodes.unshift(createCompositionNode(composition));
|
434
|
+
break;
|
435
|
+
}
|
436
|
+
}
|
437
|
+
}
|
438
|
+
else if (child instanceof Component) {
|
439
|
+
const componentIndex = slot.indexOf(child);
|
440
|
+
if (composition.index === componentIndex + 1) {
|
441
|
+
nodes.splice(i + 1, 0, createCompositionNode(composition));
|
442
|
+
break;
|
443
|
+
}
|
444
|
+
else if (componentIndex === 0 && composition.index === 0) {
|
445
|
+
nodes.unshift(createCompositionNode(composition));
|
446
|
+
break;
|
447
|
+
}
|
448
|
+
}
|
449
|
+
else if (child.tagName === 'br') {
|
450
|
+
const location = child.location;
|
451
|
+
if (location) {
|
452
|
+
if (location.endIndex === composition.index) {
|
453
|
+
nodes.splice(i + 1, 0, createCompositionNode(composition));
|
454
|
+
break;
|
455
|
+
}
|
456
|
+
else if (location.startIndex === 0 && composition.index === 0) {
|
457
|
+
nodes.unshift(createCompositionNode(composition));
|
458
|
+
break;
|
459
|
+
}
|
460
|
+
}
|
461
|
+
}
|
462
|
+
}
|
463
|
+
}
|
464
|
+
}
|
399
465
|
}
|
400
466
|
function getNodes(adapter, vElement, nativeNode, result) {
|
401
467
|
if (vElement.location) {
|
@@ -1032,15 +1098,10 @@ class ExperimentalCaret {
|
|
1032
1098
|
get display() {
|
1033
1099
|
return this._display;
|
1034
1100
|
}
|
1035
|
-
constructor(scheduler, editorMask) {
|
1101
|
+
constructor(adapter, scheduler, editorMask) {
|
1102
|
+
this.adapter = adapter;
|
1036
1103
|
this.scheduler = scheduler;
|
1037
1104
|
this.editorMask = editorMask;
|
1038
|
-
this.compositionState = null;
|
1039
|
-
this.compositionElement = createElement('span', {
|
1040
|
-
styles: {
|
1041
|
-
textDecoration: 'underline'
|
1042
|
-
}
|
1043
|
-
});
|
1044
1105
|
this.timer = null;
|
1045
1106
|
this.oldPosition = null;
|
1046
1107
|
this._display = true;
|
@@ -1184,12 +1245,10 @@ class ExperimentalCaret {
|
|
1184
1245
|
this.positionChangeEvent.next(null);
|
1185
1246
|
return;
|
1186
1247
|
}
|
1187
|
-
|
1188
|
-
|
1189
|
-
compositionElement.innerText = this.compositionState.data;
|
1248
|
+
const compositionNode = this.adapter.compositionNode;
|
1249
|
+
if (compositionNode) {
|
1190
1250
|
nativeRange = nativeRange.cloneRange();
|
1191
|
-
nativeRange.
|
1192
|
-
nativeRange.selectNodeContents(compositionElement);
|
1251
|
+
nativeRange.selectNodeContents(compositionNode);
|
1193
1252
|
nativeRange.collapse();
|
1194
1253
|
}
|
1195
1254
|
const rect = getLayoutRectByRange(nativeRange);
|
@@ -1250,8 +1309,9 @@ let MagicInput = class MagicInput extends Input {
|
|
1250
1309
|
get disabled() {
|
1251
1310
|
return this._disabled;
|
1252
1311
|
}
|
1253
|
-
constructor(parser, keyboard, commander, selection, controller, scheduler, textbus) {
|
1312
|
+
constructor(adapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
|
1254
1313
|
super();
|
1314
|
+
this.adapter = adapter;
|
1255
1315
|
this.parser = parser;
|
1256
1316
|
this.keyboard = keyboard;
|
1257
1317
|
this.commander = commander;
|
@@ -1260,8 +1320,7 @@ let MagicInput = class MagicInput extends Input {
|
|
1260
1320
|
this.scheduler = scheduler;
|
1261
1321
|
this.textbus = textbus;
|
1262
1322
|
this.composition = false;
|
1263
|
-
this.
|
1264
|
-
this.caret = new ExperimentalCaret(this.scheduler, this.textbus.get(VIEW_MASK));
|
1323
|
+
this.caret = new ExperimentalCaret(this.adapter, this.scheduler, this.textbus.get(VIEW_MASK));
|
1265
1324
|
this.isSafari = isSafari();
|
1266
1325
|
this.isFirefox = isFirefox();
|
1267
1326
|
this.isMac = isMac();
|
@@ -1342,12 +1401,19 @@ let MagicInput = class MagicInput extends Input {
|
|
1342
1401
|
contentBody.appendChild(textarea);
|
1343
1402
|
this.textarea = textarea;
|
1344
1403
|
this.subscription.add(fromEvent(textarea, 'blur').subscribe(() => {
|
1345
|
-
if (this.isFocus) {
|
1346
|
-
|
1347
|
-
|
1348
|
-
}
|
1404
|
+
// if (this.isFocus) {
|
1405
|
+
// this.isFocus = false
|
1406
|
+
// this.reInit(true)
|
1407
|
+
// }
|
1408
|
+
this.isFocus = false;
|
1349
1409
|
this.nativeFocus = false;
|
1350
1410
|
this.caret.hide();
|
1411
|
+
if (this.adapter.composition) {
|
1412
|
+
const slot = this.adapter.composition.slot;
|
1413
|
+
this.adapter.composition = null;
|
1414
|
+
this.adapter.compositionNode = null;
|
1415
|
+
slot.changeMarker.forceMarkDirtied();
|
1416
|
+
}
|
1351
1417
|
}), fromEvent(textarea, 'focus').subscribe(() => {
|
1352
1418
|
this.nativeFocus = true;
|
1353
1419
|
}), this.caret.onStyleChange.subscribe(style => {
|
@@ -1470,7 +1536,6 @@ let MagicInput = class MagicInput extends Input {
|
|
1470
1536
|
this.commander.delete();
|
1471
1537
|
}
|
1472
1538
|
this.composition = true;
|
1473
|
-
this.caret.compositionState = this.compositionState = null;
|
1474
1539
|
startIndex = this.selection.startOffset;
|
1475
1540
|
const startSlot = this.selection.startSlot;
|
1476
1541
|
const event = new Event(startSlot, {
|
@@ -1487,10 +1552,11 @@ let MagicInput = class MagicInput extends Input {
|
|
1487
1552
|
return;
|
1488
1553
|
}
|
1489
1554
|
const startSlot = this.selection.startSlot;
|
1490
|
-
this.
|
1555
|
+
this.adapter.composition = {
|
1491
1556
|
slot: startSlot,
|
1492
|
-
|
1493
|
-
|
1557
|
+
text: ev.data,
|
1558
|
+
offset: ev.data.length,
|
1559
|
+
index: startIndex
|
1494
1560
|
};
|
1495
1561
|
this.caret.refresh(true);
|
1496
1562
|
const event = new Event(startSlot, {
|
@@ -1498,6 +1564,7 @@ let MagicInput = class MagicInput extends Input {
|
|
1498
1564
|
data: ev.data
|
1499
1565
|
});
|
1500
1566
|
invokeListener(startSlot.parent, 'onCompositionUpdate', event);
|
1567
|
+
startSlot.changeMarker.forceMarkDirtied();
|
1501
1568
|
}));
|
1502
1569
|
let isCompositionEnd = false;
|
1503
1570
|
this.subscription.add(merge(fromEvent(textarea, 'beforeinput').pipe(filter(ev => {
|
@@ -1521,24 +1588,15 @@ let MagicInput = class MagicInput extends Input {
|
|
1521
1588
|
textarea.value = '';
|
1522
1589
|
return ev.data;
|
1523
1590
|
}))).subscribe(text => {
|
1591
|
+
var _a;
|
1524
1592
|
this.composition = false;
|
1525
|
-
this.
|
1526
|
-
const compositionElement = this.caret.compositionElement;
|
1527
|
-
let nextSibling = compositionElement.nextSibling;
|
1528
|
-
while (nextSibling) {
|
1529
|
-
if (!nextSibling.textContent) {
|
1530
|
-
const next = nextSibling.nextSibling;
|
1531
|
-
nextSibling.remove();
|
1532
|
-
nextSibling = next;
|
1533
|
-
continue;
|
1534
|
-
}
|
1535
|
-
nextSibling.remove();
|
1536
|
-
break;
|
1537
|
-
}
|
1538
|
-
compositionElement.remove();
|
1593
|
+
this.adapter.composition = null;
|
1539
1594
|
if (text) {
|
1540
1595
|
this.commander.write(text);
|
1541
1596
|
}
|
1597
|
+
else {
|
1598
|
+
(_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.changeMarker.forceMarkDirtied();
|
1599
|
+
}
|
1542
1600
|
if (isCompositionEnd) {
|
1543
1601
|
const startSlot = this.selection.startSlot;
|
1544
1602
|
if (startSlot) {
|
@@ -1567,7 +1625,8 @@ let MagicInput = class MagicInput extends Input {
|
|
1567
1625
|
};
|
1568
1626
|
MagicInput = __decorate([
|
1569
1627
|
Injectable(),
|
1570
|
-
__metadata("design:paramtypes", [
|
1628
|
+
__metadata("design:paramtypes", [DomAdapter,
|
1629
|
+
Parser,
|
1571
1630
|
Keyboard,
|
1572
1631
|
Commander,
|
1573
1632
|
Selection,
|
@@ -1639,6 +1698,7 @@ let CollaborateCursor = class CollaborateCursor {
|
|
1639
1698
|
this.onRectsChange = new Subject();
|
1640
1699
|
this.subscription = new Subscription();
|
1641
1700
|
this.currentSelection = [];
|
1701
|
+
this.ratio = window.devicePixelRatio || 1;
|
1642
1702
|
this.container = textbus.get(VIEW_CONTAINER);
|
1643
1703
|
this.canvasContainer.append(this.canvas);
|
1644
1704
|
this.host.append(this.canvasContainer, this.tooltips);
|
@@ -1682,8 +1742,9 @@ let CollaborateCursor = class CollaborateCursor {
|
|
1682
1742
|
this.currentSelection = paths;
|
1683
1743
|
const containerRect = this.container.getBoundingClientRect();
|
1684
1744
|
this.canvas.style.top = containerRect.top * -1 + 'px';
|
1685
|
-
this.canvas.width = this.canvas.offsetWidth;
|
1686
|
-
this.canvas.height = this.canvas.offsetHeight;
|
1745
|
+
this.canvas.width = this.canvas.offsetWidth * this.ratio;
|
1746
|
+
this.canvas.height = this.canvas.offsetHeight * this.ratio;
|
1747
|
+
this.context.scale(this.ratio, this.ratio);
|
1687
1748
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
1688
1749
|
const users = [];
|
1689
1750
|
paths.filter(i => {
|
@@ -1708,8 +1769,13 @@ let CollaborateCursor = class CollaborateCursor {
|
|
1708
1769
|
return;
|
1709
1770
|
}
|
1710
1771
|
const nativeRange = document.createRange();
|
1711
|
-
|
1712
|
-
|
1772
|
+
try {
|
1773
|
+
nativeRange.setStart(anchor.node, anchor.offset);
|
1774
|
+
nativeRange.setEnd(focus.node, focus.offset);
|
1775
|
+
}
|
1776
|
+
catch (e) {
|
1777
|
+
return;
|
1778
|
+
}
|
1713
1779
|
if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
|
1714
1780
|
nativeRange.setStart(focus.node, focus.offset);
|
1715
1781
|
nativeRange.setEnd(anchor.node, anchor.offset);
|
@@ -1972,7 +2038,7 @@ let NativeInput = class NativeInput extends Input {
|
|
1972
2038
|
this.controller = controller;
|
1973
2039
|
this.caret = new NativeCaret(this.scheduler);
|
1974
2040
|
this.composition = false;
|
1975
|
-
|
2041
|
+
// compositionState: CompositionState | null = null
|
1976
2042
|
this.onReady = Promise.resolve();
|
1977
2043
|
this._disabled = false;
|
1978
2044
|
this.nativeSelection = document.getSelection();
|
@@ -2130,7 +2196,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2130
2196
|
let startIndex;
|
2131
2197
|
const compositionStart = () => {
|
2132
2198
|
this.composition = true;
|
2133
|
-
this.compositionState = null;
|
2134
2199
|
startIndex = this.selection.startOffset;
|
2135
2200
|
const startSlot = this.selection.startSlot;
|
2136
2201
|
const event = new Event(startSlot, {
|
@@ -2140,11 +2205,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2140
2205
|
};
|
2141
2206
|
const compositionUpdate = (data) => {
|
2142
2207
|
const startSlot = this.selection.startSlot;
|
2143
|
-
this.compositionState = {
|
2144
|
-
slot: startSlot,
|
2145
|
-
index: startIndex,
|
2146
|
-
data
|
2147
|
-
};
|
2148
2208
|
const event = new Event(startSlot, {
|
2149
2209
|
index: startIndex,
|
2150
2210
|
data
|
@@ -2231,7 +2291,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2231
2291
|
return !this.ignoreComposition;
|
2232
2292
|
})).subscribe(() => {
|
2233
2293
|
this.composition = true;
|
2234
|
-
this.compositionState = null;
|
2235
2294
|
startIndex = this.selection.startOffset;
|
2236
2295
|
const startSlot = this.selection.startSlot;
|
2237
2296
|
const event = new Event(startSlot, {
|
@@ -2242,11 +2301,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2242
2301
|
return !this.ignoreComposition;
|
2243
2302
|
})).subscribe(ev => {
|
2244
2303
|
const startSlot = this.selection.startSlot;
|
2245
|
-
this.compositionState = {
|
2246
|
-
slot: startSlot,
|
2247
|
-
index: startIndex,
|
2248
|
-
data: ev.data
|
2249
|
-
};
|
2250
2304
|
const event = new Event(startSlot, {
|
2251
2305
|
index: startIndex,
|
2252
2306
|
data: ev.data
|
@@ -2296,7 +2350,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2296
2350
|
return !b;
|
2297
2351
|
}))).subscribe(text => {
|
2298
2352
|
this.composition = false;
|
2299
|
-
this.compositionState = null;
|
2300
2353
|
if (text) {
|
2301
2354
|
this.commander.write(text);
|
2302
2355
|
}
|
package/bundles/index.js
CHANGED
@@ -325,6 +325,8 @@ class DomAdapter extends core$1.ViewAdapter {
|
|
325
325
|
id: 'textbus-' + Number((Math.random() + '').substring(2)).toString(16)
|
326
326
|
}
|
327
327
|
});
|
328
|
+
this.compositionNode = null;
|
329
|
+
this.composition = null;
|
328
330
|
this.firstRending = true;
|
329
331
|
this.componentRootElementCaches = core$1.createBidirectionalMapping(a => {
|
330
332
|
return a instanceof core$1.Component;
|
@@ -398,6 +400,70 @@ class DomAdapter extends core$1.ViewAdapter {
|
|
398
400
|
const rootVNode = this.slotRootVElementCaches.get(slot);
|
399
401
|
return getLocation(node, slotRootNode, rootVNode);
|
400
402
|
}
|
403
|
+
insertCompositionByIndex(slot, vNode, composition, createCompositionNode) {
|
404
|
+
const location = vNode.location;
|
405
|
+
const nodes = vNode.children;
|
406
|
+
if (location && location.slot === composition.slot) {
|
407
|
+
for (let i = 0; i < nodes.length; i++) {
|
408
|
+
const child = nodes[i];
|
409
|
+
if (child instanceof core$1.VTextNode) {
|
410
|
+
const childLocation = child.location;
|
411
|
+
if (childLocation) {
|
412
|
+
if (composition.index > childLocation.startIndex && composition.index <= childLocation.endIndex) {
|
413
|
+
const compositionNode = createCompositionNode(composition);
|
414
|
+
if (composition.index === childLocation.endIndex) {
|
415
|
+
nodes.splice(i + 1, 0, compositionNode);
|
416
|
+
break;
|
417
|
+
}
|
418
|
+
const splitIndex = composition.index - childLocation.startIndex;
|
419
|
+
const beforeNode = new core$1.VTextNode(child.textContent.slice(0, splitIndex));
|
420
|
+
beforeNode.location = {
|
421
|
+
slot: childLocation.slot,
|
422
|
+
startIndex: childLocation.startIndex,
|
423
|
+
endIndex: childLocation.startIndex + splitIndex
|
424
|
+
};
|
425
|
+
const afterNode = new core$1.VTextNode(child.textContent.slice(splitIndex));
|
426
|
+
afterNode.location = {
|
427
|
+
slot: childLocation.slot,
|
428
|
+
startIndex: composition.index,
|
429
|
+
endIndex: childLocation.endIndex
|
430
|
+
};
|
431
|
+
nodes.splice(i, 1, beforeNode, compositionNode, afterNode);
|
432
|
+
break;
|
433
|
+
}
|
434
|
+
else if (composition.index === 0 && childLocation.startIndex === 0) {
|
435
|
+
nodes.unshift(createCompositionNode(composition));
|
436
|
+
break;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
}
|
440
|
+
else if (child instanceof core$1.Component) {
|
441
|
+
const componentIndex = slot.indexOf(child);
|
442
|
+
if (composition.index === componentIndex + 1) {
|
443
|
+
nodes.splice(i + 1, 0, createCompositionNode(composition));
|
444
|
+
break;
|
445
|
+
}
|
446
|
+
else if (componentIndex === 0 && composition.index === 0) {
|
447
|
+
nodes.unshift(createCompositionNode(composition));
|
448
|
+
break;
|
449
|
+
}
|
450
|
+
}
|
451
|
+
else if (child.tagName === 'br') {
|
452
|
+
const location = child.location;
|
453
|
+
if (location) {
|
454
|
+
if (location.endIndex === composition.index) {
|
455
|
+
nodes.splice(i + 1, 0, createCompositionNode(composition));
|
456
|
+
break;
|
457
|
+
}
|
458
|
+
else if (location.startIndex === 0 && composition.index === 0) {
|
459
|
+
nodes.unshift(createCompositionNode(composition));
|
460
|
+
break;
|
461
|
+
}
|
462
|
+
}
|
463
|
+
}
|
464
|
+
}
|
465
|
+
}
|
466
|
+
}
|
401
467
|
}
|
402
468
|
function getNodes(adapter, vElement, nativeNode, result) {
|
403
469
|
if (vElement.location) {
|
@@ -1034,15 +1100,10 @@ class ExperimentalCaret {
|
|
1034
1100
|
get display() {
|
1035
1101
|
return this._display;
|
1036
1102
|
}
|
1037
|
-
constructor(scheduler, editorMask) {
|
1103
|
+
constructor(adapter, scheduler, editorMask) {
|
1104
|
+
this.adapter = adapter;
|
1038
1105
|
this.scheduler = scheduler;
|
1039
1106
|
this.editorMask = editorMask;
|
1040
|
-
this.compositionState = null;
|
1041
|
-
this.compositionElement = createElement('span', {
|
1042
|
-
styles: {
|
1043
|
-
textDecoration: 'underline'
|
1044
|
-
}
|
1045
|
-
});
|
1046
1107
|
this.timer = null;
|
1047
1108
|
this.oldPosition = null;
|
1048
1109
|
this._display = true;
|
@@ -1186,12 +1247,10 @@ class ExperimentalCaret {
|
|
1186
1247
|
this.positionChangeEvent.next(null);
|
1187
1248
|
return;
|
1188
1249
|
}
|
1189
|
-
|
1190
|
-
|
1191
|
-
compositionElement.innerText = this.compositionState.data;
|
1250
|
+
const compositionNode = this.adapter.compositionNode;
|
1251
|
+
if (compositionNode) {
|
1192
1252
|
nativeRange = nativeRange.cloneRange();
|
1193
|
-
nativeRange.
|
1194
|
-
nativeRange.selectNodeContents(compositionElement);
|
1253
|
+
nativeRange.selectNodeContents(compositionNode);
|
1195
1254
|
nativeRange.collapse();
|
1196
1255
|
}
|
1197
1256
|
const rect = getLayoutRectByRange(nativeRange);
|
@@ -1252,8 +1311,9 @@ exports.MagicInput = class MagicInput extends Input {
|
|
1252
1311
|
get disabled() {
|
1253
1312
|
return this._disabled;
|
1254
1313
|
}
|
1255
|
-
constructor(parser, keyboard, commander, selection, controller, scheduler, textbus) {
|
1314
|
+
constructor(adapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
|
1256
1315
|
super();
|
1316
|
+
this.adapter = adapter;
|
1257
1317
|
this.parser = parser;
|
1258
1318
|
this.keyboard = keyboard;
|
1259
1319
|
this.commander = commander;
|
@@ -1262,8 +1322,7 @@ exports.MagicInput = class MagicInput extends Input {
|
|
1262
1322
|
this.scheduler = scheduler;
|
1263
1323
|
this.textbus = textbus;
|
1264
1324
|
this.composition = false;
|
1265
|
-
this.
|
1266
|
-
this.caret = new ExperimentalCaret(this.scheduler, this.textbus.get(VIEW_MASK));
|
1325
|
+
this.caret = new ExperimentalCaret(this.adapter, this.scheduler, this.textbus.get(VIEW_MASK));
|
1267
1326
|
this.isSafari = isSafari();
|
1268
1327
|
this.isFirefox = isFirefox();
|
1269
1328
|
this.isMac = isMac();
|
@@ -1344,12 +1403,19 @@ exports.MagicInput = class MagicInput extends Input {
|
|
1344
1403
|
contentBody.appendChild(textarea);
|
1345
1404
|
this.textarea = textarea;
|
1346
1405
|
this.subscription.add(stream.fromEvent(textarea, 'blur').subscribe(() => {
|
1347
|
-
if (this.isFocus) {
|
1348
|
-
|
1349
|
-
|
1350
|
-
}
|
1406
|
+
// if (this.isFocus) {
|
1407
|
+
// this.isFocus = false
|
1408
|
+
// this.reInit(true)
|
1409
|
+
// }
|
1410
|
+
this.isFocus = false;
|
1351
1411
|
this.nativeFocus = false;
|
1352
1412
|
this.caret.hide();
|
1413
|
+
if (this.adapter.composition) {
|
1414
|
+
const slot = this.adapter.composition.slot;
|
1415
|
+
this.adapter.composition = null;
|
1416
|
+
this.adapter.compositionNode = null;
|
1417
|
+
slot.changeMarker.forceMarkDirtied();
|
1418
|
+
}
|
1353
1419
|
}), stream.fromEvent(textarea, 'focus').subscribe(() => {
|
1354
1420
|
this.nativeFocus = true;
|
1355
1421
|
}), this.caret.onStyleChange.subscribe(style => {
|
@@ -1472,7 +1538,6 @@ exports.MagicInput = class MagicInput extends Input {
|
|
1472
1538
|
this.commander.delete();
|
1473
1539
|
}
|
1474
1540
|
this.composition = true;
|
1475
|
-
this.caret.compositionState = this.compositionState = null;
|
1476
1541
|
startIndex = this.selection.startOffset;
|
1477
1542
|
const startSlot = this.selection.startSlot;
|
1478
1543
|
const event = new core$1.Event(startSlot, {
|
@@ -1489,10 +1554,11 @@ exports.MagicInput = class MagicInput extends Input {
|
|
1489
1554
|
return;
|
1490
1555
|
}
|
1491
1556
|
const startSlot = this.selection.startSlot;
|
1492
|
-
this.
|
1557
|
+
this.adapter.composition = {
|
1493
1558
|
slot: startSlot,
|
1494
|
-
|
1495
|
-
|
1559
|
+
text: ev.data,
|
1560
|
+
offset: ev.data.length,
|
1561
|
+
index: startIndex
|
1496
1562
|
};
|
1497
1563
|
this.caret.refresh(true);
|
1498
1564
|
const event = new core$1.Event(startSlot, {
|
@@ -1500,6 +1566,7 @@ exports.MagicInput = class MagicInput extends Input {
|
|
1500
1566
|
data: ev.data
|
1501
1567
|
});
|
1502
1568
|
core$1.invokeListener(startSlot.parent, 'onCompositionUpdate', event);
|
1569
|
+
startSlot.changeMarker.forceMarkDirtied();
|
1503
1570
|
}));
|
1504
1571
|
let isCompositionEnd = false;
|
1505
1572
|
this.subscription.add(stream.merge(stream.fromEvent(textarea, 'beforeinput').pipe(stream.filter(ev => {
|
@@ -1523,24 +1590,15 @@ exports.MagicInput = class MagicInput extends Input {
|
|
1523
1590
|
textarea.value = '';
|
1524
1591
|
return ev.data;
|
1525
1592
|
}))).subscribe(text => {
|
1593
|
+
var _a;
|
1526
1594
|
this.composition = false;
|
1527
|
-
this.
|
1528
|
-
const compositionElement = this.caret.compositionElement;
|
1529
|
-
let nextSibling = compositionElement.nextSibling;
|
1530
|
-
while (nextSibling) {
|
1531
|
-
if (!nextSibling.textContent) {
|
1532
|
-
const next = nextSibling.nextSibling;
|
1533
|
-
nextSibling.remove();
|
1534
|
-
nextSibling = next;
|
1535
|
-
continue;
|
1536
|
-
}
|
1537
|
-
nextSibling.remove();
|
1538
|
-
break;
|
1539
|
-
}
|
1540
|
-
compositionElement.remove();
|
1595
|
+
this.adapter.composition = null;
|
1541
1596
|
if (text) {
|
1542
1597
|
this.commander.write(text);
|
1543
1598
|
}
|
1599
|
+
else {
|
1600
|
+
(_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.changeMarker.forceMarkDirtied();
|
1601
|
+
}
|
1544
1602
|
if (isCompositionEnd) {
|
1545
1603
|
const startSlot = this.selection.startSlot;
|
1546
1604
|
if (startSlot) {
|
@@ -1569,7 +1627,8 @@ exports.MagicInput = class MagicInput extends Input {
|
|
1569
1627
|
};
|
1570
1628
|
exports.MagicInput = __decorate([
|
1571
1629
|
core.Injectable(),
|
1572
|
-
__metadata("design:paramtypes", [
|
1630
|
+
__metadata("design:paramtypes", [DomAdapter,
|
1631
|
+
exports.Parser,
|
1573
1632
|
core$1.Keyboard,
|
1574
1633
|
core$1.Commander,
|
1575
1634
|
core$1.Selection,
|
@@ -1641,6 +1700,7 @@ exports.CollaborateCursor = class CollaborateCursor {
|
|
1641
1700
|
this.onRectsChange = new stream.Subject();
|
1642
1701
|
this.subscription = new stream.Subscription();
|
1643
1702
|
this.currentSelection = [];
|
1703
|
+
this.ratio = window.devicePixelRatio || 1;
|
1644
1704
|
this.container = textbus.get(VIEW_CONTAINER);
|
1645
1705
|
this.canvasContainer.append(this.canvas);
|
1646
1706
|
this.host.append(this.canvasContainer, this.tooltips);
|
@@ -1684,8 +1744,9 @@ exports.CollaborateCursor = class CollaborateCursor {
|
|
1684
1744
|
this.currentSelection = paths;
|
1685
1745
|
const containerRect = this.container.getBoundingClientRect();
|
1686
1746
|
this.canvas.style.top = containerRect.top * -1 + 'px';
|
1687
|
-
this.canvas.width = this.canvas.offsetWidth;
|
1688
|
-
this.canvas.height = this.canvas.offsetHeight;
|
1747
|
+
this.canvas.width = this.canvas.offsetWidth * this.ratio;
|
1748
|
+
this.canvas.height = this.canvas.offsetHeight * this.ratio;
|
1749
|
+
this.context.scale(this.ratio, this.ratio);
|
1689
1750
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
1690
1751
|
const users = [];
|
1691
1752
|
paths.filter(i => {
|
@@ -1710,8 +1771,13 @@ exports.CollaborateCursor = class CollaborateCursor {
|
|
1710
1771
|
return;
|
1711
1772
|
}
|
1712
1773
|
const nativeRange = document.createRange();
|
1713
|
-
|
1714
|
-
|
1774
|
+
try {
|
1775
|
+
nativeRange.setStart(anchor.node, anchor.offset);
|
1776
|
+
nativeRange.setEnd(focus.node, focus.offset);
|
1777
|
+
}
|
1778
|
+
catch (e) {
|
1779
|
+
return;
|
1780
|
+
}
|
1715
1781
|
if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
|
1716
1782
|
nativeRange.setStart(focus.node, focus.offset);
|
1717
1783
|
nativeRange.setEnd(anchor.node, anchor.offset);
|
@@ -1974,7 +2040,7 @@ let NativeInput = class NativeInput extends Input {
|
|
1974
2040
|
this.controller = controller;
|
1975
2041
|
this.caret = new NativeCaret(this.scheduler);
|
1976
2042
|
this.composition = false;
|
1977
|
-
|
2043
|
+
// compositionState: CompositionState | null = null
|
1978
2044
|
this.onReady = Promise.resolve();
|
1979
2045
|
this._disabled = false;
|
1980
2046
|
this.nativeSelection = document.getSelection();
|
@@ -2132,7 +2198,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2132
2198
|
let startIndex;
|
2133
2199
|
const compositionStart = () => {
|
2134
2200
|
this.composition = true;
|
2135
|
-
this.compositionState = null;
|
2136
2201
|
startIndex = this.selection.startOffset;
|
2137
2202
|
const startSlot = this.selection.startSlot;
|
2138
2203
|
const event = new core$1.Event(startSlot, {
|
@@ -2142,11 +2207,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2142
2207
|
};
|
2143
2208
|
const compositionUpdate = (data) => {
|
2144
2209
|
const startSlot = this.selection.startSlot;
|
2145
|
-
this.compositionState = {
|
2146
|
-
slot: startSlot,
|
2147
|
-
index: startIndex,
|
2148
|
-
data
|
2149
|
-
};
|
2150
2210
|
const event = new core$1.Event(startSlot, {
|
2151
2211
|
index: startIndex,
|
2152
2212
|
data
|
@@ -2233,7 +2293,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2233
2293
|
return !this.ignoreComposition;
|
2234
2294
|
})).subscribe(() => {
|
2235
2295
|
this.composition = true;
|
2236
|
-
this.compositionState = null;
|
2237
2296
|
startIndex = this.selection.startOffset;
|
2238
2297
|
const startSlot = this.selection.startSlot;
|
2239
2298
|
const event = new core$1.Event(startSlot, {
|
@@ -2244,11 +2303,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2244
2303
|
return !this.ignoreComposition;
|
2245
2304
|
})).subscribe(ev => {
|
2246
2305
|
const startSlot = this.selection.startSlot;
|
2247
|
-
this.compositionState = {
|
2248
|
-
slot: startSlot,
|
2249
|
-
index: startIndex,
|
2250
|
-
data: ev.data
|
2251
|
-
};
|
2252
2306
|
const event = new core$1.Event(startSlot, {
|
2253
2307
|
index: startIndex,
|
2254
2308
|
data: ev.data
|
@@ -2298,7 +2352,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2298
2352
|
return !b;
|
2299
2353
|
}))).subscribe(text => {
|
2300
2354
|
this.composition = false;
|
2301
|
-
this.compositionState = null;
|
2302
2355
|
if (text) {
|
2303
2356
|
this.commander.write(text);
|
2304
2357
|
}
|
package/bundles/magic-input.d.ts
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
import { Observable } from '@tanbo/stream';
|
2
2
|
import { Commander, Controller, Keyboard, Scheduler, Selection, Textbus } from '@textbus/core';
|
3
3
|
import { Parser } from './parser';
|
4
|
-
import { Caret, CaretPosition,
|
4
|
+
import { Caret, CaretPosition, Input, Scroller } from './types';
|
5
|
+
import { DomAdapter } from './dom-adapter';
|
5
6
|
interface CaretStyle {
|
6
7
|
height: string;
|
7
8
|
lineHeight: string;
|
8
9
|
fontSize: string;
|
9
10
|
}
|
10
11
|
declare class ExperimentalCaret implements Caret {
|
12
|
+
private adapter;
|
11
13
|
private scheduler;
|
12
14
|
private editorMask;
|
13
15
|
onPositionChange: Observable<CaretPosition | null>;
|
14
16
|
onStyleChange: Observable<CaretStyle>;
|
15
17
|
elementRef: HTMLElement;
|
16
|
-
compositionState: CompositionState | null;
|
17
18
|
get rect(): DOMRect;
|
18
|
-
compositionElement: HTMLElement;
|
19
19
|
private timer;
|
20
20
|
private caret;
|
21
21
|
private oldPosition;
|
@@ -29,7 +29,7 @@ declare class ExperimentalCaret implements Caret {
|
|
29
29
|
private styleChangeEvent;
|
30
30
|
private oldRange;
|
31
31
|
private isFixed;
|
32
|
-
constructor(scheduler: Scheduler, editorMask: HTMLElement);
|
32
|
+
constructor(adapter: DomAdapter<any, any>, scheduler: Scheduler, editorMask: HTMLElement);
|
33
33
|
refresh(isFixedCaret?: boolean): void;
|
34
34
|
show(range: Range, restart: boolean): void;
|
35
35
|
hide(): void;
|
@@ -41,6 +41,7 @@ declare class ExperimentalCaret implements Caret {
|
|
41
41
|
* Textbus PC 端输入实现
|
42
42
|
*/
|
43
43
|
export declare class MagicInput extends Input {
|
44
|
+
private adapter;
|
44
45
|
private parser;
|
45
46
|
private keyboard;
|
46
47
|
private commander;
|
@@ -49,7 +50,6 @@ export declare class MagicInput extends Input {
|
|
49
50
|
private scheduler;
|
50
51
|
private textbus;
|
51
52
|
composition: boolean;
|
52
|
-
compositionState: CompositionState | null;
|
53
53
|
onReady: Promise<void>;
|
54
54
|
caret: ExperimentalCaret;
|
55
55
|
set disabled(b: boolean);
|
@@ -66,7 +66,7 @@ export declare class MagicInput extends Input {
|
|
66
66
|
private isFocus;
|
67
67
|
private nativeFocus;
|
68
68
|
private ignoreComposition;
|
69
|
-
constructor(parser: Parser, keyboard: Keyboard, commander: Commander, selection: Selection, controller: Controller, scheduler: Scheduler, textbus: Textbus);
|
69
|
+
constructor(adapter: DomAdapter<any, any>, parser: Parser, keyboard: Keyboard, commander: Commander, selection: Selection, controller: Controller, scheduler: Scheduler, textbus: Textbus);
|
70
70
|
focus(range: Range, restart: boolean): void;
|
71
71
|
blur(): void;
|
72
72
|
destroy(): void;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { Observable } from '@tanbo/stream';
|
2
2
|
import { Commander, Controller, Keyboard, Scheduler, Selection, Textbus } from '@textbus/core';
|
3
|
-
import { Caret, CaretPosition,
|
3
|
+
import { Caret, CaretPosition, Input, Scroller } from './types';
|
4
4
|
import { Parser } from './parser';
|
5
5
|
import { DomAdapter } from './dom-adapter';
|
6
6
|
declare class NativeCaret implements Caret {
|
@@ -28,7 +28,6 @@ export declare class NativeInput extends Input {
|
|
28
28
|
private controller;
|
29
29
|
caret: NativeCaret;
|
30
30
|
composition: boolean;
|
31
|
-
compositionState: CompositionState | null;
|
32
31
|
onReady: Promise<void>;
|
33
32
|
set disabled(b: boolean);
|
34
33
|
get disabled(): boolean;
|
package/bundles/types.d.ts
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import { Slot } from '@textbus/core';
|
2
1
|
import { Observable } from '@tanbo/stream';
|
3
2
|
import { Rect } from './_utils/uikit';
|
4
3
|
export interface CaretLimit {
|
@@ -21,11 +20,6 @@ export interface Caret {
|
|
21
20
|
refresh(isFixedCaret: boolean): void;
|
22
21
|
correctScrollTop(scroller: Scroller): void;
|
23
22
|
}
|
24
|
-
export interface CompositionState {
|
25
|
-
slot: Slot;
|
26
|
-
index: number;
|
27
|
-
data: string;
|
28
|
-
}
|
29
23
|
export declare abstract class Input {
|
30
24
|
/**
|
31
25
|
* @experimental
|
@@ -34,7 +28,6 @@ export declare abstract class Input {
|
|
34
28
|
/**
|
35
29
|
* @experimental
|
36
30
|
*/
|
37
|
-
abstract compositionState: CompositionState | null;
|
38
31
|
abstract onReady: Promise<void>;
|
39
32
|
abstract caret: Caret;
|
40
33
|
abstract disabled: boolean;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@textbus/platform-browser",
|
3
|
-
"version": "4.0.0-alpha.
|
3
|
+
"version": "4.0.0-alpha.34",
|
4
4
|
"description": "Textbus is a rich text editor and framework that is highly customizable and extensible to achieve rich wysiwyg effects.",
|
5
5
|
"main": "./bundles/index.js",
|
6
6
|
"module": "./bundles/index.esm.js",
|
@@ -26,9 +26,9 @@
|
|
26
26
|
],
|
27
27
|
"dependencies": {
|
28
28
|
"@tanbo/stream": "^1.2.3",
|
29
|
-
"@textbus/collaborate": "^4.0.0-alpha.
|
30
|
-
"@textbus/core": "^4.0.0-alpha.
|
31
|
-
"@viewfly/core": "^0.6.
|
29
|
+
"@textbus/collaborate": "^4.0.0-alpha.34",
|
30
|
+
"@textbus/core": "^4.0.0-alpha.34",
|
31
|
+
"@viewfly/core": "^0.6.3",
|
32
32
|
"reflect-metadata": "^0.1.13"
|
33
33
|
},
|
34
34
|
"devDependencies": {
|
@@ -49,5 +49,5 @@
|
|
49
49
|
"bugs": {
|
50
50
|
"url": "https://github.com/textbus/textbus.git/issues"
|
51
51
|
},
|
52
|
-
"gitHead": "
|
52
|
+
"gitHead": "b6f9bfbce3135865fc0c8a3e6b622a7040019634"
|
53
53
|
}
|