@textbus/platform-browser 4.0.0-alpha.5 → 4.0.0-alpha.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bundles/index.js CHANGED
@@ -2,8 +2,9 @@
2
2
 
3
3
  require('reflect-metadata');
4
4
  var core$1 = require('@textbus/core');
5
- var core = require('@viewfly/core');
6
5
  var stream = require('@tanbo/stream');
6
+ var core = require('@viewfly/core');
7
+ var collaborate = require('@textbus/collaborate');
7
8
 
8
9
  function createElement(tagName, options = {}) {
9
10
  const el = document.createElement(tagName);
@@ -168,9 +169,9 @@ exports.Parser = Parser_1 = class Parser {
168
169
  static parseHTML(html) {
169
170
  return new DOMParser().parseFromString(html, 'text/html').body;
170
171
  }
171
- constructor(options, injector) {
172
+ constructor(options, textbus) {
172
173
  this.options = options;
173
- this.injector = injector;
174
+ this.textbus = textbus;
174
175
  const componentLoaders = [
175
176
  ...(options.componentLoaders || [])
176
177
  ];
@@ -195,7 +196,7 @@ exports.Parser = Parser_1 = class Parser {
195
196
  */
196
197
  parseDoc(html, rootComponentLoader) {
197
198
  const element = typeof html === 'string' ? Parser_1.parseHTML(html) : html;
198
- return rootComponentLoader.read(element, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
199
+ return rootComponentLoader.read(element, this.textbus, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
199
200
  return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
200
201
  });
201
202
  }
@@ -216,7 +217,7 @@ exports.Parser = Parser_1 = class Parser {
216
217
  }
217
218
  for (const t of this.componentLoaders) {
218
219
  if (t.match(el)) {
219
- const result = t.read(el, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
220
+ const result = t.read(el, this.textbus, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
220
221
  return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
221
222
  });
222
223
  if (!result) {
@@ -296,19 +297,16 @@ exports.Parser = Parser_1 = class Parser {
296
297
  exports.Parser = Parser_1 = __decorate([
297
298
  core.Injectable(),
298
299
  __param(0, core.Inject(EDITOR_OPTIONS)),
299
- __metadata("design:paramtypes", [Object, core.Injector])
300
+ __metadata("design:paramtypes", [Object, core$1.Textbus])
300
301
  ], exports.Parser);
301
302
 
302
303
  class Input {
303
304
  }
304
305
 
305
- /**
306
- * Textbus PC 端浏览器渲染能力桥接器抽象类,提供了 DOM 元素查询能力,具体渲染能力由各前端框架实现相应桥接
307
- */
308
- class DomAdapter extends core$1.ViewAdapter {
309
- constructor(mount) {
310
- super();
311
- this.mount = mount;
306
+ class DomAdapter extends core$1.Adapter {
307
+ constructor() {
308
+ super(...arguments);
309
+ this.onViewUpdated = new stream.Subject();
312
310
  this.host = createElement('div', {
313
311
  styles: {
314
312
  cursor: 'text',
@@ -324,126 +322,6 @@ class DomAdapter extends core$1.ViewAdapter {
324
322
  id: 'textbus-' + Number((Math.random() + '').substring(2)).toString(16)
325
323
  }
326
324
  });
327
- this.componentRootElementCaches = core$1.createBidirectionalMapping(a => {
328
- return a instanceof core$1.ComponentInstance;
329
- });
330
- this.slotRootNativeElementCaches = core$1.createBidirectionalMapping(a => {
331
- return a instanceof core$1.Slot;
332
- });
333
- this.slotRootVElementCaches = new WeakMap();
334
- }
335
- render(rootComponent) {
336
- const view = this.componentRender(rootComponent);
337
- return this.mount(this.host, view);
338
- }
339
- copy() {
340
- document.execCommand('copy');
341
- }
342
- /**
343
- * 根据组件获取组件的根 DOM 节点
344
- * @param component
345
- */
346
- getNativeNodeByComponent(component) {
347
- return this.componentRootElementCaches.get(component) || null;
348
- }
349
- /**
350
- * 根据 DOM 节点,获对对应的组件根节点,如传入的 DOM 节点不为组件的根节点,则返回 null
351
- * @param node
352
- */
353
- getComponentByNativeNode(node) {
354
- return this.componentRootElementCaches.get(node) || null;
355
- }
356
- /**
357
- * 根据插槽获取插槽的根 DOM 节点
358
- * @param slot
359
- */
360
- getNativeNodeBySlot(slot) {
361
- return this.slotRootNativeElementCaches.get(slot) || null;
362
- }
363
- /**
364
- * 根据 DOM 节点,获对对应的插槽根节点,如传入的 DOM 节点不为插槽的根节点,则返回 null
365
- * @param node
366
- */
367
- getSlotByNativeNode(node) {
368
- return this.slotRootNativeElementCaches.get(node) || null;
369
- }
370
- /**
371
- * 获取插槽内容节点集合
372
- * @param slot
373
- */
374
- getNodesBySlot(slot) {
375
- const rootNativeNode = this.getNativeNodeBySlot(slot);
376
- if (!rootNativeNode) {
377
- return [];
378
- }
379
- const rootVNode = this.slotRootVElementCaches.get(slot);
380
- const getNodes = (vElement, nativeNode, result) => {
381
- if (vElement.location) {
382
- result.push(nativeNode);
383
- }
384
- for (let i = 0; i < vElement.children.length; i++) {
385
- const vChild = vElement.children[i];
386
- const nativeChild = nativeNode.childNodes[i];
387
- if (vChild instanceof core$1.VElement) {
388
- getNodes(vChild, nativeChild, result);
389
- }
390
- else if (vChild instanceof core$1.VTextNode) {
391
- result.push(nativeChild);
392
- }
393
- else {
394
- result.push(this.getNativeNodeByComponent(vChild));
395
- }
396
- }
397
- return result;
398
- };
399
- return getNodes(rootVNode, rootNativeNode, []);
400
- }
401
- /**
402
- * 获取原生节点的原始数据在文档中的位置
403
- * @param node
404
- */
405
- getLocationByNativeNode(node) {
406
- let slotRootNode = node;
407
- while (!this.slotRootNativeElementCaches.get(slotRootNode)) {
408
- slotRootNode = slotRootNode.parentNode;
409
- if (!slotRootNode) {
410
- return null;
411
- }
412
- }
413
- const slot = this.slotRootNativeElementCaches.get(slotRootNode);
414
- const rootVNode = this.slotRootVElementCaches.get(slot);
415
- const getLocation = (target, tree, vNodeTree) => {
416
- if (target === tree) {
417
- return Object.assign({}, vNodeTree.location);
418
- }
419
- const childNodes = tree.childNodes;
420
- for (let i = 0; i < childNodes.length; i++) {
421
- const child = vNodeTree.children[i];
422
- const nativeChild = tree.childNodes[i];
423
- if (nativeChild === target) {
424
- if (child instanceof core$1.ComponentInstance) {
425
- const index = child.parent.indexOf(child);
426
- return {
427
- slot: child.parent,
428
- startIndex: index,
429
- endIndex: index + 1
430
- };
431
- }
432
- return child.location;
433
- }
434
- else if (child instanceof core$1.VElement) {
435
- let r = null;
436
- if (nativeChild.nodeType === Node.ELEMENT_NODE) {
437
- r = getLocation(target, nativeChild, child);
438
- }
439
- if (r) {
440
- return r;
441
- }
442
- }
443
- }
444
- return null;
445
- };
446
- return getLocation(node, slotRootNode, rootVNode);
447
325
  }
448
326
  }
449
327
 
@@ -451,7 +329,7 @@ class DomAdapter extends core$1.ViewAdapter {
451
329
  * Textbus PC 端选区桥接实现
452
330
  */
453
331
  exports.SelectionBridge = class SelectionBridge {
454
- constructor(config, injector, controller, selection, rootComponentRef, input, domAdapter) {
332
+ constructor(config, textbus, controller, selection, rootComponentRef, input, domAdapter) {
455
333
  this.config = config;
456
334
  this.selection = selection;
457
335
  this.rootComponentRef = rootComponentRef;
@@ -463,7 +341,7 @@ exports.SelectionBridge = class SelectionBridge {
463
341
  this.connector = null;
464
342
  this.ignoreSelectionChange = false;
465
343
  this.changeFromUser = false;
466
- this.docContainer = injector.get(VIEW_DOCUMENT);
344
+ this.docContainer = textbus.get(VIEW_DOCUMENT);
467
345
  this.onSelectionChange = this.selectionChangeEvent.asObservable().pipe(stream.filter(() => {
468
346
  return !controller.readonly;
469
347
  }));
@@ -647,6 +525,7 @@ exports.SelectionBridge = class SelectionBridge {
647
525
  }
648
526
  minLeft = rect2.left;
649
527
  minTop = rect2.top;
528
+ oldPosition = position;
650
529
  }
651
530
  if (isToPrevLine) {
652
531
  if (rect2.left < startLeft) {
@@ -753,7 +632,7 @@ exports.SelectionBridge = class SelectionBridge {
753
632
  this.input.composition ||
754
633
  selection.rangeCount === 0 ||
755
634
  !this.docContainer.contains(selection.anchorNode) ||
756
- this.rootComponentRef.component.slots.length === 0) {
635
+ this.rootComponentRef.component.__slots__.length === 0) {
757
636
  return;
758
637
  }
759
638
  const rawRange = selection.getRangeAt(0);
@@ -762,14 +641,14 @@ exports.SelectionBridge = class SelectionBridge {
762
641
  const isFocusStart = selection.focusNode === nativeRange.startContainer && selection.focusOffset === nativeRange.startOffset;
763
642
  if (!this.docContainer.contains(selection.focusNode)) {
764
643
  if (isFocusEnd) {
765
- const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.first);
644
+ const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.__slots__.first);
766
645
  if (!nativeNode) {
767
646
  return;
768
647
  }
769
648
  nativeRange.setEndAfter(nativeNode.lastChild);
770
649
  }
771
650
  else {
772
- const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.last);
651
+ const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.__slots__.last);
773
652
  if (!nativeNode) {
774
653
  return;
775
654
  }
@@ -992,7 +871,7 @@ exports.SelectionBridge = class SelectionBridge {
992
871
  exports.SelectionBridge = __decorate([
993
872
  core.Injectable(),
994
873
  __param(0, core.Inject(EDITOR_OPTIONS)),
995
- __metadata("design:paramtypes", [Object, core.Injector,
874
+ __metadata("design:paramtypes", [Object, core$1.Textbus,
996
875
  core$1.Controller,
997
876
  core$1.Selection,
998
877
  core$1.RootComponentRef,
@@ -1030,15 +909,10 @@ class ExperimentalCaret {
1030
909
  get display() {
1031
910
  return this._display;
1032
911
  }
1033
- constructor(scheduler, editorMask) {
912
+ constructor(domRenderer, scheduler, editorMask) {
913
+ this.domRenderer = domRenderer;
1034
914
  this.scheduler = scheduler;
1035
915
  this.editorMask = editorMask;
1036
- this.compositionState = null;
1037
- this.compositionElement = createElement('span', {
1038
- styles: {
1039
- textDecoration: 'underline'
1040
- }
1041
- });
1042
916
  this.timer = null;
1043
917
  this.oldPosition = null;
1044
918
  this._display = true;
@@ -1182,12 +1056,10 @@ class ExperimentalCaret {
1182
1056
  this.positionChangeEvent.next(null);
1183
1057
  return;
1184
1058
  }
1185
- if (this.compositionState) {
1186
- const compositionElement = this.compositionElement;
1187
- compositionElement.innerText = this.compositionState.data;
1059
+ const compositionNode = this.domRenderer.compositionNode;
1060
+ if (compositionNode) {
1188
1061
  nativeRange = nativeRange.cloneRange();
1189
- nativeRange.insertNode(compositionElement);
1190
- nativeRange.selectNodeContents(compositionElement);
1062
+ nativeRange.selectNodeContents(compositionNode);
1191
1063
  nativeRange.collapse();
1192
1064
  }
1193
1065
  const rect = getLayoutRectByRange(nativeRange);
@@ -1248,18 +1120,18 @@ exports.MagicInput = class MagicInput extends Input {
1248
1120
  get disabled() {
1249
1121
  return this._disabled;
1250
1122
  }
1251
- constructor(parser, keyboard, commander, selection, controller, scheduler, injector) {
1123
+ constructor(domAdapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
1252
1124
  super();
1125
+ this.domAdapter = domAdapter;
1253
1126
  this.parser = parser;
1254
1127
  this.keyboard = keyboard;
1255
1128
  this.commander = commander;
1256
1129
  this.selection = selection;
1257
1130
  this.controller = controller;
1258
1131
  this.scheduler = scheduler;
1259
- this.injector = injector;
1132
+ this.textbus = textbus;
1260
1133
  this.composition = false;
1261
- this.compositionState = null;
1262
- this.caret = new ExperimentalCaret(this.scheduler, this.injector.get(VIEW_MASK));
1134
+ this.caret = new ExperimentalCaret(this.domAdapter, this.scheduler, this.textbus.get(VIEW_MASK));
1263
1135
  this.isSafari = isSafari();
1264
1136
  this.isFirefox = isFirefox();
1265
1137
  this.isMac = isMac();
@@ -1299,13 +1171,8 @@ exports.MagicInput = class MagicInput extends Input {
1299
1171
  if (!this.isFocus) {
1300
1172
  (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1301
1173
  setTimeout(() => {
1302
- var _a, _b, _c;
1303
1174
  if (!this.nativeFocus && this.isFocus) {
1304
- this.subscription.unsubscribe();
1305
- (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1306
- this.subscription = new stream.Subscription();
1307
- this.init();
1308
- (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1175
+ this.reInit();
1309
1176
  }
1310
1177
  });
1311
1178
  }
@@ -1321,6 +1188,22 @@ exports.MagicInput = class MagicInput extends Input {
1321
1188
  this.caret.destroy();
1322
1189
  this.subscription.unsubscribe();
1323
1190
  }
1191
+ reInit(delay = false) {
1192
+ var _a, _b, _c;
1193
+ this.subscription.unsubscribe();
1194
+ (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1195
+ this.subscription = new stream.Subscription();
1196
+ this.init();
1197
+ if (delay) {
1198
+ setTimeout(() => {
1199
+ var _a;
1200
+ (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1201
+ });
1202
+ }
1203
+ else {
1204
+ (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1205
+ }
1206
+ }
1324
1207
  init() {
1325
1208
  const doc = this.doc;
1326
1209
  const contentBody = doc.body;
@@ -1329,9 +1212,19 @@ exports.MagicInput = class MagicInput extends Input {
1329
1212
  contentBody.appendChild(textarea);
1330
1213
  this.textarea = textarea;
1331
1214
  this.subscription.add(stream.fromEvent(textarea, 'blur').subscribe(() => {
1215
+ // if (this.isFocus) {
1216
+ // this.isFocus = false
1217
+ // this.reInit(true)
1218
+ // }
1332
1219
  this.isFocus = false;
1333
1220
  this.nativeFocus = false;
1334
1221
  this.caret.hide();
1222
+ if (this.domAdapter.composition) {
1223
+ const slot = this.domAdapter.composition.slot;
1224
+ this.domAdapter.composition = null;
1225
+ this.domAdapter.compositionNode = null;
1226
+ slot.__changeMarker__.forceMarkDirtied();
1227
+ }
1335
1228
  }), stream.fromEvent(textarea, 'focus').subscribe(() => {
1336
1229
  this.nativeFocus = true;
1337
1230
  }), this.caret.onStyleChange.subscribe(style => {
@@ -1342,7 +1235,7 @@ exports.MagicInput = class MagicInput extends Input {
1342
1235
  this.handleDefaultActions(textarea);
1343
1236
  }
1344
1237
  handleDefaultActions(textarea) {
1345
- this.subscription.add(stream.fromEvent(document, 'copy').subscribe(ev => {
1238
+ this.subscription.add(stream.fromEvent(isFirefox() ? textarea : document, 'copy').subscribe(ev => {
1346
1239
  const selection = this.selection;
1347
1240
  if (!selection.isSelected) {
1348
1241
  return;
@@ -1454,7 +1347,6 @@ exports.MagicInput = class MagicInput extends Input {
1454
1347
  this.commander.delete();
1455
1348
  }
1456
1349
  this.composition = true;
1457
- this.caret.compositionState = this.compositionState = null;
1458
1350
  startIndex = this.selection.startOffset;
1459
1351
  const startSlot = this.selection.startSlot;
1460
1352
  const event = new core$1.Event(startSlot, {
@@ -1471,10 +1363,11 @@ exports.MagicInput = class MagicInput extends Input {
1471
1363
  return;
1472
1364
  }
1473
1365
  const startSlot = this.selection.startSlot;
1474
- this.caret.compositionState = this.compositionState = {
1366
+ this.domAdapter.composition = {
1475
1367
  slot: startSlot,
1476
- index: startIndex,
1477
- data: ev.data
1368
+ text: ev.data,
1369
+ offset: ev.data.length,
1370
+ index: startIndex
1478
1371
  };
1479
1372
  this.caret.refresh(true);
1480
1373
  const event = new core$1.Event(startSlot, {
@@ -1482,6 +1375,7 @@ exports.MagicInput = class MagicInput extends Input {
1482
1375
  data: ev.data
1483
1376
  });
1484
1377
  core$1.invokeListener(startSlot.parent, 'onCompositionUpdate', event);
1378
+ startSlot.__changeMarker__.forceMarkDirtied();
1485
1379
  }));
1486
1380
  let isCompositionEnd = false;
1487
1381
  this.subscription.add(stream.merge(stream.fromEvent(textarea, 'beforeinput').pipe(stream.filter(ev => {
@@ -1505,24 +1399,15 @@ exports.MagicInput = class MagicInput extends Input {
1505
1399
  textarea.value = '';
1506
1400
  return ev.data;
1507
1401
  }))).subscribe(text => {
1402
+ var _a;
1508
1403
  this.composition = false;
1509
- this.caret.compositionState = this.compositionState = null;
1510
- const compositionElement = this.caret.compositionElement;
1511
- let nextSibling = compositionElement.nextSibling;
1512
- while (nextSibling) {
1513
- if (!nextSibling.textContent) {
1514
- const next = nextSibling.nextSibling;
1515
- nextSibling.remove();
1516
- nextSibling = next;
1517
- continue;
1518
- }
1519
- nextSibling.remove();
1520
- break;
1521
- }
1522
- compositionElement.remove();
1404
+ this.domAdapter.composition = null;
1523
1405
  if (text) {
1524
1406
  this.commander.write(text);
1525
1407
  }
1408
+ else {
1409
+ (_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.__changeMarker__.forceMarkDirtied();
1410
+ }
1526
1411
  if (isCompositionEnd) {
1527
1412
  const startSlot = this.selection.startSlot;
1528
1413
  if (startSlot) {
@@ -1551,13 +1436,14 @@ exports.MagicInput = class MagicInput extends Input {
1551
1436
  };
1552
1437
  exports.MagicInput = __decorate([
1553
1438
  core.Injectable(),
1554
- __metadata("design:paramtypes", [exports.Parser,
1439
+ __metadata("design:paramtypes", [DomAdapter,
1440
+ exports.Parser,
1555
1441
  core$1.Keyboard,
1556
1442
  core$1.Commander,
1557
1443
  core$1.Selection,
1558
1444
  core$1.Controller,
1559
1445
  core$1.Scheduler,
1560
- core.Injector])
1446
+ core$1.Textbus])
1561
1447
  ], exports.MagicInput);
1562
1448
 
1563
1449
  /**
@@ -1569,10 +1455,11 @@ class CollaborateSelectionAwarenessDelegate {
1569
1455
  * 协作光标绘制类
1570
1456
  */
1571
1457
  exports.CollaborateCursor = class CollaborateCursor {
1572
- constructor(injector, nativeSelection, scheduler, selection, awarenessDelegate) {
1458
+ constructor(textbus, nativeSelection, scheduler, selection, userActivity, awarenessDelegate) {
1573
1459
  this.nativeSelection = nativeSelection;
1574
1460
  this.scheduler = scheduler;
1575
1461
  this.selection = selection;
1462
+ this.userActivity = userActivity;
1576
1463
  this.awarenessDelegate = awarenessDelegate;
1577
1464
  this.host = createElement('div', {
1578
1465
  styles: {
@@ -1622,7 +1509,8 @@ exports.CollaborateCursor = class CollaborateCursor {
1622
1509
  this.onRectsChange = new stream.Subject();
1623
1510
  this.subscription = new stream.Subscription();
1624
1511
  this.currentSelection = [];
1625
- this.container = injector.get(VIEW_CONTAINER);
1512
+ this.ratio = window.devicePixelRatio || 1;
1513
+ this.container = textbus.get(VIEW_CONTAINER);
1626
1514
  this.canvasContainer.append(this.canvas);
1627
1515
  this.host.append(this.canvasContainer, this.tooltips);
1628
1516
  this.container.prepend(this.host);
@@ -1641,6 +1529,13 @@ exports.CollaborateCursor = class CollaborateCursor {
1641
1529
  this.refresh();
1642
1530
  }));
1643
1531
  }
1532
+ init() {
1533
+ if (this.userActivity) {
1534
+ this.subscription.add(this.userActivity.onStateChange.subscribe(v => {
1535
+ this.draw(v);
1536
+ }));
1537
+ }
1538
+ }
1644
1539
  /**
1645
1540
  * 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
1646
1541
  */
@@ -1658,15 +1553,16 @@ exports.CollaborateCursor = class CollaborateCursor {
1658
1553
  this.currentSelection = paths;
1659
1554
  const containerRect = this.container.getBoundingClientRect();
1660
1555
  this.canvas.style.top = containerRect.top * -1 + 'px';
1661
- this.canvas.width = this.canvas.offsetWidth;
1662
- this.canvas.height = this.canvas.offsetHeight;
1556
+ this.canvas.width = this.canvas.offsetWidth * this.ratio;
1557
+ this.canvas.height = this.canvas.offsetHeight * this.ratio;
1558
+ this.context.scale(this.ratio, this.ratio);
1663
1559
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1664
1560
  const users = [];
1665
1561
  paths.filter(i => {
1666
- return i.paths.anchor.length && i.paths.focus.length;
1562
+ return i.selection.anchor.length && i.selection.focus.length;
1667
1563
  }).forEach(item => {
1668
- const anchorPaths = [...item.paths.anchor];
1669
- const focusPaths = [...item.paths.focus];
1564
+ const anchorPaths = [...item.selection.anchor];
1565
+ const focusPaths = [...item.selection.focus];
1670
1566
  const anchorOffset = anchorPaths.pop();
1671
1567
  const anchorSlot = this.selection.findSlotByPaths(anchorPaths);
1672
1568
  const focusOffset = focusPaths.pop();
@@ -1684,8 +1580,13 @@ exports.CollaborateCursor = class CollaborateCursor {
1684
1580
  return;
1685
1581
  }
1686
1582
  const nativeRange = document.createRange();
1687
- nativeRange.setStart(anchor.node, anchor.offset);
1688
- nativeRange.setEnd(focus.node, focus.offset);
1583
+ try {
1584
+ nativeRange.setStart(anchor.node, anchor.offset);
1585
+ nativeRange.setEnd(focus.node, focus.offset);
1586
+ }
1587
+ catch (e) {
1588
+ return;
1589
+ }
1689
1590
  if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
1690
1591
  nativeRange.setStart(focus.node, focus.offset);
1691
1592
  nativeRange.setEnd(anchor.node, anchor.offset);
@@ -1814,10 +1715,12 @@ exports.CollaborateCursor = class CollaborateCursor {
1814
1715
  exports.CollaborateCursor = __decorate([
1815
1716
  core.Injectable(),
1816
1717
  __param(4, core.Optional()),
1817
- __metadata("design:paramtypes", [core.Injector,
1718
+ __param(5, core.Optional()),
1719
+ __metadata("design:paramtypes", [core$1.Textbus,
1818
1720
  exports.SelectionBridge,
1819
1721
  core$1.Scheduler,
1820
1722
  core$1.Selection,
1723
+ collaborate.UserActivity,
1821
1724
  CollaborateSelectionAwarenessDelegate])
1822
1725
  ], exports.CollaborateCursor);
1823
1726
 
@@ -1923,7 +1826,7 @@ class NativeCaret {
1923
1826
  this.subs = [];
1924
1827
  }
1925
1828
  }
1926
- let NativeInput = class NativeInput extends Input {
1829
+ exports.NativeInput = class NativeInput extends Input {
1927
1830
  set disabled(b) {
1928
1831
  this._disabled = b;
1929
1832
  if (this.controller.readonly) {
@@ -1935,7 +1838,7 @@ let NativeInput = class NativeInput extends Input {
1935
1838
  get disabled() {
1936
1839
  return this._disabled;
1937
1840
  }
1938
- constructor(injector, parser, scheduler, selection, keyboard, domAdapter, commander, controller) {
1841
+ constructor(textbus, parser, scheduler, selection, keyboard, domAdapter, commander, controller) {
1939
1842
  super();
1940
1843
  this.parser = parser;
1941
1844
  this.scheduler = scheduler;
@@ -1946,7 +1849,7 @@ let NativeInput = class NativeInput extends Input {
1946
1849
  this.controller = controller;
1947
1850
  this.caret = new NativeCaret(this.scheduler);
1948
1851
  this.composition = false;
1949
- this.compositionState = null;
1852
+ // compositionState: CompositionState | null = null
1950
1853
  this.onReady = Promise.resolve();
1951
1854
  this._disabled = false;
1952
1855
  this.nativeSelection = document.getSelection();
@@ -1956,7 +1859,7 @@ let NativeInput = class NativeInput extends Input {
1956
1859
  this.isMac = isMac();
1957
1860
  this.isMobileBrowser = isMobileBrowser();
1958
1861
  this.ignoreComposition = false; // 有 bug 版本搜狗拼音
1959
- this.documentView = injector.get(VIEW_DOCUMENT);
1862
+ this.documentView = textbus.get(VIEW_DOCUMENT);
1960
1863
  if (!controller.readonly) {
1961
1864
  this.documentView.contentEditable = 'true';
1962
1865
  }
@@ -1989,7 +1892,7 @@ let NativeInput = class NativeInput extends Input {
1989
1892
  this.subscription.unsubscribe();
1990
1893
  }
1991
1894
  handleDefaultActions(textarea) {
1992
- this.subscription.add(stream.fromEvent(document, 'copy').subscribe(ev => {
1895
+ this.subscription.add(stream.fromEvent(isFirefox() ? textarea : document, 'copy').subscribe(ev => {
1993
1896
  const selection = this.selection;
1994
1897
  if (!selection.isSelected) {
1995
1898
  return;
@@ -2043,8 +1946,8 @@ let NativeInput = class NativeInput extends Input {
2043
1946
  });
2044
1947
  }));
2045
1948
  }
2046
- handlePaste(html, text) {
2047
- const slot = this.parser.parse(html, new core$1.Slot([
1949
+ handlePaste(dom, text) {
1950
+ const slot = this.parser.parse(dom, new core$1.Slot([
2048
1951
  core$1.ContentType.BlockComponent,
2049
1952
  core$1.ContentType.InlineComponent,
2050
1953
  core$1.ContentType.Text
@@ -2104,7 +2007,6 @@ let NativeInput = class NativeInput extends Input {
2104
2007
  let startIndex;
2105
2008
  const compositionStart = () => {
2106
2009
  this.composition = true;
2107
- this.compositionState = null;
2108
2010
  startIndex = this.selection.startOffset;
2109
2011
  const startSlot = this.selection.startSlot;
2110
2012
  const event = new core$1.Event(startSlot, {
@@ -2114,11 +2016,6 @@ let NativeInput = class NativeInput extends Input {
2114
2016
  };
2115
2017
  const compositionUpdate = (data) => {
2116
2018
  const startSlot = this.selection.startSlot;
2117
- this.compositionState = {
2118
- slot: startSlot,
2119
- index: startIndex,
2120
- data
2121
- };
2122
2019
  const event = new core$1.Event(startSlot, {
2123
2020
  index: startIndex,
2124
2021
  data
@@ -2205,7 +2102,6 @@ let NativeInput = class NativeInput extends Input {
2205
2102
  return !this.ignoreComposition;
2206
2103
  })).subscribe(() => {
2207
2104
  this.composition = true;
2208
- this.compositionState = null;
2209
2105
  startIndex = this.selection.startOffset;
2210
2106
  const startSlot = this.selection.startSlot;
2211
2107
  const event = new core$1.Event(startSlot, {
@@ -2216,11 +2112,6 @@ let NativeInput = class NativeInput extends Input {
2216
2112
  return !this.ignoreComposition;
2217
2113
  })).subscribe(ev => {
2218
2114
  const startSlot = this.selection.startSlot;
2219
- this.compositionState = {
2220
- slot: startSlot,
2221
- index: startIndex,
2222
- data: ev.data
2223
- };
2224
2115
  const event = new core$1.Event(startSlot, {
2225
2116
  index: startIndex,
2226
2117
  data: ev.data
@@ -2270,7 +2161,6 @@ let NativeInput = class NativeInput extends Input {
2270
2161
  return !b;
2271
2162
  }))).subscribe(text => {
2272
2163
  this.composition = false;
2273
- this.compositionState = null;
2274
2164
  if (text) {
2275
2165
  this.commander.write(text);
2276
2166
  }
@@ -2285,9 +2175,9 @@ let NativeInput = class NativeInput extends Input {
2285
2175
  }));
2286
2176
  }
2287
2177
  };
2288
- NativeInput = __decorate([
2178
+ exports.NativeInput = __decorate([
2289
2179
  core.Injectable(),
2290
- __metadata("design:paramtypes", [core.Injector,
2180
+ __metadata("design:paramtypes", [core$1.Textbus,
2291
2181
  exports.Parser,
2292
2182
  core$1.Scheduler,
2293
2183
  core$1.Selection,
@@ -2295,11 +2185,11 @@ NativeInput = __decorate([
2295
2185
  DomAdapter,
2296
2186
  core$1.Commander,
2297
2187
  core$1.Controller])
2298
- ], NativeInput);
2188
+ ], exports.NativeInput);
2299
2189
 
2190
+ const browserErrorFn = core$1.makeError('BrowserModule');
2300
2191
  class BrowserModule {
2301
- constructor(host, config) {
2302
- this.host = host;
2192
+ constructor(config) {
2303
2193
  this.config = config;
2304
2194
  const { mask, wrapper } = BrowserModule.createLayout();
2305
2195
  wrapper.prepend(config.adapter.host);
@@ -2323,26 +2213,79 @@ class BrowserModule {
2323
2213
  useExisting: exports.SelectionBridge
2324
2214
  }, {
2325
2215
  provide: Input,
2326
- useClass: config.useContentEditable ? NativeInput : exports.MagicInput
2216
+ useClass: config.useContentEditable ? exports.NativeInput : exports.MagicInput
2327
2217
  }, {
2328
- provide: core$1.ViewAdapter,
2329
- useFactory(v) {
2330
- return v;
2331
- },
2332
- deps: [DomAdapter]
2218
+ provide: core$1.Adapter,
2219
+ useValue: config.adapter
2333
2220
  }, {
2334
2221
  provide: DomAdapter,
2335
2222
  useValue: config.adapter
2223
+ }, {
2224
+ provide: core$1.FocusManager,
2225
+ useFactory: (input) => {
2226
+ const focusEvent = new stream.Subject();
2227
+ const blurEvent = new stream.Subject();
2228
+ input.caret.onPositionChange.pipe(stream.map(p => !!p), stream.distinctUntilChanged()).subscribe(b => {
2229
+ if (b) {
2230
+ focusEvent.next();
2231
+ }
2232
+ else {
2233
+ blurEvent.next();
2234
+ }
2235
+ });
2236
+ return {
2237
+ onFocus: focusEvent,
2238
+ onBlur: blurEvent
2239
+ };
2240
+ },
2241
+ deps: [Input]
2336
2242
  },
2337
2243
  exports.Parser,
2338
2244
  exports.SelectionBridge,
2339
- exports.CollaborateCursor
2340
- ];
2245
+ exports.CollaborateCursor];
2341
2246
  this.workbench = wrapper;
2342
- this.host.append(wrapper);
2343
2247
  }
2344
- onDestroy() {
2345
- this.workbench.remove();
2248
+ /**
2249
+ * 解析 HTML 并返回一个组件实例
2250
+ * @param html 要解析的 HTML
2251
+ * @param rootComponentLoader 文档根组件加载器
2252
+ * @param textbus
2253
+ */
2254
+ readDocumentByHTML(html, rootComponentLoader, textbus) {
2255
+ const parser = textbus.get(exports.Parser);
2256
+ const doc = parser.parseDoc(html, rootComponentLoader);
2257
+ if (doc instanceof core$1.Component) {
2258
+ return doc;
2259
+ }
2260
+ throw browserErrorFn('rootComponentLoader must return a component instance.');
2261
+ }
2262
+ /**
2263
+ * 将组件数据解析到组件实例中
2264
+ * @param data 要解析的 JSON 数据
2265
+ * @param rootComponent 根组件
2266
+ * @param textbus
2267
+ */
2268
+ readDocumentByComponentLiteral(data, rootComponent, textbus) {
2269
+ const registry = textbus.get(core$1.Registry);
2270
+ return registry.createComponentByFactory(data, rootComponent);
2271
+ }
2272
+ setup(textbus) {
2273
+ const host = this.config.renderTo();
2274
+ if (!(host instanceof HTMLElement)) {
2275
+ throw browserErrorFn('view container is not a HTMLElement');
2276
+ }
2277
+ const cursor = textbus.get(exports.CollaborateCursor);
2278
+ cursor.init();
2279
+ host.append(this.workbench);
2280
+ return () => {
2281
+ cursor.destroy();
2282
+ this.workbench.remove();
2283
+ };
2284
+ }
2285
+ onAfterStartup(textbus) {
2286
+ if (this.config.autoFocus) {
2287
+ textbus.focus();
2288
+ }
2346
2289
  }
2347
2290
  static createLayout() {
2348
2291
  const mask = createElement('div', {