@textbus/platform-browser 3.3.1 → 3.3.3

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.
@@ -2,6 +2,9 @@ import { Injector } from '@tanbo/di';
2
2
  import { Selection, SelectionPaths, AbstractSelection, Scheduler } from '@textbus/core';
3
3
  import { SelectionBridge } from '../core/selection-bridge';
4
4
  import { Rect } from '../_utils/uikit';
5
+ /**
6
+ * 远程用户及光标位置信息
7
+ */
5
8
  export interface RemoteSelection {
6
9
  id: string;
7
10
  color: string;
@@ -18,9 +21,15 @@ export interface RemoteSelectionCursor {
18
21
  anchor: HTMLElement;
19
22
  userTip: HTMLElement;
20
23
  }
24
+ /**
25
+ * 远程光标绘制范围计算代理类,可用于定制特定场景下的远程选区绘制,如表格有选区,不会遵守常见的文档流形式
26
+ */
21
27
  export declare abstract class CollaborateSelectionAwarenessDelegate {
22
28
  abstract getRects(abstractSelection: AbstractSelection, nativeRange: Range): false | Rect[];
23
29
  }
30
+ /**
31
+ * 协作光标绘制类
32
+ */
24
33
  export declare class CollaborateCursor {
25
34
  private injector;
26
35
  private nativeSelection;
@@ -37,8 +46,15 @@ export declare class CollaborateCursor {
37
46
  private currentSelection;
38
47
  private container;
39
48
  constructor(injector: Injector, nativeSelection: SelectionBridge, scheduler: Scheduler, selection: Selection, awarenessDelegate?: CollaborateSelectionAwarenessDelegate | undefined);
49
+ /**
50
+ * 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
51
+ */
40
52
  refresh(): void;
41
53
  destroy(): void;
54
+ /**
55
+ * 根据远程用户光标位置,绘制协作光标
56
+ * @param paths
57
+ */
42
58
  draw(paths: RemoteSelection[]): void;
43
59
  protected drawUserCursor(rects: SelectionRect[]): void;
44
60
  private getUserCursor;
@@ -1,6 +1,6 @@
1
1
  import { VElement } from '@textbus/core';
2
2
  /**
3
- * HTML 输出转换器
3
+ * HTML 输出转换器,用于将虚拟 DOM 转换为 HTML 字符串
4
4
  */
5
5
  export declare class OutputTranslator {
6
6
  static singleTags: string[];
@@ -10,6 +10,10 @@ export declare class OutputTranslator {
10
10
  attrValue(text: string): string;
11
11
  };
12
12
  private singleTagTest;
13
+ /**
14
+ * 将虚拟 DOM 转换为 HTML 字符串的方法
15
+ * @param vDom 虚拟 DOM 节点
16
+ */
13
17
  transform(vDom: VElement): string;
14
18
  private vDomToHTMLString;
15
19
  private replaceEmpty;
@@ -1,6 +1,9 @@
1
1
  import { Injector } from '@tanbo/di';
2
2
  import { Attribute, ComponentInstance, Formatter, FormatValue, Slot } from '@textbus/core';
3
3
  import { ViewOptions } from '../core/types';
4
+ /**
5
+ * 组件可附加携带的信息,如一些样式表、脚本、或编辑时模式时的样式
6
+ */
4
7
  export interface ComponentResources {
5
8
  links?: Array<{
6
9
  [key: string]: string;
@@ -9,7 +12,18 @@ export interface ComponentResources {
9
12
  scripts?: string[];
10
13
  editModeStyles?: string[];
11
14
  }
15
+ /**
16
+ * 插槽解析器
17
+ */
12
18
  export interface SlotParser {
19
+ /**
20
+ * 将指定 DOM 节点解析为插槽数据
21
+ * @param childSlot 储存数据的插槽
22
+ * @param slotRootElement 插槽的根节点
23
+ * @param slotContentHostElement 插槽的内容节点
24
+ *
25
+ * 注意:当不传入内容节点时,Textbus 会把根节点当成内容节点
26
+ */
13
27
  <T extends Slot>(childSlot: T, slotRootElement: HTMLElement, slotContentHostElement?: HTMLElement): T;
14
28
  }
15
29
  /**
@@ -27,18 +41,43 @@ export interface FormatLoaderReadResult<T extends FormatValue> {
27
41
  formatter: Formatter<T>;
28
42
  value: T;
29
43
  }
44
+ /**
45
+ * 格式加载器
46
+ */
30
47
  export interface FormatLoader<T extends FormatValue> {
48
+ /**
49
+ * 匹配一个 DOM 节点是否是某个格式节点
50
+ * @param element
51
+ */
31
52
  match(element: HTMLElement): boolean;
53
+ /**
54
+ * 读取匹配到的节点,并返回读取后的信息
55
+ * @param element
56
+ */
32
57
  read(element: HTMLElement): FormatLoaderReadResult<T>;
33
58
  }
34
59
  export interface AttributeLoaderReadResult<T extends FormatValue> {
35
60
  attribute: Attribute<T>;
36
61
  value: T;
37
62
  }
63
+ /**
64
+ * 属性加载器
65
+ */
38
66
  export interface AttributeLoader<T extends FormatValue> {
67
+ /**
68
+ * 匹配一个 DOM 节点是否是某个属性节点
69
+ * @param element
70
+ */
39
71
  match(element: HTMLElement): boolean;
72
+ /**
73
+ * 读取匹配到的节点,并返回读取后的信息
74
+ * @param element
75
+ */
40
76
  read(element: HTMLElement): AttributeLoaderReadResult<T>;
41
77
  }
78
+ /**
79
+ * 用于解析 HTML,并把 HTML 内容转换为 Textbus 可以支持的组件或插槽数据
80
+ */
42
81
  export declare class Parser {
43
82
  private options;
44
83
  private injector;
@@ -47,7 +86,17 @@ export declare class Parser {
47
86
  formatLoaders: FormatLoader<any>[];
48
87
  attributeLoaders: AttributeLoader<any>[];
49
88
  constructor(options: ViewOptions, injector: Injector);
89
+ /**
90
+ * 使用指定的组件加载器解析一段 HTML 字符串
91
+ * @param html
92
+ * @param rootComponentLoader
93
+ */
50
94
  parseDoc(html: string, rootComponentLoader: ComponentLoader): Slot<any> | ComponentInstance<import("@textbus/core").ComponentExtends, any, unknown>;
95
+ /**
96
+ * 将一段 HTML 解析到指定插槽
97
+ * @param html
98
+ * @param rootSlot
99
+ */
51
100
  parse(html: string, rootSlot: Slot): Slot<any>;
52
101
  private readComponent;
53
102
  private readFormats;
@@ -463,28 +463,8 @@ let SelectionBridge = class SelectionBridge {
463
463
  }
464
464
  }));
465
465
  }
466
- const oldSelection = {
467
- focusNode: null,
468
- focusOffset: null,
469
- anchorNode: null,
470
- anchorOffset: null
471
- };
472
466
  this.subs.push(fromEvent(document, 'selectionchange').pipe().subscribe(() => {
473
- const { anchorNode, anchorOffset, focusOffset, focusNode } = this.nativeSelection;
474
- if (anchorNode !== oldSelection.anchorNode ||
475
- anchorOffset !== oldSelection.anchorOffset ||
476
- focusNode !== oldSelection.focusNode ||
477
- focusOffset !== oldSelection.focusOffset) {
478
- this.syncSelection(connector);
479
- oldSelection.anchorNode = anchorNode;
480
- oldSelection.anchorOffset = anchorOffset;
481
- oldSelection.focusNode = focusNode;
482
- oldSelection.focusOffset = focusOffset;
483
- }
484
- else {
485
- const nativeRange = this.nativeSelection.getRangeAt(0);
486
- this.selectionChangeEvent.next(nativeRange || null);
487
- }
467
+ this.syncSelection(connector);
488
468
  }));
489
469
  }
490
470
  syncSelection(connector) {
@@ -558,7 +538,10 @@ let SelectionBridge = class SelectionBridge {
558
538
  nativeRange.setEnd(end.node, end.offset);
559
539
  }
560
540
  connector.setSelection(abstractSelection);
561
- if (selection.isCollapsed) {
541
+ if (selection.isCollapsed && (rawRange.startContainer !== start.node ||
542
+ rawRange.startOffset !== start.offset ||
543
+ rawRange.endContainer !== end.node ||
544
+ rawRange.endOffset !== end.offset)) {
562
545
  rawRange.setStart(start.node, start.offset);
563
546
  rawRange.setEnd(end.node, end.offset);
564
547
  }
@@ -752,8 +735,14 @@ SelectionBridge = __decorate([
752
735
  Renderer])
753
736
  ], SelectionBridge);
754
737
 
738
+ /**
739
+ * 远程光标绘制范围计算代理类,可用于定制特定场景下的远程选区绘制,如表格有选区,不会遵守常见的文档流形式
740
+ */
755
741
  class CollaborateSelectionAwarenessDelegate {
756
742
  }
743
+ /**
744
+ * 协作光标绘制类
745
+ */
757
746
  let CollaborateCursor = class CollaborateCursor {
758
747
  constructor(injector, nativeSelection, scheduler, selection, awarenessDelegate) {
759
748
  this.injector = injector;
@@ -828,12 +817,19 @@ let CollaborateCursor = class CollaborateCursor {
828
817
  this.refresh();
829
818
  }));
830
819
  }
820
+ /**
821
+ * 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
822
+ */
831
823
  refresh() {
832
824
  this.draw(this.currentSelection);
833
825
  }
834
826
  destroy() {
835
827
  this.subscription.unsubscribe();
836
828
  }
829
+ /**
830
+ * 根据远程用户光标位置,绘制协作光标
831
+ * @param paths
832
+ */
837
833
  draw(paths) {
838
834
  this.currentSelection = paths;
839
835
  const containerRect = this.container.getBoundingClientRect();
@@ -1214,6 +1210,9 @@ DomRenderer = DomRenderer_1 = __decorate([
1214
1210
  ], DomRenderer);
1215
1211
 
1216
1212
  var Parser_1;
1213
+ /**
1214
+ * 用于解析 HTML,并把 HTML 内容转换为 Textbus 可以支持的组件或插槽数据
1215
+ */
1217
1216
  let Parser = Parser_1 = class Parser {
1218
1217
  static parseHTML(html) {
1219
1218
  return new DOMParser().parseFromString(html, 'text/html').body;
@@ -1239,12 +1238,22 @@ let Parser = Parser_1 = class Parser {
1239
1238
  this.formatLoaders = formatLoaders;
1240
1239
  this.attributeLoaders = attributeLoaders;
1241
1240
  }
1241
+ /**
1242
+ * 使用指定的组件加载器解析一段 HTML 字符串
1243
+ * @param html
1244
+ * @param rootComponentLoader
1245
+ */
1242
1246
  parseDoc(html, rootComponentLoader) {
1243
1247
  const element = Parser_1.parseHTML(html);
1244
1248
  return rootComponentLoader.read(element, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
1245
1249
  return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
1246
1250
  });
1247
1251
  }
1252
+ /**
1253
+ * 将一段 HTML 解析到指定插槽
1254
+ * @param html
1255
+ * @param rootSlot
1256
+ */
1248
1257
  parse(html, rootSlot) {
1249
1258
  const element = Parser_1.parseHTML(html);
1250
1259
  return this.readFormats(element, rootSlot);
@@ -1530,7 +1539,7 @@ class ExperimentalCaret {
1530
1539
  else {
1531
1540
  height = parseFloat(fontSize) * parseFloat(lineHeight);
1532
1541
  }
1533
- const boxHeight = Math.floor(Math.max(height, rect.height));
1542
+ const boxHeight = Math.max(Math.floor(Math.max(height, rect.height)), 12);
1534
1543
  // const boxHeight = Math.floor(height)
1535
1544
  let rectTop = rect.top;
1536
1545
  if (rect.height < height) {
@@ -2345,12 +2354,16 @@ NativeInput = __decorate([
2345
2354
 
2346
2355
  var OutputTranslator_1;
2347
2356
  /**
2348
- * HTML 输出转换器
2357
+ * HTML 输出转换器,用于将虚拟 DOM 转换为 HTML 字符串
2349
2358
  */
2350
2359
  let OutputTranslator = OutputTranslator_1 = class OutputTranslator {
2351
2360
  constructor() {
2352
2361
  this.singleTagTest = new RegExp(`^(${OutputTranslator_1.singleTags.join('|')})$`, 'i');
2353
2362
  }
2363
+ /**
2364
+ * 将虚拟 DOM 转换为 HTML 字符串的方法
2365
+ * @param vDom 虚拟 DOM 节点
2366
+ */
2354
2367
  transform(vDom) {
2355
2368
  return vDom.children.map(child => {
2356
2369
  return this.vDomToHTMLString(child);
package/bundles/index.js CHANGED
@@ -465,28 +465,8 @@ exports.SelectionBridge = class SelectionBridge {
465
465
  }
466
466
  }));
467
467
  }
468
- const oldSelection = {
469
- focusNode: null,
470
- focusOffset: null,
471
- anchorNode: null,
472
- anchorOffset: null
473
- };
474
468
  this.subs.push(stream.fromEvent(document, 'selectionchange').pipe().subscribe(() => {
475
- const { anchorNode, anchorOffset, focusOffset, focusNode } = this.nativeSelection;
476
- if (anchorNode !== oldSelection.anchorNode ||
477
- anchorOffset !== oldSelection.anchorOffset ||
478
- focusNode !== oldSelection.focusNode ||
479
- focusOffset !== oldSelection.focusOffset) {
480
- this.syncSelection(connector);
481
- oldSelection.anchorNode = anchorNode;
482
- oldSelection.anchorOffset = anchorOffset;
483
- oldSelection.focusNode = focusNode;
484
- oldSelection.focusOffset = focusOffset;
485
- }
486
- else {
487
- const nativeRange = this.nativeSelection.getRangeAt(0);
488
- this.selectionChangeEvent.next(nativeRange || null);
489
- }
469
+ this.syncSelection(connector);
490
470
  }));
491
471
  }
492
472
  syncSelection(connector) {
@@ -560,7 +540,10 @@ exports.SelectionBridge = class SelectionBridge {
560
540
  nativeRange.setEnd(end.node, end.offset);
561
541
  }
562
542
  connector.setSelection(abstractSelection);
563
- if (selection.isCollapsed) {
543
+ if (selection.isCollapsed && (rawRange.startContainer !== start.node ||
544
+ rawRange.startOffset !== start.offset ||
545
+ rawRange.endContainer !== end.node ||
546
+ rawRange.endOffset !== end.offset)) {
564
547
  rawRange.setStart(start.node, start.offset);
565
548
  rawRange.setEnd(end.node, end.offset);
566
549
  }
@@ -754,8 +737,14 @@ exports.SelectionBridge = __decorate([
754
737
  core.Renderer])
755
738
  ], exports.SelectionBridge);
756
739
 
740
+ /**
741
+ * 远程光标绘制范围计算代理类,可用于定制特定场景下的远程选区绘制,如表格有选区,不会遵守常见的文档流形式
742
+ */
757
743
  class CollaborateSelectionAwarenessDelegate {
758
744
  }
745
+ /**
746
+ * 协作光标绘制类
747
+ */
759
748
  exports.CollaborateCursor = class CollaborateCursor {
760
749
  constructor(injector, nativeSelection, scheduler, selection, awarenessDelegate) {
761
750
  this.injector = injector;
@@ -830,12 +819,19 @@ exports.CollaborateCursor = class CollaborateCursor {
830
819
  this.refresh();
831
820
  }));
832
821
  }
822
+ /**
823
+ * 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
824
+ */
833
825
  refresh() {
834
826
  this.draw(this.currentSelection);
835
827
  }
836
828
  destroy() {
837
829
  this.subscription.unsubscribe();
838
830
  }
831
+ /**
832
+ * 根据远程用户光标位置,绘制协作光标
833
+ * @param paths
834
+ */
839
835
  draw(paths) {
840
836
  this.currentSelection = paths;
841
837
  const containerRect = this.container.getBoundingClientRect();
@@ -1216,6 +1212,9 @@ exports.DomRenderer = DomRenderer_1 = __decorate([
1216
1212
  ], exports.DomRenderer);
1217
1213
 
1218
1214
  var Parser_1;
1215
+ /**
1216
+ * 用于解析 HTML,并把 HTML 内容转换为 Textbus 可以支持的组件或插槽数据
1217
+ */
1219
1218
  exports.Parser = Parser_1 = class Parser {
1220
1219
  static parseHTML(html) {
1221
1220
  return new DOMParser().parseFromString(html, 'text/html').body;
@@ -1241,12 +1240,22 @@ exports.Parser = Parser_1 = class Parser {
1241
1240
  this.formatLoaders = formatLoaders;
1242
1241
  this.attributeLoaders = attributeLoaders;
1243
1242
  }
1243
+ /**
1244
+ * 使用指定的组件加载器解析一段 HTML 字符串
1245
+ * @param html
1246
+ * @param rootComponentLoader
1247
+ */
1244
1248
  parseDoc(html, rootComponentLoader) {
1245
1249
  const element = Parser_1.parseHTML(html);
1246
1250
  return rootComponentLoader.read(element, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
1247
1251
  return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
1248
1252
  });
1249
1253
  }
1254
+ /**
1255
+ * 将一段 HTML 解析到指定插槽
1256
+ * @param html
1257
+ * @param rootSlot
1258
+ */
1250
1259
  parse(html, rootSlot) {
1251
1260
  const element = Parser_1.parseHTML(html);
1252
1261
  return this.readFormats(element, rootSlot);
@@ -1532,7 +1541,7 @@ class ExperimentalCaret {
1532
1541
  else {
1533
1542
  height = parseFloat(fontSize) * parseFloat(lineHeight);
1534
1543
  }
1535
- const boxHeight = Math.floor(Math.max(height, rect.height));
1544
+ const boxHeight = Math.max(Math.floor(Math.max(height, rect.height)), 12);
1536
1545
  // const boxHeight = Math.floor(height)
1537
1546
  let rectTop = rect.top;
1538
1547
  if (rect.height < height) {
@@ -2347,12 +2356,16 @@ exports.NativeInput = __decorate([
2347
2356
 
2348
2357
  var OutputTranslator_1;
2349
2358
  /**
2350
- * HTML 输出转换器
2359
+ * HTML 输出转换器,用于将虚拟 DOM 转换为 HTML 字符串
2351
2360
  */
2352
2361
  exports.OutputTranslator = OutputTranslator_1 = class OutputTranslator {
2353
2362
  constructor() {
2354
2363
  this.singleTagTest = new RegExp(`^(${OutputTranslator_1.singleTags.join('|')})$`, 'i');
2355
2364
  }
2365
+ /**
2366
+ * 将虚拟 DOM 转换为 HTML 字符串的方法
2367
+ * @param vDom 虚拟 DOM 节点
2368
+ */
2356
2369
  transform(vDom) {
2357
2370
  return vDom.children.map(child => {
2358
2371
  return this.vDomToHTMLString(child);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@textbus/platform-browser",
3
- "version": "3.3.1",
3
+ "version": "3.3.3",
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",
@@ -27,7 +27,7 @@
27
27
  "dependencies": {
28
28
  "@tanbo/di": "^1.1.4",
29
29
  "@tanbo/stream": "^1.1.9",
30
- "@textbus/core": "^3.3.1",
30
+ "@textbus/core": "^3.3.3",
31
31
  "reflect-metadata": "^0.1.13"
32
32
  },
33
33
  "devDependencies": {
@@ -48,5 +48,5 @@
48
48
  "bugs": {
49
49
  "url": "https://github.com/textbus/textbus.git/issues"
50
50
  },
51
- "gitHead": "afa1c378f5f46be38bd4b1fe8f881e7c6e0c7478"
51
+ "gitHead": "eed9200db6a32b45de15797d655f07939c88764b"
52
52
  }