@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;
|
package/bundles/index.esm.js
CHANGED
@@ -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
|
-
|
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
|
-
|
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.
|
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.
|
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": "
|
51
|
+
"gitHead": "eed9200db6a32b45de15797d655f07939c88764b"
|
52
52
|
}
|