@textbus/platform-browser 4.0.0-alpha.5 → 4.0.0-alpha.51
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/README.md +0 -114
- package/bundles/browser-module.d.ts +22 -7
- package/bundles/collaborate-cursor.d.ts +7 -13
- package/bundles/dom-adapter.d.ts +4 -64
- package/bundles/index.esm.js +170 -227
- package/bundles/index.js +172 -229
- package/bundles/magic-input.d.ts +9 -9
- package/bundles/native-input.d.ts +3 -5
- package/bundles/parser.d.ts +10 -11
- package/bundles/public-api.d.ts +1 -0
- package/bundles/selection-bridge.d.ts +3 -4
- package/bundles/types.d.ts +0 -7
- package/package.json +6 -5
package/bundles/index.esm.js
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import 'reflect-metadata';
|
2
|
-
import { Slot,
|
3
|
-
import { InjectionToken, Injectable, Inject, Injector, Optional } from '@viewfly/core';
|
2
|
+
import { Slot, Textbus, Adapter, Controller, Selection, RootComponentRef, ContentType, Event, invokeListener, Keyboard, Commander, Scheduler, makeError, NativeSelectionBridge, FocusManager, Component, Registry } from '@textbus/core';
|
4
3
|
import { Subject, filter, fromEvent, Subscription, distinctUntilChanged, merge, map, Observable } from '@tanbo/stream';
|
4
|
+
import { InjectionToken, Injectable, Inject, Optional } from '@viewfly/core';
|
5
|
+
import { UserActivity } from '@textbus/collaborate';
|
5
6
|
|
6
7
|
function createElement(tagName, options = {}) {
|
7
8
|
const el = document.createElement(tagName);
|
@@ -166,9 +167,9 @@ let Parser = Parser_1 = class Parser {
|
|
166
167
|
static parseHTML(html) {
|
167
168
|
return new DOMParser().parseFromString(html, 'text/html').body;
|
168
169
|
}
|
169
|
-
constructor(options,
|
170
|
+
constructor(options, textbus) {
|
170
171
|
this.options = options;
|
171
|
-
this.
|
172
|
+
this.textbus = textbus;
|
172
173
|
const componentLoaders = [
|
173
174
|
...(options.componentLoaders || [])
|
174
175
|
];
|
@@ -193,7 +194,7 @@ let Parser = Parser_1 = class Parser {
|
|
193
194
|
*/
|
194
195
|
parseDoc(html, rootComponentLoader) {
|
195
196
|
const element = typeof html === 'string' ? Parser_1.parseHTML(html) : html;
|
196
|
-
return rootComponentLoader.read(element, this.
|
197
|
+
return rootComponentLoader.read(element, this.textbus, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
|
197
198
|
return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
|
198
199
|
});
|
199
200
|
}
|
@@ -214,7 +215,7 @@ let Parser = Parser_1 = class Parser {
|
|
214
215
|
}
|
215
216
|
for (const t of this.componentLoaders) {
|
216
217
|
if (t.match(el)) {
|
217
|
-
const result = t.read(el, this.
|
218
|
+
const result = t.read(el, this.textbus, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
|
218
219
|
return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
|
219
220
|
});
|
220
221
|
if (!result) {
|
@@ -294,19 +295,16 @@ let Parser = Parser_1 = class Parser {
|
|
294
295
|
Parser = Parser_1 = __decorate([
|
295
296
|
Injectable(),
|
296
297
|
__param(0, Inject(EDITOR_OPTIONS)),
|
297
|
-
__metadata("design:paramtypes", [Object,
|
298
|
+
__metadata("design:paramtypes", [Object, Textbus])
|
298
299
|
], Parser);
|
299
300
|
|
300
301
|
class Input {
|
301
302
|
}
|
302
303
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
constructor(mount) {
|
308
|
-
super();
|
309
|
-
this.mount = mount;
|
304
|
+
class DomAdapter extends Adapter {
|
305
|
+
constructor() {
|
306
|
+
super(...arguments);
|
307
|
+
this.onViewUpdated = new Subject();
|
310
308
|
this.host = createElement('div', {
|
311
309
|
styles: {
|
312
310
|
cursor: 'text',
|
@@ -322,126 +320,6 @@ class DomAdapter extends ViewAdapter {
|
|
322
320
|
id: 'textbus-' + Number((Math.random() + '').substring(2)).toString(16)
|
323
321
|
}
|
324
322
|
});
|
325
|
-
this.componentRootElementCaches = createBidirectionalMapping(a => {
|
326
|
-
return a instanceof ComponentInstance;
|
327
|
-
});
|
328
|
-
this.slotRootNativeElementCaches = createBidirectionalMapping(a => {
|
329
|
-
return a instanceof Slot;
|
330
|
-
});
|
331
|
-
this.slotRootVElementCaches = new WeakMap();
|
332
|
-
}
|
333
|
-
render(rootComponent) {
|
334
|
-
const view = this.componentRender(rootComponent);
|
335
|
-
return this.mount(this.host, view);
|
336
|
-
}
|
337
|
-
copy() {
|
338
|
-
document.execCommand('copy');
|
339
|
-
}
|
340
|
-
/**
|
341
|
-
* 根据组件获取组件的根 DOM 节点
|
342
|
-
* @param component
|
343
|
-
*/
|
344
|
-
getNativeNodeByComponent(component) {
|
345
|
-
return this.componentRootElementCaches.get(component) || null;
|
346
|
-
}
|
347
|
-
/**
|
348
|
-
* 根据 DOM 节点,获对对应的组件根节点,如传入的 DOM 节点不为组件的根节点,则返回 null
|
349
|
-
* @param node
|
350
|
-
*/
|
351
|
-
getComponentByNativeNode(node) {
|
352
|
-
return this.componentRootElementCaches.get(node) || null;
|
353
|
-
}
|
354
|
-
/**
|
355
|
-
* 根据插槽获取插槽的根 DOM 节点
|
356
|
-
* @param slot
|
357
|
-
*/
|
358
|
-
getNativeNodeBySlot(slot) {
|
359
|
-
return this.slotRootNativeElementCaches.get(slot) || null;
|
360
|
-
}
|
361
|
-
/**
|
362
|
-
* 根据 DOM 节点,获对对应的插槽根节点,如传入的 DOM 节点不为插槽的根节点,则返回 null
|
363
|
-
* @param node
|
364
|
-
*/
|
365
|
-
getSlotByNativeNode(node) {
|
366
|
-
return this.slotRootNativeElementCaches.get(node) || null;
|
367
|
-
}
|
368
|
-
/**
|
369
|
-
* 获取插槽内容节点集合
|
370
|
-
* @param slot
|
371
|
-
*/
|
372
|
-
getNodesBySlot(slot) {
|
373
|
-
const rootNativeNode = this.getNativeNodeBySlot(slot);
|
374
|
-
if (!rootNativeNode) {
|
375
|
-
return [];
|
376
|
-
}
|
377
|
-
const rootVNode = this.slotRootVElementCaches.get(slot);
|
378
|
-
const getNodes = (vElement, nativeNode, result) => {
|
379
|
-
if (vElement.location) {
|
380
|
-
result.push(nativeNode);
|
381
|
-
}
|
382
|
-
for (let i = 0; i < vElement.children.length; i++) {
|
383
|
-
const vChild = vElement.children[i];
|
384
|
-
const nativeChild = nativeNode.childNodes[i];
|
385
|
-
if (vChild instanceof VElement) {
|
386
|
-
getNodes(vChild, nativeChild, result);
|
387
|
-
}
|
388
|
-
else if (vChild instanceof VTextNode) {
|
389
|
-
result.push(nativeChild);
|
390
|
-
}
|
391
|
-
else {
|
392
|
-
result.push(this.getNativeNodeByComponent(vChild));
|
393
|
-
}
|
394
|
-
}
|
395
|
-
return result;
|
396
|
-
};
|
397
|
-
return getNodes(rootVNode, rootNativeNode, []);
|
398
|
-
}
|
399
|
-
/**
|
400
|
-
* 获取原生节点的原始数据在文档中的位置
|
401
|
-
* @param node
|
402
|
-
*/
|
403
|
-
getLocationByNativeNode(node) {
|
404
|
-
let slotRootNode = node;
|
405
|
-
while (!this.slotRootNativeElementCaches.get(slotRootNode)) {
|
406
|
-
slotRootNode = slotRootNode.parentNode;
|
407
|
-
if (!slotRootNode) {
|
408
|
-
return null;
|
409
|
-
}
|
410
|
-
}
|
411
|
-
const slot = this.slotRootNativeElementCaches.get(slotRootNode);
|
412
|
-
const rootVNode = this.slotRootVElementCaches.get(slot);
|
413
|
-
const getLocation = (target, tree, vNodeTree) => {
|
414
|
-
if (target === tree) {
|
415
|
-
return Object.assign({}, vNodeTree.location);
|
416
|
-
}
|
417
|
-
const childNodes = tree.childNodes;
|
418
|
-
for (let i = 0; i < childNodes.length; i++) {
|
419
|
-
const child = vNodeTree.children[i];
|
420
|
-
const nativeChild = tree.childNodes[i];
|
421
|
-
if (nativeChild === target) {
|
422
|
-
if (child instanceof ComponentInstance) {
|
423
|
-
const index = child.parent.indexOf(child);
|
424
|
-
return {
|
425
|
-
slot: child.parent,
|
426
|
-
startIndex: index,
|
427
|
-
endIndex: index + 1
|
428
|
-
};
|
429
|
-
}
|
430
|
-
return child.location;
|
431
|
-
}
|
432
|
-
else if (child instanceof VElement) {
|
433
|
-
let r = null;
|
434
|
-
if (nativeChild.nodeType === Node.ELEMENT_NODE) {
|
435
|
-
r = getLocation(target, nativeChild, child);
|
436
|
-
}
|
437
|
-
if (r) {
|
438
|
-
return r;
|
439
|
-
}
|
440
|
-
}
|
441
|
-
}
|
442
|
-
return null;
|
443
|
-
};
|
444
|
-
return getLocation(node, slotRootNode, rootVNode);
|
445
323
|
}
|
446
324
|
}
|
447
325
|
|
@@ -449,7 +327,7 @@ class DomAdapter extends ViewAdapter {
|
|
449
327
|
* Textbus PC 端选区桥接实现
|
450
328
|
*/
|
451
329
|
let SelectionBridge = class SelectionBridge {
|
452
|
-
constructor(config,
|
330
|
+
constructor(config, textbus, controller, selection, rootComponentRef, input, domAdapter) {
|
453
331
|
this.config = config;
|
454
332
|
this.selection = selection;
|
455
333
|
this.rootComponentRef = rootComponentRef;
|
@@ -461,7 +339,7 @@ let SelectionBridge = class SelectionBridge {
|
|
461
339
|
this.connector = null;
|
462
340
|
this.ignoreSelectionChange = false;
|
463
341
|
this.changeFromUser = false;
|
464
|
-
this.docContainer =
|
342
|
+
this.docContainer = textbus.get(VIEW_DOCUMENT);
|
465
343
|
this.onSelectionChange = this.selectionChangeEvent.asObservable().pipe(filter(() => {
|
466
344
|
return !controller.readonly;
|
467
345
|
}));
|
@@ -645,6 +523,7 @@ let SelectionBridge = class SelectionBridge {
|
|
645
523
|
}
|
646
524
|
minLeft = rect2.left;
|
647
525
|
minTop = rect2.top;
|
526
|
+
oldPosition = position;
|
648
527
|
}
|
649
528
|
if (isToPrevLine) {
|
650
529
|
if (rect2.left < startLeft) {
|
@@ -751,7 +630,7 @@ let SelectionBridge = class SelectionBridge {
|
|
751
630
|
this.input.composition ||
|
752
631
|
selection.rangeCount === 0 ||
|
753
632
|
!this.docContainer.contains(selection.anchorNode) ||
|
754
|
-
this.rootComponentRef.component.
|
633
|
+
this.rootComponentRef.component.__slots__.length === 0) {
|
755
634
|
return;
|
756
635
|
}
|
757
636
|
const rawRange = selection.getRangeAt(0);
|
@@ -760,14 +639,14 @@ let SelectionBridge = class SelectionBridge {
|
|
760
639
|
const isFocusStart = selection.focusNode === nativeRange.startContainer && selection.focusOffset === nativeRange.startOffset;
|
761
640
|
if (!this.docContainer.contains(selection.focusNode)) {
|
762
641
|
if (isFocusEnd) {
|
763
|
-
const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.
|
642
|
+
const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.__slots__.first);
|
764
643
|
if (!nativeNode) {
|
765
644
|
return;
|
766
645
|
}
|
767
646
|
nativeRange.setEndAfter(nativeNode.lastChild);
|
768
647
|
}
|
769
648
|
else {
|
770
|
-
const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.
|
649
|
+
const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.__slots__.last);
|
771
650
|
if (!nativeNode) {
|
772
651
|
return;
|
773
652
|
}
|
@@ -990,7 +869,7 @@ let SelectionBridge = class SelectionBridge {
|
|
990
869
|
SelectionBridge = __decorate([
|
991
870
|
Injectable(),
|
992
871
|
__param(0, Inject(EDITOR_OPTIONS)),
|
993
|
-
__metadata("design:paramtypes", [Object,
|
872
|
+
__metadata("design:paramtypes", [Object, Textbus,
|
994
873
|
Controller,
|
995
874
|
Selection,
|
996
875
|
RootComponentRef,
|
@@ -1028,15 +907,10 @@ class ExperimentalCaret {
|
|
1028
907
|
get display() {
|
1029
908
|
return this._display;
|
1030
909
|
}
|
1031
|
-
constructor(scheduler, editorMask) {
|
910
|
+
constructor(domRenderer, scheduler, editorMask) {
|
911
|
+
this.domRenderer = domRenderer;
|
1032
912
|
this.scheduler = scheduler;
|
1033
913
|
this.editorMask = editorMask;
|
1034
|
-
this.compositionState = null;
|
1035
|
-
this.compositionElement = createElement('span', {
|
1036
|
-
styles: {
|
1037
|
-
textDecoration: 'underline'
|
1038
|
-
}
|
1039
|
-
});
|
1040
914
|
this.timer = null;
|
1041
915
|
this.oldPosition = null;
|
1042
916
|
this._display = true;
|
@@ -1180,12 +1054,10 @@ class ExperimentalCaret {
|
|
1180
1054
|
this.positionChangeEvent.next(null);
|
1181
1055
|
return;
|
1182
1056
|
}
|
1183
|
-
|
1184
|
-
|
1185
|
-
compositionElement.innerText = this.compositionState.data;
|
1057
|
+
const compositionNode = this.domRenderer.compositionNode;
|
1058
|
+
if (compositionNode) {
|
1186
1059
|
nativeRange = nativeRange.cloneRange();
|
1187
|
-
nativeRange.
|
1188
|
-
nativeRange.selectNodeContents(compositionElement);
|
1060
|
+
nativeRange.selectNodeContents(compositionNode);
|
1189
1061
|
nativeRange.collapse();
|
1190
1062
|
}
|
1191
1063
|
const rect = getLayoutRectByRange(nativeRange);
|
@@ -1246,18 +1118,18 @@ let MagicInput = class MagicInput extends Input {
|
|
1246
1118
|
get disabled() {
|
1247
1119
|
return this._disabled;
|
1248
1120
|
}
|
1249
|
-
constructor(parser, keyboard, commander, selection, controller, scheduler,
|
1121
|
+
constructor(domAdapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
|
1250
1122
|
super();
|
1123
|
+
this.domAdapter = domAdapter;
|
1251
1124
|
this.parser = parser;
|
1252
1125
|
this.keyboard = keyboard;
|
1253
1126
|
this.commander = commander;
|
1254
1127
|
this.selection = selection;
|
1255
1128
|
this.controller = controller;
|
1256
1129
|
this.scheduler = scheduler;
|
1257
|
-
this.
|
1130
|
+
this.textbus = textbus;
|
1258
1131
|
this.composition = false;
|
1259
|
-
this.
|
1260
|
-
this.caret = new ExperimentalCaret(this.scheduler, this.injector.get(VIEW_MASK));
|
1132
|
+
this.caret = new ExperimentalCaret(this.domAdapter, this.scheduler, this.textbus.get(VIEW_MASK));
|
1261
1133
|
this.isSafari = isSafari();
|
1262
1134
|
this.isFirefox = isFirefox();
|
1263
1135
|
this.isMac = isMac();
|
@@ -1297,13 +1169,8 @@ let MagicInput = class MagicInput extends Input {
|
|
1297
1169
|
if (!this.isFocus) {
|
1298
1170
|
(_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
|
1299
1171
|
setTimeout(() => {
|
1300
|
-
var _a, _b, _c;
|
1301
1172
|
if (!this.nativeFocus && this.isFocus) {
|
1302
|
-
this.
|
1303
|
-
(_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
|
1304
|
-
this.subscription = new Subscription();
|
1305
|
-
this.init();
|
1306
|
-
(_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
|
1173
|
+
this.reInit();
|
1307
1174
|
}
|
1308
1175
|
});
|
1309
1176
|
}
|
@@ -1319,6 +1186,22 @@ let MagicInput = class MagicInput extends Input {
|
|
1319
1186
|
this.caret.destroy();
|
1320
1187
|
this.subscription.unsubscribe();
|
1321
1188
|
}
|
1189
|
+
reInit(delay = false) {
|
1190
|
+
var _a, _b, _c;
|
1191
|
+
this.subscription.unsubscribe();
|
1192
|
+
(_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
|
1193
|
+
this.subscription = new Subscription();
|
1194
|
+
this.init();
|
1195
|
+
if (delay) {
|
1196
|
+
setTimeout(() => {
|
1197
|
+
var _a;
|
1198
|
+
(_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
|
1199
|
+
});
|
1200
|
+
}
|
1201
|
+
else {
|
1202
|
+
(_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
|
1203
|
+
}
|
1204
|
+
}
|
1322
1205
|
init() {
|
1323
1206
|
const doc = this.doc;
|
1324
1207
|
const contentBody = doc.body;
|
@@ -1327,9 +1210,19 @@ let MagicInput = class MagicInput extends Input {
|
|
1327
1210
|
contentBody.appendChild(textarea);
|
1328
1211
|
this.textarea = textarea;
|
1329
1212
|
this.subscription.add(fromEvent(textarea, 'blur').subscribe(() => {
|
1213
|
+
// if (this.isFocus) {
|
1214
|
+
// this.isFocus = false
|
1215
|
+
// this.reInit(true)
|
1216
|
+
// }
|
1330
1217
|
this.isFocus = false;
|
1331
1218
|
this.nativeFocus = false;
|
1332
1219
|
this.caret.hide();
|
1220
|
+
if (this.domAdapter.composition) {
|
1221
|
+
const slot = this.domAdapter.composition.slot;
|
1222
|
+
this.domAdapter.composition = null;
|
1223
|
+
this.domAdapter.compositionNode = null;
|
1224
|
+
slot.__changeMarker__.forceMarkDirtied();
|
1225
|
+
}
|
1333
1226
|
}), fromEvent(textarea, 'focus').subscribe(() => {
|
1334
1227
|
this.nativeFocus = true;
|
1335
1228
|
}), this.caret.onStyleChange.subscribe(style => {
|
@@ -1340,7 +1233,7 @@ let MagicInput = class MagicInput extends Input {
|
|
1340
1233
|
this.handleDefaultActions(textarea);
|
1341
1234
|
}
|
1342
1235
|
handleDefaultActions(textarea) {
|
1343
|
-
this.subscription.add(fromEvent(document, 'copy').subscribe(ev => {
|
1236
|
+
this.subscription.add(fromEvent(isFirefox() ? textarea : document, 'copy').subscribe(ev => {
|
1344
1237
|
const selection = this.selection;
|
1345
1238
|
if (!selection.isSelected) {
|
1346
1239
|
return;
|
@@ -1452,7 +1345,6 @@ let MagicInput = class MagicInput extends Input {
|
|
1452
1345
|
this.commander.delete();
|
1453
1346
|
}
|
1454
1347
|
this.composition = true;
|
1455
|
-
this.caret.compositionState = this.compositionState = null;
|
1456
1348
|
startIndex = this.selection.startOffset;
|
1457
1349
|
const startSlot = this.selection.startSlot;
|
1458
1350
|
const event = new Event(startSlot, {
|
@@ -1469,10 +1361,11 @@ let MagicInput = class MagicInput extends Input {
|
|
1469
1361
|
return;
|
1470
1362
|
}
|
1471
1363
|
const startSlot = this.selection.startSlot;
|
1472
|
-
this.
|
1364
|
+
this.domAdapter.composition = {
|
1473
1365
|
slot: startSlot,
|
1474
|
-
|
1475
|
-
|
1366
|
+
text: ev.data,
|
1367
|
+
offset: ev.data.length,
|
1368
|
+
index: startIndex
|
1476
1369
|
};
|
1477
1370
|
this.caret.refresh(true);
|
1478
1371
|
const event = new Event(startSlot, {
|
@@ -1480,6 +1373,7 @@ let MagicInput = class MagicInput extends Input {
|
|
1480
1373
|
data: ev.data
|
1481
1374
|
});
|
1482
1375
|
invokeListener(startSlot.parent, 'onCompositionUpdate', event);
|
1376
|
+
startSlot.__changeMarker__.forceMarkDirtied();
|
1483
1377
|
}));
|
1484
1378
|
let isCompositionEnd = false;
|
1485
1379
|
this.subscription.add(merge(fromEvent(textarea, 'beforeinput').pipe(filter(ev => {
|
@@ -1503,24 +1397,15 @@ let MagicInput = class MagicInput extends Input {
|
|
1503
1397
|
textarea.value = '';
|
1504
1398
|
return ev.data;
|
1505
1399
|
}))).subscribe(text => {
|
1400
|
+
var _a;
|
1506
1401
|
this.composition = false;
|
1507
|
-
this.
|
1508
|
-
const compositionElement = this.caret.compositionElement;
|
1509
|
-
let nextSibling = compositionElement.nextSibling;
|
1510
|
-
while (nextSibling) {
|
1511
|
-
if (!nextSibling.textContent) {
|
1512
|
-
const next = nextSibling.nextSibling;
|
1513
|
-
nextSibling.remove();
|
1514
|
-
nextSibling = next;
|
1515
|
-
continue;
|
1516
|
-
}
|
1517
|
-
nextSibling.remove();
|
1518
|
-
break;
|
1519
|
-
}
|
1520
|
-
compositionElement.remove();
|
1402
|
+
this.domAdapter.composition = null;
|
1521
1403
|
if (text) {
|
1522
1404
|
this.commander.write(text);
|
1523
1405
|
}
|
1406
|
+
else {
|
1407
|
+
(_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.__changeMarker__.forceMarkDirtied();
|
1408
|
+
}
|
1524
1409
|
if (isCompositionEnd) {
|
1525
1410
|
const startSlot = this.selection.startSlot;
|
1526
1411
|
if (startSlot) {
|
@@ -1549,13 +1434,14 @@ let MagicInput = class MagicInput extends Input {
|
|
1549
1434
|
};
|
1550
1435
|
MagicInput = __decorate([
|
1551
1436
|
Injectable(),
|
1552
|
-
__metadata("design:paramtypes", [
|
1437
|
+
__metadata("design:paramtypes", [DomAdapter,
|
1438
|
+
Parser,
|
1553
1439
|
Keyboard,
|
1554
1440
|
Commander,
|
1555
1441
|
Selection,
|
1556
1442
|
Controller,
|
1557
1443
|
Scheduler,
|
1558
|
-
|
1444
|
+
Textbus])
|
1559
1445
|
], MagicInput);
|
1560
1446
|
|
1561
1447
|
/**
|
@@ -1567,10 +1453,11 @@ class CollaborateSelectionAwarenessDelegate {
|
|
1567
1453
|
* 协作光标绘制类
|
1568
1454
|
*/
|
1569
1455
|
let CollaborateCursor = class CollaborateCursor {
|
1570
|
-
constructor(
|
1456
|
+
constructor(textbus, nativeSelection, scheduler, selection, userActivity, awarenessDelegate) {
|
1571
1457
|
this.nativeSelection = nativeSelection;
|
1572
1458
|
this.scheduler = scheduler;
|
1573
1459
|
this.selection = selection;
|
1460
|
+
this.userActivity = userActivity;
|
1574
1461
|
this.awarenessDelegate = awarenessDelegate;
|
1575
1462
|
this.host = createElement('div', {
|
1576
1463
|
styles: {
|
@@ -1620,7 +1507,8 @@ let CollaborateCursor = class CollaborateCursor {
|
|
1620
1507
|
this.onRectsChange = new Subject();
|
1621
1508
|
this.subscription = new Subscription();
|
1622
1509
|
this.currentSelection = [];
|
1623
|
-
this.
|
1510
|
+
this.ratio = window.devicePixelRatio || 1;
|
1511
|
+
this.container = textbus.get(VIEW_CONTAINER);
|
1624
1512
|
this.canvasContainer.append(this.canvas);
|
1625
1513
|
this.host.append(this.canvasContainer, this.tooltips);
|
1626
1514
|
this.container.prepend(this.host);
|
@@ -1639,6 +1527,13 @@ let CollaborateCursor = class CollaborateCursor {
|
|
1639
1527
|
this.refresh();
|
1640
1528
|
}));
|
1641
1529
|
}
|
1530
|
+
init() {
|
1531
|
+
if (this.userActivity) {
|
1532
|
+
this.subscription.add(this.userActivity.onStateChange.subscribe(v => {
|
1533
|
+
this.draw(v);
|
1534
|
+
}));
|
1535
|
+
}
|
1536
|
+
}
|
1642
1537
|
/**
|
1643
1538
|
* 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
|
1644
1539
|
*/
|
@@ -1656,15 +1551,16 @@ let CollaborateCursor = class CollaborateCursor {
|
|
1656
1551
|
this.currentSelection = paths;
|
1657
1552
|
const containerRect = this.container.getBoundingClientRect();
|
1658
1553
|
this.canvas.style.top = containerRect.top * -1 + 'px';
|
1659
|
-
this.canvas.width = this.canvas.offsetWidth;
|
1660
|
-
this.canvas.height = this.canvas.offsetHeight;
|
1554
|
+
this.canvas.width = this.canvas.offsetWidth * this.ratio;
|
1555
|
+
this.canvas.height = this.canvas.offsetHeight * this.ratio;
|
1556
|
+
this.context.scale(this.ratio, this.ratio);
|
1661
1557
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
1662
1558
|
const users = [];
|
1663
1559
|
paths.filter(i => {
|
1664
|
-
return i.
|
1560
|
+
return i.selection.anchor.length && i.selection.focus.length;
|
1665
1561
|
}).forEach(item => {
|
1666
|
-
const anchorPaths = [...item.
|
1667
|
-
const focusPaths = [...item.
|
1562
|
+
const anchorPaths = [...item.selection.anchor];
|
1563
|
+
const focusPaths = [...item.selection.focus];
|
1668
1564
|
const anchorOffset = anchorPaths.pop();
|
1669
1565
|
const anchorSlot = this.selection.findSlotByPaths(anchorPaths);
|
1670
1566
|
const focusOffset = focusPaths.pop();
|
@@ -1682,8 +1578,13 @@ let CollaborateCursor = class CollaborateCursor {
|
|
1682
1578
|
return;
|
1683
1579
|
}
|
1684
1580
|
const nativeRange = document.createRange();
|
1685
|
-
|
1686
|
-
|
1581
|
+
try {
|
1582
|
+
nativeRange.setStart(anchor.node, anchor.offset);
|
1583
|
+
nativeRange.setEnd(focus.node, focus.offset);
|
1584
|
+
}
|
1585
|
+
catch (e) {
|
1586
|
+
return;
|
1587
|
+
}
|
1687
1588
|
if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
|
1688
1589
|
nativeRange.setStart(focus.node, focus.offset);
|
1689
1590
|
nativeRange.setEnd(anchor.node, anchor.offset);
|
@@ -1812,10 +1713,12 @@ let CollaborateCursor = class CollaborateCursor {
|
|
1812
1713
|
CollaborateCursor = __decorate([
|
1813
1714
|
Injectable(),
|
1814
1715
|
__param(4, Optional()),
|
1815
|
-
|
1716
|
+
__param(5, Optional()),
|
1717
|
+
__metadata("design:paramtypes", [Textbus,
|
1816
1718
|
SelectionBridge,
|
1817
1719
|
Scheduler,
|
1818
1720
|
Selection,
|
1721
|
+
UserActivity,
|
1819
1722
|
CollaborateSelectionAwarenessDelegate])
|
1820
1723
|
], CollaborateCursor);
|
1821
1724
|
|
@@ -1933,7 +1836,7 @@ let NativeInput = class NativeInput extends Input {
|
|
1933
1836
|
get disabled() {
|
1934
1837
|
return this._disabled;
|
1935
1838
|
}
|
1936
|
-
constructor(
|
1839
|
+
constructor(textbus, parser, scheduler, selection, keyboard, domAdapter, commander, controller) {
|
1937
1840
|
super();
|
1938
1841
|
this.parser = parser;
|
1939
1842
|
this.scheduler = scheduler;
|
@@ -1944,7 +1847,7 @@ let NativeInput = class NativeInput extends Input {
|
|
1944
1847
|
this.controller = controller;
|
1945
1848
|
this.caret = new NativeCaret(this.scheduler);
|
1946
1849
|
this.composition = false;
|
1947
|
-
|
1850
|
+
// compositionState: CompositionState | null = null
|
1948
1851
|
this.onReady = Promise.resolve();
|
1949
1852
|
this._disabled = false;
|
1950
1853
|
this.nativeSelection = document.getSelection();
|
@@ -1954,7 +1857,7 @@ let NativeInput = class NativeInput extends Input {
|
|
1954
1857
|
this.isMac = isMac();
|
1955
1858
|
this.isMobileBrowser = isMobileBrowser();
|
1956
1859
|
this.ignoreComposition = false; // 有 bug 版本搜狗拼音
|
1957
|
-
this.documentView =
|
1860
|
+
this.documentView = textbus.get(VIEW_DOCUMENT);
|
1958
1861
|
if (!controller.readonly) {
|
1959
1862
|
this.documentView.contentEditable = 'true';
|
1960
1863
|
}
|
@@ -1987,7 +1890,7 @@ let NativeInput = class NativeInput extends Input {
|
|
1987
1890
|
this.subscription.unsubscribe();
|
1988
1891
|
}
|
1989
1892
|
handleDefaultActions(textarea) {
|
1990
|
-
this.subscription.add(fromEvent(document, 'copy').subscribe(ev => {
|
1893
|
+
this.subscription.add(fromEvent(isFirefox() ? textarea : document, 'copy').subscribe(ev => {
|
1991
1894
|
const selection = this.selection;
|
1992
1895
|
if (!selection.isSelected) {
|
1993
1896
|
return;
|
@@ -2041,8 +1944,8 @@ let NativeInput = class NativeInput extends Input {
|
|
2041
1944
|
});
|
2042
1945
|
}));
|
2043
1946
|
}
|
2044
|
-
handlePaste(
|
2045
|
-
const slot = this.parser.parse(
|
1947
|
+
handlePaste(dom, text) {
|
1948
|
+
const slot = this.parser.parse(dom, new Slot([
|
2046
1949
|
ContentType.BlockComponent,
|
2047
1950
|
ContentType.InlineComponent,
|
2048
1951
|
ContentType.Text
|
@@ -2102,7 +2005,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2102
2005
|
let startIndex;
|
2103
2006
|
const compositionStart = () => {
|
2104
2007
|
this.composition = true;
|
2105
|
-
this.compositionState = null;
|
2106
2008
|
startIndex = this.selection.startOffset;
|
2107
2009
|
const startSlot = this.selection.startSlot;
|
2108
2010
|
const event = new Event(startSlot, {
|
@@ -2112,11 +2014,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2112
2014
|
};
|
2113
2015
|
const compositionUpdate = (data) => {
|
2114
2016
|
const startSlot = this.selection.startSlot;
|
2115
|
-
this.compositionState = {
|
2116
|
-
slot: startSlot,
|
2117
|
-
index: startIndex,
|
2118
|
-
data
|
2119
|
-
};
|
2120
2017
|
const event = new Event(startSlot, {
|
2121
2018
|
index: startIndex,
|
2122
2019
|
data
|
@@ -2203,7 +2100,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2203
2100
|
return !this.ignoreComposition;
|
2204
2101
|
})).subscribe(() => {
|
2205
2102
|
this.composition = true;
|
2206
|
-
this.compositionState = null;
|
2207
2103
|
startIndex = this.selection.startOffset;
|
2208
2104
|
const startSlot = this.selection.startSlot;
|
2209
2105
|
const event = new Event(startSlot, {
|
@@ -2214,11 +2110,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2214
2110
|
return !this.ignoreComposition;
|
2215
2111
|
})).subscribe(ev => {
|
2216
2112
|
const startSlot = this.selection.startSlot;
|
2217
|
-
this.compositionState = {
|
2218
|
-
slot: startSlot,
|
2219
|
-
index: startIndex,
|
2220
|
-
data: ev.data
|
2221
|
-
};
|
2222
2113
|
const event = new Event(startSlot, {
|
2223
2114
|
index: startIndex,
|
2224
2115
|
data: ev.data
|
@@ -2268,7 +2159,6 @@ let NativeInput = class NativeInput extends Input {
|
|
2268
2159
|
return !b;
|
2269
2160
|
}))).subscribe(text => {
|
2270
2161
|
this.composition = false;
|
2271
|
-
this.compositionState = null;
|
2272
2162
|
if (text) {
|
2273
2163
|
this.commander.write(text);
|
2274
2164
|
}
|
@@ -2285,7 +2175,7 @@ let NativeInput = class NativeInput extends Input {
|
|
2285
2175
|
};
|
2286
2176
|
NativeInput = __decorate([
|
2287
2177
|
Injectable(),
|
2288
|
-
__metadata("design:paramtypes", [
|
2178
|
+
__metadata("design:paramtypes", [Textbus,
|
2289
2179
|
Parser,
|
2290
2180
|
Scheduler,
|
2291
2181
|
Selection,
|
@@ -2295,9 +2185,9 @@ NativeInput = __decorate([
|
|
2295
2185
|
Controller])
|
2296
2186
|
], NativeInput);
|
2297
2187
|
|
2188
|
+
const browserErrorFn = makeError('BrowserModule');
|
2298
2189
|
class BrowserModule {
|
2299
|
-
constructor(
|
2300
|
-
this.host = host;
|
2190
|
+
constructor(config) {
|
2301
2191
|
this.config = config;
|
2302
2192
|
const { mask, wrapper } = BrowserModule.createLayout();
|
2303
2193
|
wrapper.prepend(config.adapter.host);
|
@@ -2323,24 +2213,77 @@ class BrowserModule {
|
|
2323
2213
|
provide: Input,
|
2324
2214
|
useClass: config.useContentEditable ? NativeInput : MagicInput
|
2325
2215
|
}, {
|
2326
|
-
provide:
|
2327
|
-
|
2328
|
-
return v;
|
2329
|
-
},
|
2330
|
-
deps: [DomAdapter]
|
2216
|
+
provide: Adapter,
|
2217
|
+
useValue: config.adapter
|
2331
2218
|
}, {
|
2332
2219
|
provide: DomAdapter,
|
2333
2220
|
useValue: config.adapter
|
2221
|
+
}, {
|
2222
|
+
provide: FocusManager,
|
2223
|
+
useFactory: (input) => {
|
2224
|
+
const focusEvent = new Subject();
|
2225
|
+
const blurEvent = new Subject();
|
2226
|
+
input.caret.onPositionChange.pipe(map(p => !!p), distinctUntilChanged()).subscribe(b => {
|
2227
|
+
if (b) {
|
2228
|
+
focusEvent.next();
|
2229
|
+
}
|
2230
|
+
else {
|
2231
|
+
blurEvent.next();
|
2232
|
+
}
|
2233
|
+
});
|
2234
|
+
return {
|
2235
|
+
onFocus: focusEvent,
|
2236
|
+
onBlur: blurEvent
|
2237
|
+
};
|
2238
|
+
},
|
2239
|
+
deps: [Input]
|
2334
2240
|
},
|
2335
2241
|
Parser,
|
2336
2242
|
SelectionBridge,
|
2337
|
-
CollaborateCursor
|
2338
|
-
];
|
2243
|
+
CollaborateCursor];
|
2339
2244
|
this.workbench = wrapper;
|
2340
|
-
this.host.append(wrapper);
|
2341
2245
|
}
|
2342
|
-
|
2343
|
-
|
2246
|
+
/**
|
2247
|
+
* 解析 HTML 并返回一个组件实例
|
2248
|
+
* @param html 要解析的 HTML
|
2249
|
+
* @param rootComponentLoader 文档根组件加载器
|
2250
|
+
* @param textbus
|
2251
|
+
*/
|
2252
|
+
readDocumentByHTML(html, rootComponentLoader, textbus) {
|
2253
|
+
const parser = textbus.get(Parser);
|
2254
|
+
const doc = parser.parseDoc(html, rootComponentLoader);
|
2255
|
+
if (doc instanceof Component) {
|
2256
|
+
return doc;
|
2257
|
+
}
|
2258
|
+
throw browserErrorFn('rootComponentLoader must return a component instance.');
|
2259
|
+
}
|
2260
|
+
/**
|
2261
|
+
* 将组件数据解析到组件实例中
|
2262
|
+
* @param data 要解析的 JSON 数据
|
2263
|
+
* @param rootComponent 根组件
|
2264
|
+
* @param textbus
|
2265
|
+
*/
|
2266
|
+
readDocumentByComponentLiteral(data, rootComponent, textbus) {
|
2267
|
+
const registry = textbus.get(Registry);
|
2268
|
+
return registry.createComponentByFactory(data, rootComponent);
|
2269
|
+
}
|
2270
|
+
setup(textbus) {
|
2271
|
+
const host = this.config.renderTo();
|
2272
|
+
if (!(host instanceof HTMLElement)) {
|
2273
|
+
throw browserErrorFn('view container is not a HTMLElement');
|
2274
|
+
}
|
2275
|
+
const cursor = textbus.get(CollaborateCursor);
|
2276
|
+
cursor.init();
|
2277
|
+
host.append(this.workbench);
|
2278
|
+
return () => {
|
2279
|
+
cursor.destroy();
|
2280
|
+
this.workbench.remove();
|
2281
|
+
};
|
2282
|
+
}
|
2283
|
+
onAfterStartup(textbus) {
|
2284
|
+
if (this.config.autoFocus) {
|
2285
|
+
textbus.focus();
|
2286
|
+
}
|
2344
2287
|
}
|
2345
2288
|
static createLayout() {
|
2346
2289
|
const mask = createElement('div', {
|
@@ -2355,7 +2298,7 @@ class BrowserModule {
|
|
2355
2298
|
bottom: 0,
|
2356
2299
|
zIndex: 1,
|
2357
2300
|
pointerEvents: 'none',
|
2358
|
-
overflow: 'hidden'
|
2301
|
+
// overflow: 'hidden'
|
2359
2302
|
}
|
2360
2303
|
});
|
2361
2304
|
const wrapper = createElement('div', {
|
@@ -2377,4 +2320,4 @@ class BrowserModule {
|
|
2377
2320
|
}
|
2378
2321
|
}
|
2379
2322
|
|
2380
|
-
export { BrowserModule, CollaborateCursor, CollaborateSelectionAwarenessDelegate, DomAdapter, EDITOR_OPTIONS, Input, MagicInput, Parser, SelectionBridge, VIEW_CONTAINER, VIEW_DOCUMENT, VIEW_MASK, createElement, createTextNode, getLayoutRectByRange, isFirefox, isMac, isMobileBrowser, isSafari, isWindows };
|
2323
|
+
export { BrowserModule, CollaborateCursor, CollaborateSelectionAwarenessDelegate, DomAdapter, EDITOR_OPTIONS, Input, MagicInput, NativeInput, Parser, SelectionBridge, VIEW_CONTAINER, VIEW_DOCUMENT, VIEW_MASK, createElement, createTextNode, getLayoutRectByRange, isFirefox, isMac, isMobileBrowser, isSafari, isWindows };
|