@textbus/platform-browser 3.5.0 → 4.0.0-alpha.1
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/browser-module.d.ts +33 -0
- package/bundles/{collaborate/collaborate-cursor.d.ts → collaborate-cursor.d.ts} +3 -4
- package/bundles/dom-adapter.d.ts +66 -0
- package/bundles/index.esm.js +682 -1271
- package/bundles/index.js +737 -1325
- package/bundles/{core/injection-tokens.d.ts → injection-tokens.d.ts} +2 -2
- package/bundles/{core/magic-input.d.ts → magic-input.d.ts} +2 -2
- package/bundles/{core/native-input.d.ts → native-input.d.ts} +7 -7
- package/bundles/{dom-support/parser.d.ts → parser.d.ts} +3 -16
- package/bundles/public-api.d.ts +8 -4
- package/bundles/{core/selection-bridge.d.ts → selection-bridge.d.ts} +8 -10
- package/bundles/types.d.ts +44 -0
- package/package.json +4 -4
- package/bundles/core/_api.d.ts +0 -6
- package/bundles/core/dom-renderer.d.ts +0 -53
- package/bundles/core/types.d.ts +0 -74
- package/bundles/dom-support/_api.d.ts +0 -2
- package/bundles/dom-support/output-translator.d.ts +0 -20
- package/bundles/viewer.d.ts +0 -90
package/bundles/index.esm.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import 'reflect-metadata';
|
2
|
-
import {
|
3
|
-
import {
|
2
|
+
import { Slot, ViewAdapter, createBidirectionalMapping, ComponentInstance, VElement, VTextNode, Controller, Selection, RootComponentRef, ContentType, Event, invokeListener, Keyboard, Commander, Scheduler, NativeSelectionBridge } from '@textbus/core';
|
3
|
+
import { InjectionToken, Injectable, Inject, Injector, Optional } from '@viewfly/core';
|
4
4
|
import { Subject, filter, fromEvent, Subscription, distinctUntilChanged, merge, map, Observable } from '@tanbo/stream';
|
5
5
|
|
6
6
|
function createElement(tagName, options = {}) {
|
@@ -118,6 +118,8 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
118
118
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
119
119
|
PERFORMANCE OF THIS SOFTWARE.
|
120
120
|
***************************************************************************** */
|
121
|
+
/* global Reflect, Promise, SuppressedError, Symbol */
|
122
|
+
|
121
123
|
|
122
124
|
function __decorate(decorators, target, key, desc) {
|
123
125
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
@@ -134,15 +136,10 @@ function __metadata(metadataKey, metadataValue) {
|
|
134
136
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
135
137
|
}
|
136
138
|
|
137
|
-
function
|
138
|
-
|
139
|
-
return
|
140
|
-
|
141
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
142
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
143
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
144
|
-
});
|
145
|
-
}
|
139
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
140
|
+
var e = new Error(message);
|
141
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
142
|
+
};
|
146
143
|
|
147
144
|
/**
|
148
145
|
* 编辑器可选项依赖注入 token
|
@@ -161,34 +158,313 @@ const VIEW_DOCUMENT = new InjectionToken('VIEW_DOCUMENT');
|
|
161
158
|
*/
|
162
159
|
const VIEW_MASK = new InjectionToken('VIEW_MASK');
|
163
160
|
|
161
|
+
var Parser_1;
|
162
|
+
/**
|
163
|
+
* 用于解析 HTML,并把 HTML 内容转换为 Textbus 可以支持的组件或插槽数据
|
164
|
+
*/
|
165
|
+
let Parser = Parser_1 = class Parser {
|
166
|
+
static parseHTML(html) {
|
167
|
+
return new DOMParser().parseFromString(html, 'text/html').body;
|
168
|
+
}
|
169
|
+
constructor(options, injector) {
|
170
|
+
this.options = options;
|
171
|
+
this.injector = injector;
|
172
|
+
const componentLoaders = [
|
173
|
+
...(options.componentLoaders || [])
|
174
|
+
];
|
175
|
+
const formatLoaders = [
|
176
|
+
...(options.formatLoaders || [])
|
177
|
+
];
|
178
|
+
const attributeLoaders = [
|
179
|
+
...(options.attributeLoaders || [])
|
180
|
+
];
|
181
|
+
// options.imports?.forEach(i => {
|
182
|
+
// componentLoaders.push(...(i.componentLoaders || []))
|
183
|
+
// formatLoaders.push(...(i.formatLoaders || []))
|
184
|
+
// })
|
185
|
+
this.componentLoaders = componentLoaders;
|
186
|
+
this.formatLoaders = formatLoaders;
|
187
|
+
this.attributeLoaders = attributeLoaders;
|
188
|
+
}
|
189
|
+
/**
|
190
|
+
* 使用指定的组件加载器解析一段 HTML 字符串
|
191
|
+
* @param html
|
192
|
+
* @param rootComponentLoader
|
193
|
+
*/
|
194
|
+
parseDoc(html, rootComponentLoader) {
|
195
|
+
const element = Parser_1.parseHTML(html);
|
196
|
+
return rootComponentLoader.read(element, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
|
197
|
+
return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
|
198
|
+
});
|
199
|
+
}
|
200
|
+
/**
|
201
|
+
* 将一段 HTML 解析到指定插槽
|
202
|
+
* @param html
|
203
|
+
* @param rootSlot
|
204
|
+
*/
|
205
|
+
parse(html, rootSlot) {
|
206
|
+
const element = Parser_1.parseHTML(html);
|
207
|
+
return this.readFormats(element, rootSlot);
|
208
|
+
}
|
209
|
+
readComponent(el, slot) {
|
210
|
+
if (el.nodeType === Node.ELEMENT_NODE) {
|
211
|
+
if (el.tagName === 'BR') {
|
212
|
+
slot.insert('\n');
|
213
|
+
return;
|
214
|
+
}
|
215
|
+
for (const t of this.componentLoaders) {
|
216
|
+
if (t.match(el)) {
|
217
|
+
const result = t.read(el, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
|
218
|
+
return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
|
219
|
+
});
|
220
|
+
if (!result) {
|
221
|
+
return;
|
222
|
+
}
|
223
|
+
if (result instanceof Slot) {
|
224
|
+
result.toDelta().forEach(i => slot.insert(i.insert, i.formats));
|
225
|
+
return;
|
226
|
+
}
|
227
|
+
slot.insert(result);
|
228
|
+
return;
|
229
|
+
}
|
230
|
+
}
|
231
|
+
this.readFormats(el, slot);
|
232
|
+
}
|
233
|
+
else if (el.nodeType === Node.TEXT_NODE) {
|
234
|
+
this.readText(slot, el);
|
235
|
+
}
|
236
|
+
}
|
237
|
+
readText(slot, el) {
|
238
|
+
const textContent = el.textContent;
|
239
|
+
if (/^\s*[\r\n\u200b]+\s*$/.test(textContent)) {
|
240
|
+
return;
|
241
|
+
}
|
242
|
+
slot.insert(textContent);
|
243
|
+
}
|
244
|
+
readFormats(el, slot) {
|
245
|
+
const formats = this.formatLoaders.filter(f => {
|
246
|
+
return f.match(el);
|
247
|
+
}).map(f => {
|
248
|
+
return f.read(el);
|
249
|
+
});
|
250
|
+
const startIndex = slot.index;
|
251
|
+
let startNode = el.firstChild;
|
252
|
+
while (startNode) {
|
253
|
+
this.readComponent(startNode, slot);
|
254
|
+
startNode = startNode.nextSibling;
|
255
|
+
}
|
256
|
+
const endIndex = slot.index;
|
257
|
+
this.applyFormats(slot, formats.map(i => {
|
258
|
+
return {
|
259
|
+
formatter: i.formatter,
|
260
|
+
value: i.value,
|
261
|
+
startIndex,
|
262
|
+
endIndex
|
263
|
+
};
|
264
|
+
}));
|
265
|
+
slot.retain(endIndex);
|
266
|
+
return slot;
|
267
|
+
}
|
268
|
+
readSlot(childSlot, slotRootElement, slotContentElement) {
|
269
|
+
if (slotRootElement.nodeType === Node.ELEMENT_NODE) {
|
270
|
+
this.attributeLoaders.filter(a => {
|
271
|
+
return a.match(slotRootElement);
|
272
|
+
}).forEach(a => {
|
273
|
+
const r = a.read(slotRootElement);
|
274
|
+
childSlot.setAttribute(r.attribute, r.value);
|
275
|
+
});
|
276
|
+
}
|
277
|
+
if (slotContentElement.nodeType === Node.ELEMENT_NODE) {
|
278
|
+
this.readFormats(slotContentElement, childSlot);
|
279
|
+
}
|
280
|
+
else {
|
281
|
+
this.readText(childSlot, slotContentElement);
|
282
|
+
}
|
283
|
+
return childSlot;
|
284
|
+
}
|
285
|
+
applyFormats(slot, formatItems) {
|
286
|
+
slot.background(() => {
|
287
|
+
formatItems.forEach(i => {
|
288
|
+
slot.retain(i.startIndex);
|
289
|
+
slot.retain(i.endIndex - i.startIndex, i.formatter, i.value);
|
290
|
+
});
|
291
|
+
});
|
292
|
+
}
|
293
|
+
};
|
294
|
+
Parser = Parser_1 = __decorate([
|
295
|
+
Injectable(),
|
296
|
+
__param(0, Inject(EDITOR_OPTIONS)),
|
297
|
+
__metadata("design:paramtypes", [Object, Injector])
|
298
|
+
], Parser);
|
299
|
+
|
164
300
|
class Input {
|
165
301
|
}
|
166
302
|
|
303
|
+
/**
|
304
|
+
* Textbus PC 端浏览器渲染能力桥接器抽象类,提供了 DOM 元素查询能力,具体渲染能力由各前端框架实现相应桥接
|
305
|
+
*/
|
306
|
+
class DomAdapter extends ViewAdapter {
|
307
|
+
constructor(mount) {
|
308
|
+
super();
|
309
|
+
this.mount = mount;
|
310
|
+
this.host = createElement('div', {
|
311
|
+
styles: {
|
312
|
+
cursor: 'text',
|
313
|
+
wordBreak: 'break-all',
|
314
|
+
boxSizing: 'border-box',
|
315
|
+
flex: 1,
|
316
|
+
outline: 'none'
|
317
|
+
},
|
318
|
+
attrs: {
|
319
|
+
'data-textbus-view': VIEW_DOCUMENT,
|
320
|
+
},
|
321
|
+
props: {
|
322
|
+
id: 'textbus-' + Number((Math.random() + '').substring(2)).toString(16)
|
323
|
+
}
|
324
|
+
});
|
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
|
+
}
|
446
|
+
}
|
447
|
+
|
167
448
|
/**
|
168
449
|
* Textbus PC 端选区桥接实现
|
169
450
|
*/
|
170
451
|
let SelectionBridge = class SelectionBridge {
|
171
|
-
constructor(config, injector, controller, selection, rootComponentRef, input,
|
452
|
+
constructor(config, injector, controller, selection, rootComponentRef, input, domAdapter) {
|
172
453
|
this.config = config;
|
173
|
-
this.injector = injector;
|
174
|
-
this.controller = controller;
|
175
454
|
this.selection = selection;
|
176
455
|
this.rootComponentRef = rootComponentRef;
|
177
456
|
this.input = input;
|
178
|
-
this.
|
457
|
+
this.domAdapter = domAdapter;
|
179
458
|
this.nativeSelection = document.getSelection();
|
180
|
-
this.selectionMaskElement = createElement('style');
|
181
459
|
this.selectionChangeEvent = new Subject();
|
182
460
|
this.subs = [];
|
183
461
|
this.connector = null;
|
184
462
|
this.ignoreSelectionChange = false;
|
185
463
|
this.changeFromUser = false;
|
186
464
|
this.docContainer = injector.get(VIEW_DOCUMENT);
|
187
|
-
this.maskContainer = injector.get(VIEW_MASK);
|
188
465
|
this.onSelectionChange = this.selectionChangeEvent.asObservable().pipe(filter(() => {
|
189
466
|
return !controller.readonly;
|
190
467
|
}));
|
191
|
-
document.head.appendChild(this.selectionMaskElement);
|
192
468
|
this.sub = this.onSelectionChange.subscribe((r) => {
|
193
469
|
if (r) {
|
194
470
|
input.focus(r, this.changeFromUser);
|
@@ -484,22 +760,14 @@ let SelectionBridge = class SelectionBridge {
|
|
484
760
|
const isFocusStart = selection.focusNode === nativeRange.startContainer && selection.focusOffset === nativeRange.startOffset;
|
485
761
|
if (!this.docContainer.contains(selection.focusNode)) {
|
486
762
|
if (isFocusEnd) {
|
487
|
-
const
|
488
|
-
if (!vEle) {
|
489
|
-
return;
|
490
|
-
}
|
491
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vEle);
|
763
|
+
const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.first);
|
492
764
|
if (!nativeNode) {
|
493
765
|
return;
|
494
766
|
}
|
495
767
|
nativeRange.setEndAfter(nativeNode.lastChild);
|
496
768
|
}
|
497
769
|
else {
|
498
|
-
const
|
499
|
-
if (!vEle) {
|
500
|
-
return;
|
501
|
-
}
|
502
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vEle);
|
770
|
+
const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.last);
|
503
771
|
if (!nativeNode) {
|
504
772
|
return;
|
505
773
|
}
|
@@ -556,30 +824,28 @@ let SelectionBridge = class SelectionBridge {
|
|
556
824
|
}
|
557
825
|
findSelectedNodeAndOffset(slot, offset) {
|
558
826
|
const prev = slot.getContentAtIndex(offset - 1);
|
559
|
-
const
|
827
|
+
const nodes = this.domAdapter.getNodesBySlot(slot);
|
560
828
|
if (prev) {
|
561
829
|
if (typeof prev !== 'string') {
|
562
|
-
const
|
563
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
|
830
|
+
const nativeNode = this.domAdapter.getNativeNodeByComponent(prev);
|
564
831
|
return {
|
565
832
|
node: nativeNode.parentNode,
|
566
833
|
offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode) + 1
|
567
834
|
};
|
568
835
|
}
|
569
836
|
else if (prev === '\n') {
|
570
|
-
for (const
|
571
|
-
if (
|
837
|
+
for (const node of nodes) {
|
838
|
+
if (node instanceof Text) {
|
572
839
|
continue;
|
573
840
|
}
|
574
|
-
if (
|
575
|
-
const position = this.
|
841
|
+
if (node.nodeName === 'BR') {
|
842
|
+
const position = this.domAdapter.getLocationByNativeNode(node);
|
576
843
|
if (position) {
|
577
844
|
if (position.endIndex === offset) {
|
578
|
-
const
|
579
|
-
const parentNode = nativeNode.parentNode;
|
845
|
+
const parentNode = node.parentNode;
|
580
846
|
return {
|
581
847
|
node: parentNode,
|
582
|
-
offset: Array.from(parentNode.childNodes).indexOf(
|
848
|
+
offset: Array.from(parentNode.childNodes).indexOf(node) + 1
|
583
849
|
};
|
584
850
|
}
|
585
851
|
}
|
@@ -589,36 +855,33 @@ let SelectionBridge = class SelectionBridge {
|
|
589
855
|
}
|
590
856
|
const current = slot.getContentAtIndex(offset);
|
591
857
|
if (current && typeof current !== 'string') {
|
592
|
-
const
|
593
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
|
858
|
+
const nativeNode = this.domAdapter.getNativeNodeByComponent(current);
|
594
859
|
return {
|
595
860
|
node: nativeNode.parentNode,
|
596
861
|
offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode)
|
597
862
|
};
|
598
863
|
}
|
599
|
-
for (const
|
600
|
-
if (
|
601
|
-
if (
|
602
|
-
const position = this.
|
864
|
+
for (const node of nodes) {
|
865
|
+
if (node instanceof Element) {
|
866
|
+
if (node.tagName === 'BR') {
|
867
|
+
const position = this.domAdapter.getLocationByNativeNode(node);
|
603
868
|
if (position) {
|
604
869
|
if (position.startIndex === offset) {
|
605
|
-
const
|
606
|
-
const parentNode = nativeNode.parentNode;
|
870
|
+
const parentNode = node.parentNode;
|
607
871
|
return {
|
608
872
|
node: parentNode,
|
609
|
-
offset: Array.from(parentNode.childNodes).indexOf(
|
873
|
+
offset: Array.from(parentNode.childNodes).indexOf(node)
|
610
874
|
};
|
611
875
|
}
|
612
876
|
}
|
613
877
|
}
|
614
878
|
continue;
|
615
879
|
}
|
616
|
-
const position = this.
|
880
|
+
const position = this.domAdapter.getLocationByNativeNode(node);
|
617
881
|
if (position) {
|
618
882
|
if (offset >= position.startIndex && offset <= position.endIndex) {
|
619
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
|
620
883
|
return {
|
621
|
-
node:
|
884
|
+
node: node,
|
622
885
|
offset: offset - position.startIndex
|
623
886
|
};
|
624
887
|
}
|
@@ -629,10 +892,10 @@ let SelectionBridge = class SelectionBridge {
|
|
629
892
|
getCorrectedPosition(node, offset, toAfter, excludeNodes = []) {
|
630
893
|
excludeNodes.push(node);
|
631
894
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
632
|
-
const containerPosition = this.
|
895
|
+
const containerPosition = this.domAdapter.getLocationByNativeNode(node);
|
633
896
|
const childNode = node.childNodes[offset];
|
634
897
|
if (childNode) {
|
635
|
-
const childPosition = this.
|
898
|
+
const childPosition = this.domAdapter.getLocationByNativeNode(childNode);
|
636
899
|
if (childPosition) {
|
637
900
|
if (containerPosition) {
|
638
901
|
return {
|
@@ -646,7 +909,7 @@ let SelectionBridge = class SelectionBridge {
|
|
646
909
|
}
|
647
910
|
const prevNode = node.childNodes[offset - 1];
|
648
911
|
if (prevNode) {
|
649
|
-
const prevPosition = this.
|
912
|
+
const prevPosition = this.domAdapter.getLocationByNativeNode(prevNode);
|
650
913
|
if (prevPosition && containerPosition) {
|
651
914
|
return {
|
652
915
|
slot: prevPosition.slot,
|
@@ -667,7 +930,7 @@ let SelectionBridge = class SelectionBridge {
|
|
667
930
|
return this.findFocusNodeByParent(node, toAfter, excludeNodes);
|
668
931
|
}
|
669
932
|
else if (node.nodeType === Node.TEXT_NODE) {
|
670
|
-
const containerPosition = this.
|
933
|
+
const containerPosition = this.domAdapter.getLocationByNativeNode(node);
|
671
934
|
if (containerPosition) {
|
672
935
|
return {
|
673
936
|
slot: containerPosition.slot,
|
@@ -691,7 +954,7 @@ let SelectionBridge = class SelectionBridge {
|
|
691
954
|
return this.findFocusNodeByParent(node, toAfter, excludeNodes);
|
692
955
|
}
|
693
956
|
excludeNodes.push(node);
|
694
|
-
const position = this.
|
957
|
+
const position = this.domAdapter.getLocationByNativeNode(node);
|
695
958
|
if (position) {
|
696
959
|
return {
|
697
960
|
slot: position.slot,
|
@@ -711,7 +974,7 @@ let SelectionBridge = class SelectionBridge {
|
|
711
974
|
findFocusNodeByParent(node, toAfter, excludeNodes) {
|
712
975
|
const parentNode = node.parentNode;
|
713
976
|
if (parentNode) {
|
714
|
-
const parentPosition = this.
|
977
|
+
const parentPosition = this.domAdapter.getLocationByNativeNode(parentNode);
|
715
978
|
if (parentPosition) {
|
716
979
|
return {
|
717
980
|
slot: parentPosition.slot,
|
@@ -732,654 +995,40 @@ SelectionBridge = __decorate([
|
|
732
995
|
Selection,
|
733
996
|
RootComponentRef,
|
734
997
|
Input,
|
735
|
-
|
998
|
+
DomAdapter])
|
736
999
|
], SelectionBridge);
|
737
1000
|
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
width: '100%',
|
770
|
-
height: '100%',
|
771
|
-
overflow: 'hidden'
|
772
|
-
}
|
773
|
-
});
|
774
|
-
this.canvas = createElement('canvas', {
|
775
|
-
styles: {
|
776
|
-
position: 'absolute',
|
777
|
-
opacity: 0.5,
|
778
|
-
left: 0,
|
779
|
-
top: 0,
|
780
|
-
width: '100%',
|
781
|
-
height: document.documentElement.clientHeight + 'px',
|
782
|
-
pointerEvents: 'none',
|
783
|
-
}
|
784
|
-
});
|
785
|
-
this.context = this.canvas.getContext('2d');
|
786
|
-
this.tooltips = createElement('div', {
|
787
|
-
styles: {
|
788
|
-
position: 'absolute',
|
789
|
-
left: 0,
|
790
|
-
top: 0,
|
791
|
-
width: '100%',
|
792
|
-
height: '100%',
|
793
|
-
pointerEvents: 'none',
|
794
|
-
fontSize: '12px',
|
795
|
-
zIndex: 10
|
796
|
-
}
|
797
|
-
});
|
798
|
-
this.onRectsChange = new Subject();
|
799
|
-
this.subscription = new Subscription();
|
800
|
-
this.currentSelection = [];
|
801
|
-
this.container = injector.get(VIEW_CONTAINER);
|
802
|
-
this.canvasContainer.append(this.canvas);
|
803
|
-
this.host.append(this.canvasContainer, this.tooltips);
|
804
|
-
this.container.prepend(this.host);
|
805
|
-
this.subscription.add(this.onRectsChange.subscribe(rects => {
|
806
|
-
for (const rect of rects) {
|
807
|
-
this.context.fillStyle = rect.color;
|
808
|
-
this.context.beginPath();
|
809
|
-
this.context.rect(rect.left, rect.top, rect.width, rect.height);
|
810
|
-
this.context.fill();
|
811
|
-
this.context.closePath();
|
812
|
-
}
|
813
|
-
}), fromEvent(window, 'resize').subscribe(() => {
|
814
|
-
this.canvas.style.height = document.documentElement.clientHeight + 'px';
|
815
|
-
this.refresh();
|
816
|
-
}), this.scheduler.onDocChanged.subscribe(() => {
|
817
|
-
this.refresh();
|
818
|
-
}));
|
819
|
-
}
|
820
|
-
/**
|
821
|
-
* 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
|
822
|
-
*/
|
823
|
-
refresh() {
|
824
|
-
this.draw(this.currentSelection);
|
825
|
-
}
|
826
|
-
destroy() {
|
827
|
-
this.subscription.unsubscribe();
|
828
|
-
}
|
829
|
-
/**
|
830
|
-
* 根据远程用户光标位置,绘制协作光标
|
831
|
-
* @param paths
|
832
|
-
*/
|
833
|
-
draw(paths) {
|
834
|
-
this.currentSelection = paths;
|
835
|
-
const containerRect = this.container.getBoundingClientRect();
|
836
|
-
this.canvas.style.top = containerRect.top * -1 + 'px';
|
837
|
-
this.canvas.width = this.canvas.offsetWidth;
|
838
|
-
this.canvas.height = this.canvas.offsetHeight;
|
839
|
-
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
840
|
-
const users = [];
|
841
|
-
paths.filter(i => {
|
842
|
-
return i.paths.anchor.length && i.paths.focus.length;
|
843
|
-
}).forEach(item => {
|
844
|
-
const anchorPaths = [...item.paths.anchor];
|
845
|
-
const focusPaths = [...item.paths.focus];
|
846
|
-
const anchorOffset = anchorPaths.pop();
|
847
|
-
const anchorSlot = this.selection.findSlotByPaths(anchorPaths);
|
848
|
-
const focusOffset = focusPaths.pop();
|
849
|
-
const focusSlot = this.selection.findSlotByPaths(focusPaths);
|
850
|
-
if (!anchorSlot || !focusSlot) {
|
851
|
-
return;
|
852
|
-
}
|
853
|
-
const { focus, anchor } = this.nativeSelection.getPositionByRange({
|
854
|
-
focusOffset,
|
855
|
-
anchorOffset,
|
856
|
-
focusSlot,
|
857
|
-
anchorSlot
|
858
|
-
});
|
859
|
-
if (!focus || !anchor) {
|
860
|
-
return;
|
861
|
-
}
|
862
|
-
const nativeRange = document.createRange();
|
863
|
-
nativeRange.setStart(anchor.node, anchor.offset);
|
864
|
-
nativeRange.setEnd(focus.node, focus.offset);
|
865
|
-
if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
|
866
|
-
nativeRange.setStart(focus.node, focus.offset);
|
867
|
-
nativeRange.setEnd(anchor.node, anchor.offset);
|
868
|
-
}
|
869
|
-
let rects = false;
|
870
|
-
if (this.awarenessDelegate) {
|
871
|
-
rects = this.awarenessDelegate.getRects({
|
872
|
-
focusOffset,
|
873
|
-
anchorOffset,
|
874
|
-
focusSlot,
|
875
|
-
anchorSlot
|
876
|
-
}, nativeRange);
|
877
|
-
}
|
878
|
-
if (!rects) {
|
879
|
-
rects = nativeRange.getClientRects();
|
880
|
-
}
|
881
|
-
const selectionRects = [];
|
882
|
-
for (let i = rects.length - 1; i >= 0; i--) {
|
883
|
-
const rect = rects[i];
|
884
|
-
selectionRects.push({
|
885
|
-
id: item.id,
|
886
|
-
color: item.color,
|
887
|
-
username: item.username,
|
888
|
-
left: rect.left - containerRect.left,
|
889
|
-
top: rect.top,
|
890
|
-
width: rect.width,
|
891
|
-
height: rect.height,
|
892
|
-
});
|
893
|
-
}
|
894
|
-
this.onRectsChange.next(selectionRects);
|
895
|
-
const cursorRange = nativeRange.cloneRange();
|
896
|
-
cursorRange.setStart(focus.node, focus.offset);
|
897
|
-
cursorRange.collapse(true);
|
898
|
-
const cursorRect = getLayoutRectByRange(cursorRange);
|
899
|
-
const rect = {
|
900
|
-
id: item.id,
|
901
|
-
username: item.username,
|
902
|
-
color: item.color,
|
903
|
-
left: cursorRect.left - containerRect.left,
|
904
|
-
top: cursorRect.top - containerRect.top,
|
905
|
-
width: 1,
|
906
|
-
height: cursorRect.height
|
907
|
-
};
|
908
|
-
if (rect.left < 0 || rect.top < 0 || rect.left > containerRect.width) {
|
909
|
-
return;
|
910
|
-
}
|
911
|
-
users.push(rect);
|
912
|
-
});
|
913
|
-
this.drawUserCursor(users);
|
914
|
-
}
|
915
|
-
drawUserCursor(rects) {
|
916
|
-
for (let i = 0; i < rects.length; i++) {
|
917
|
-
const rect = rects[i];
|
918
|
-
const { cursor, userTip, anchor } = this.getUserCursor(i);
|
919
|
-
Object.assign(cursor.style, {
|
920
|
-
left: rect.left + 'px',
|
921
|
-
top: rect.top + 'px',
|
922
|
-
width: rect.width + 'px',
|
923
|
-
height: rect.height + 'px',
|
924
|
-
background: rect.color,
|
925
|
-
display: 'block'
|
926
|
-
});
|
927
|
-
anchor.style.background = rect.color;
|
928
|
-
userTip.innerText = rect.username;
|
929
|
-
userTip.style.background = rect.color;
|
930
|
-
}
|
931
|
-
for (let i = rects.length; i < this.tooltips.children.length; i++) {
|
932
|
-
this.tooltips.removeChild(this.tooltips.children[i]);
|
933
|
-
}
|
934
|
-
}
|
935
|
-
getUserCursor(index) {
|
936
|
-
let child = this.tooltips.children[index];
|
937
|
-
if (child) {
|
938
|
-
const anchor = child.children[0];
|
939
|
-
return {
|
940
|
-
cursor: child,
|
941
|
-
anchor,
|
942
|
-
userTip: anchor.children[0]
|
943
|
-
};
|
944
|
-
}
|
945
|
-
const userTip = createElement('span', {
|
946
|
-
styles: {
|
947
|
-
position: 'absolute',
|
948
|
-
left: '50%',
|
949
|
-
transform: 'translateX(-50%)',
|
950
|
-
marginBottom: '2px',
|
951
|
-
bottom: '100%',
|
952
|
-
whiteSpace: 'nowrap',
|
953
|
-
color: '#fff',
|
954
|
-
boxShadow: '0 1px 2px rgba(0,0,0,.1)',
|
955
|
-
opacity: 0.8,
|
956
|
-
borderRadius: '3px',
|
957
|
-
padding: '3px 5px',
|
958
|
-
pointerEvents: 'none',
|
959
|
-
}
|
960
|
-
});
|
961
|
-
const anchor = createElement('span', {
|
962
|
-
styles: {
|
963
|
-
position: 'absolute',
|
964
|
-
top: '-2px',
|
965
|
-
left: '-2px',
|
966
|
-
width: '5px',
|
967
|
-
height: '5px',
|
968
|
-
borderRadius: '50%',
|
969
|
-
pointerEvents: 'auto',
|
970
|
-
pointer: 'cursor',
|
971
|
-
},
|
972
|
-
children: [userTip]
|
973
|
-
});
|
974
|
-
child = createElement('span', {
|
975
|
-
styles: {
|
976
|
-
position: 'absolute',
|
977
|
-
},
|
978
|
-
children: [
|
979
|
-
anchor
|
980
|
-
]
|
981
|
-
});
|
982
|
-
this.tooltips.append(child);
|
983
|
-
return {
|
984
|
-
cursor: child,
|
985
|
-
anchor,
|
986
|
-
userTip
|
987
|
-
};
|
988
|
-
}
|
989
|
-
};
|
990
|
-
CollaborateCursor = __decorate([
|
991
|
-
Injectable(),
|
992
|
-
__param(4, Optional()),
|
993
|
-
__metadata("design:paramtypes", [Injector,
|
994
|
-
SelectionBridge,
|
995
|
-
Scheduler,
|
996
|
-
Selection,
|
997
|
-
CollaborateSelectionAwarenessDelegate])
|
998
|
-
], CollaborateCursor);
|
999
|
-
|
1000
|
-
var DomRenderer_1;
|
1001
|
-
/**
|
1002
|
-
* Textbus PC 端浏览器渲染能力实现
|
1003
|
-
*/
|
1004
|
-
let DomRenderer = DomRenderer_1 = class DomRenderer {
|
1005
|
-
constructor() {
|
1006
|
-
this.isSVG = new RegExp(`^(${[
|
1007
|
-
// 'a',
|
1008
|
-
'animate',
|
1009
|
-
'animateMotion',
|
1010
|
-
'animateTransform',
|
1011
|
-
'circle',
|
1012
|
-
'clipPath',
|
1013
|
-
'defs',
|
1014
|
-
'desc',
|
1015
|
-
'ellipse',
|
1016
|
-
'feBlend',
|
1017
|
-
'feColorMatrix',
|
1018
|
-
'feComponentTransfer',
|
1019
|
-
'feComposite',
|
1020
|
-
'feConvolveMatrix',
|
1021
|
-
'feDiffuseLighting',
|
1022
|
-
'feDisplacementMap',
|
1023
|
-
'feDistantLight',
|
1024
|
-
'feDropShadow',
|
1025
|
-
'feFlood',
|
1026
|
-
'feFuncA',
|
1027
|
-
'feFuncB',
|
1028
|
-
'feFuncG',
|
1029
|
-
'feFuncR',
|
1030
|
-
'feGaussianBlur',
|
1031
|
-
'feImage',
|
1032
|
-
'feMerge',
|
1033
|
-
'feMergeNode',
|
1034
|
-
'feMorphology',
|
1035
|
-
'feOffset',
|
1036
|
-
'fePointLight',
|
1037
|
-
'feSpecularLighting',
|
1038
|
-
'feSpotLight',
|
1039
|
-
'feTile',
|
1040
|
-
'feTurbulence',
|
1041
|
-
'filter',
|
1042
|
-
'foreignObject',
|
1043
|
-
'g',
|
1044
|
-
'image',
|
1045
|
-
'line',
|
1046
|
-
'linearGradient',
|
1047
|
-
'marker',
|
1048
|
-
'mask',
|
1049
|
-
'metadata',
|
1050
|
-
'mpath',
|
1051
|
-
'path',
|
1052
|
-
'pattern',
|
1053
|
-
'polygon',
|
1054
|
-
'polyline',
|
1055
|
-
'radialGradient',
|
1056
|
-
'rect',
|
1057
|
-
// 'script',
|
1058
|
-
'set',
|
1059
|
-
'stop',
|
1060
|
-
// 'style',
|
1061
|
-
'svg',
|
1062
|
-
'switch',
|
1063
|
-
'symbol',
|
1064
|
-
'text',
|
1065
|
-
'textPath',
|
1066
|
-
'title',
|
1067
|
-
'tspan',
|
1068
|
-
'use',
|
1069
|
-
'view'
|
1070
|
-
].join('|')})$`, 'i');
|
1071
|
-
this.xlinkNameSpace = 'http://www.w3.org/1999/xlink';
|
1072
|
-
this.possibleXlinkNames = {
|
1073
|
-
xlinkActuate: 'xlink:actuate',
|
1074
|
-
xlinkactuate: 'xlink:actuate',
|
1075
|
-
'xlink:actuate': 'xlink:actuate',
|
1076
|
-
xlinkArcrole: 'xlink:arcrole',
|
1077
|
-
xlinkarcrole: 'xlink:arcrole',
|
1078
|
-
'xlink:arcrole': 'xlink:arcrole',
|
1079
|
-
xlinkHref: 'xlink:href',
|
1080
|
-
xlinkhref: 'xlink:href',
|
1081
|
-
'xlink:href': 'xlink:href',
|
1082
|
-
xlinkRole: 'xlink:role',
|
1083
|
-
xlinkrole: 'xlink:role',
|
1084
|
-
'xlink:role': 'xlink:role',
|
1085
|
-
xlinkShow: 'xlink:show',
|
1086
|
-
xlinkshow: 'xlink:show',
|
1087
|
-
'xlink:show': 'xlink:show',
|
1088
|
-
xlinkTitle: 'xlink:title',
|
1089
|
-
xlinktitle: 'xlink:title',
|
1090
|
-
'xlink:title': 'xlink:title',
|
1091
|
-
xlinkType: 'xlink:type',
|
1092
|
-
xlinktype: 'xlink:type',
|
1093
|
-
'xlink:type': 'xlink:type'
|
1094
|
-
};
|
1095
|
-
this.booleanProps = {
|
1096
|
-
input: ['disabled', 'readonly'],
|
1097
|
-
select: ['disabled', 'readonly'],
|
1098
|
-
option: ['disabled', 'selected'],
|
1099
|
-
button: ['disabled'],
|
1100
|
-
video: ['controls', 'autoplay', 'loop', 'muted'],
|
1101
|
-
audio: ['controls', 'autoplay', 'loop', 'muted'],
|
1102
|
-
};
|
1103
|
-
this.valueProps = {
|
1104
|
-
input: ['value'],
|
1105
|
-
option: ['value'],
|
1106
|
-
video: ['src'],
|
1107
|
-
audio: ['src']
|
1108
|
-
};
|
1109
|
-
}
|
1110
|
-
listen(node, type, callback) {
|
1111
|
-
node.addEventListener(type, callback);
|
1112
|
-
}
|
1113
|
-
unListen(node, type, callback) {
|
1114
|
-
node.removeEventListener(type, callback);
|
1115
|
-
}
|
1116
|
-
createTextNode(textContent) {
|
1117
|
-
return document.createTextNode(DomRenderer_1.replaceEmpty(textContent));
|
1118
|
-
}
|
1119
|
-
createElement(name) {
|
1120
|
-
if (this.isSVG.test(name)) {
|
1121
|
-
return document.createElementNS('http://www.w3.org/2000/svg', name);
|
1122
|
-
}
|
1123
|
-
return document.createElement(name);
|
1124
|
-
}
|
1125
|
-
appendChild(parent, newChild) {
|
1126
|
-
parent.appendChild(newChild);
|
1127
|
-
}
|
1128
|
-
remove(node) {
|
1129
|
-
var _a;
|
1130
|
-
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
|
1131
|
-
}
|
1132
|
-
insertBefore(newNode, ref) {
|
1133
|
-
ref.parentNode.insertBefore(newNode, ref);
|
1134
|
-
}
|
1135
|
-
getChildByIndex(parent, index) {
|
1136
|
-
return parent.childNodes[index] || null;
|
1137
|
-
}
|
1138
|
-
addClass(target, name) {
|
1139
|
-
target.classList.add(name);
|
1140
|
-
}
|
1141
|
-
removeClass(target, name) {
|
1142
|
-
target.classList.remove(name);
|
1143
|
-
}
|
1144
|
-
setStyle(target, key, value) {
|
1145
|
-
target.style[key] = value !== null && value !== void 0 ? value : '';
|
1146
|
-
}
|
1147
|
-
syncTextContent(target, content) {
|
1148
|
-
const c = DomRenderer_1.replaceEmpty(content);
|
1149
|
-
if (target.textContent !== c) {
|
1150
|
-
target.textContent = c;
|
1151
|
-
}
|
1152
|
-
}
|
1153
|
-
removeStyle(target, key) {
|
1154
|
-
target.style[key] = '';
|
1155
|
-
}
|
1156
|
-
setAttribute(target, key, value) {
|
1157
|
-
if (this.possibleXlinkNames[key]) {
|
1158
|
-
this.setXlinkAttribute(target, this.possibleXlinkNames[key], value);
|
1159
|
-
return;
|
1160
|
-
}
|
1161
|
-
target.setAttribute(key, value);
|
1162
|
-
const tag = target.tagName.toLowerCase();
|
1163
|
-
const booleanTagNames = this.booleanProps[tag];
|
1164
|
-
const valueTagNames = this.valueProps[tag];
|
1165
|
-
if (booleanTagNames && booleanTagNames.includes(key)) {
|
1166
|
-
target[key] = Boolean(value);
|
1167
|
-
}
|
1168
|
-
if (valueTagNames && valueTagNames.includes(key)) {
|
1169
|
-
target[key] = value;
|
1170
|
-
}
|
1171
|
-
}
|
1172
|
-
removeAttribute(target, key) {
|
1173
|
-
if (this.possibleXlinkNames[key]) {
|
1174
|
-
this.removeXlinkAttribute(target, this.possibleXlinkNames[key]);
|
1175
|
-
}
|
1176
|
-
target.removeAttribute(key);
|
1177
|
-
const tag = target.tagName.toLowerCase();
|
1178
|
-
const booleanTagNames = this.booleanProps[tag];
|
1179
|
-
const valueTagNames = this.valueProps[tag];
|
1180
|
-
if (booleanTagNames && booleanTagNames.includes(key)) {
|
1181
|
-
target[key] = false;
|
1182
|
-
}
|
1183
|
-
if (valueTagNames && valueTagNames.includes(key)) {
|
1184
|
-
target[key] = '';
|
1185
|
-
}
|
1186
|
-
}
|
1187
|
-
setXlinkAttribute(target, key, value) {
|
1188
|
-
target.setAttributeNS(this.xlinkNameSpace, key, value);
|
1189
|
-
}
|
1190
|
-
removeXlinkAttribute(target, key) {
|
1191
|
-
target.removeAttributeNS(this.xlinkNameSpace, key);
|
1192
|
-
}
|
1193
|
-
replace(newChild, oldChild) {
|
1194
|
-
oldChild.parentNode.replaceChild(newChild, oldChild);
|
1195
|
-
}
|
1196
|
-
copy() {
|
1197
|
-
document.execCommand('copy');
|
1198
|
-
}
|
1199
|
-
static replaceEmpty(s) {
|
1200
|
-
const empty = '\u00a0';
|
1201
|
-
return s.replace(/\s\s+/g, str => {
|
1202
|
-
return ' ' + Array.from({
|
1203
|
-
length: str.length - 1
|
1204
|
-
}).fill(empty).join('');
|
1205
|
-
}).replace(/^\s|\s$/g, empty);
|
1206
|
-
}
|
1207
|
-
};
|
1208
|
-
DomRenderer = DomRenderer_1 = __decorate([
|
1209
|
-
Injectable()
|
1210
|
-
], DomRenderer);
|
1211
|
-
|
1212
|
-
var Parser_1;
|
1213
|
-
/**
|
1214
|
-
* 用于解析 HTML,并把 HTML 内容转换为 Textbus 可以支持的组件或插槽数据
|
1215
|
-
*/
|
1216
|
-
let Parser = Parser_1 = class Parser {
|
1217
|
-
static parseHTML(html) {
|
1218
|
-
return new DOMParser().parseFromString(html, 'text/html').body;
|
1219
|
-
}
|
1220
|
-
constructor(options, injector) {
|
1221
|
-
var _a;
|
1222
|
-
this.options = options;
|
1223
|
-
this.injector = injector;
|
1224
|
-
const componentLoaders = [
|
1225
|
-
...(options.componentLoaders || [])
|
1226
|
-
];
|
1227
|
-
const formatLoaders = [
|
1228
|
-
...(options.formatLoaders || [])
|
1229
|
-
];
|
1230
|
-
const attributeLoaders = [
|
1231
|
-
...(options.attributeLoaders || [])
|
1232
|
-
];
|
1233
|
-
(_a = options.imports) === null || _a === void 0 ? void 0 : _a.forEach(i => {
|
1234
|
-
componentLoaders.push(...(i.componentLoaders || []));
|
1235
|
-
formatLoaders.push(...(i.formatLoaders || []));
|
1236
|
-
});
|
1237
|
-
this.componentLoaders = componentLoaders;
|
1238
|
-
this.formatLoaders = formatLoaders;
|
1239
|
-
this.attributeLoaders = attributeLoaders;
|
1240
|
-
}
|
1241
|
-
/**
|
1242
|
-
* 使用指定的组件加载器解析一段 HTML 字符串
|
1243
|
-
* @param html
|
1244
|
-
* @param rootComponentLoader
|
1245
|
-
*/
|
1246
|
-
parseDoc(html, rootComponentLoader) {
|
1247
|
-
const element = Parser_1.parseHTML(html);
|
1248
|
-
return rootComponentLoader.read(element, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
|
1249
|
-
return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
|
1250
|
-
});
|
1251
|
-
}
|
1252
|
-
/**
|
1253
|
-
* 将一段 HTML 解析到指定插槽
|
1254
|
-
* @param html
|
1255
|
-
* @param rootSlot
|
1256
|
-
*/
|
1257
|
-
parse(html, rootSlot) {
|
1258
|
-
const element = Parser_1.parseHTML(html);
|
1259
|
-
return this.readFormats(element, rootSlot);
|
1260
|
-
}
|
1261
|
-
readComponent(el, slot) {
|
1262
|
-
if (el.nodeType === Node.ELEMENT_NODE) {
|
1263
|
-
if (el.tagName === 'BR') {
|
1264
|
-
slot.insert('\n');
|
1265
|
-
return;
|
1266
|
-
}
|
1267
|
-
for (const t of this.componentLoaders) {
|
1268
|
-
if (t.match(el)) {
|
1269
|
-
const result = t.read(el, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
|
1270
|
-
return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
|
1271
|
-
});
|
1272
|
-
if (!result) {
|
1273
|
-
return;
|
1274
|
-
}
|
1275
|
-
if (result instanceof Slot) {
|
1276
|
-
result.toDelta().forEach(i => slot.insert(i.insert, i.formats));
|
1277
|
-
return;
|
1278
|
-
}
|
1279
|
-
slot.insert(result);
|
1280
|
-
return;
|
1281
|
-
}
|
1282
|
-
}
|
1283
|
-
this.readFormats(el, slot);
|
1284
|
-
}
|
1285
|
-
else if (el.nodeType === Node.TEXT_NODE) {
|
1286
|
-
this.readText(slot, el);
|
1287
|
-
}
|
1288
|
-
}
|
1289
|
-
readText(slot, el) {
|
1290
|
-
const textContent = el.textContent;
|
1291
|
-
if (/^\s*[\r\n\u200b]+\s*$/.test(textContent)) {
|
1292
|
-
return;
|
1293
|
-
}
|
1294
|
-
slot.insert(textContent);
|
1295
|
-
}
|
1296
|
-
readFormats(el, slot) {
|
1297
|
-
const formats = this.formatLoaders.filter(f => {
|
1298
|
-
return f.match(el);
|
1299
|
-
}).map(f => {
|
1300
|
-
return f.read(el);
|
1301
|
-
});
|
1302
|
-
const startIndex = slot.index;
|
1303
|
-
let startNode = el.firstChild;
|
1304
|
-
while (startNode) {
|
1305
|
-
this.readComponent(startNode, slot);
|
1306
|
-
startNode = startNode.nextSibling;
|
1307
|
-
}
|
1308
|
-
const endIndex = slot.index;
|
1309
|
-
this.applyFormats(slot, formats.map(i => {
|
1310
|
-
return {
|
1311
|
-
formatter: i.formatter,
|
1312
|
-
value: i.value,
|
1313
|
-
startIndex,
|
1314
|
-
endIndex
|
1315
|
-
};
|
1316
|
-
}));
|
1317
|
-
slot.retain(endIndex);
|
1318
|
-
return slot;
|
1319
|
-
}
|
1320
|
-
readSlot(childSlot, slotRootElement, slotContentElement) {
|
1321
|
-
if (slotRootElement.nodeType === Node.ELEMENT_NODE) {
|
1322
|
-
this.attributeLoaders.filter(a => {
|
1323
|
-
return a.match(slotRootElement);
|
1324
|
-
}).forEach(a => {
|
1325
|
-
const r = a.read(slotRootElement);
|
1326
|
-
childSlot.setAttribute(r.attribute, r.value);
|
1327
|
-
});
|
1328
|
-
}
|
1329
|
-
if (slotContentElement.nodeType === Node.ELEMENT_NODE) {
|
1330
|
-
this.readFormats(slotContentElement, childSlot);
|
1331
|
-
}
|
1332
|
-
else {
|
1333
|
-
this.readText(childSlot, slotContentElement);
|
1334
|
-
}
|
1335
|
-
return childSlot;
|
1336
|
-
}
|
1337
|
-
applyFormats(slot, formatItems) {
|
1338
|
-
slot.background(() => {
|
1339
|
-
formatItems.forEach(i => {
|
1340
|
-
slot.retain(i.startIndex);
|
1341
|
-
slot.retain(i.endIndex - i.startIndex, i.formatter, i.value);
|
1342
|
-
});
|
1343
|
-
});
|
1344
|
-
}
|
1345
|
-
};
|
1346
|
-
Parser = Parser_1 = __decorate([
|
1347
|
-
Injectable(),
|
1348
|
-
__param(0, Inject(EDITOR_OPTIONS)),
|
1349
|
-
__metadata("design:paramtypes", [Object, Injector])
|
1350
|
-
], Parser);
|
1351
|
-
|
1352
|
-
const iframeHTML = `
|
1353
|
-
<!DOCTYPE html>
|
1354
|
-
<html>
|
1355
|
-
<head>
|
1356
|
-
<meta charset="UTF-8">
|
1357
|
-
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
1358
|
-
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
1359
|
-
<title>Textbus</title>
|
1360
|
-
<style>
|
1361
|
-
html {position: fixed; left:0; overflow: hidden}
|
1362
|
-
html, body{height: 100%;width:100%}
|
1363
|
-
body{margin:0; overflow: hidden}
|
1364
|
-
textarea{width: 2000px;height: 100%;opacity: 0; padding: 0; outline: none; border: none; position: absolute; left:0; top:0;}
|
1365
|
-
</style>
|
1366
|
-
</head>
|
1367
|
-
<body>
|
1368
|
-
</body>
|
1369
|
-
</html>
|
1370
|
-
`;
|
1371
|
-
class ExperimentalCaret {
|
1372
|
-
get rect() {
|
1373
|
-
return this.caret.getBoundingClientRect();
|
1374
|
-
}
|
1375
|
-
set display(v) {
|
1376
|
-
this._display = v;
|
1377
|
-
this.caret.style.visibility = v ? 'visible' : 'hidden';
|
1378
|
-
}
|
1379
|
-
get display() {
|
1380
|
-
return this._display;
|
1381
|
-
}
|
1382
|
-
constructor(scheduler, editorMask) {
|
1001
|
+
const iframeHTML = `
|
1002
|
+
<!DOCTYPE html>
|
1003
|
+
<html>
|
1004
|
+
<head>
|
1005
|
+
<meta charset="UTF-8">
|
1006
|
+
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
1007
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
1008
|
+
<title>Textbus</title>
|
1009
|
+
<style>
|
1010
|
+
html {position: fixed; left:0; overflow: hidden}
|
1011
|
+
html, body{height: 100%;width:100%}
|
1012
|
+
body{margin:0; overflow: hidden}
|
1013
|
+
textarea{width: 2000px;height: 100%;opacity: 0; padding: 0; outline: none; border: none; position: absolute; left:0; top:0;}
|
1014
|
+
</style>
|
1015
|
+
</head>
|
1016
|
+
<body>
|
1017
|
+
</body>
|
1018
|
+
</html>
|
1019
|
+
`;
|
1020
|
+
class ExperimentalCaret {
|
1021
|
+
get rect() {
|
1022
|
+
return this.caret.getBoundingClientRect();
|
1023
|
+
}
|
1024
|
+
set display(v) {
|
1025
|
+
this._display = v;
|
1026
|
+
this.caret.style.visibility = v ? 'visible' : 'hidden';
|
1027
|
+
}
|
1028
|
+
get display() {
|
1029
|
+
return this._display;
|
1030
|
+
}
|
1031
|
+
constructor(scheduler, editorMask) {
|
1383
1032
|
this.scheduler = scheduler;
|
1384
1033
|
this.editorMask = editorMask;
|
1385
1034
|
this.compositionState = null;
|
@@ -1857,10 +1506,21 @@ let MagicInput = class MagicInput extends Input {
|
|
1857
1506
|
textarea.value = '';
|
1858
1507
|
return ev.data;
|
1859
1508
|
}))).subscribe(text => {
|
1860
|
-
var _a;
|
1861
1509
|
this.composition = false;
|
1862
1510
|
this.caret.compositionState = this.compositionState = null;
|
1863
|
-
|
1511
|
+
const compositionElement = this.caret.compositionElement;
|
1512
|
+
let nextSibling = compositionElement.nextSibling;
|
1513
|
+
while (nextSibling) {
|
1514
|
+
if (!nextSibling.textContent) {
|
1515
|
+
const next = nextSibling.nextSibling;
|
1516
|
+
nextSibling.remove();
|
1517
|
+
nextSibling = next;
|
1518
|
+
continue;
|
1519
|
+
}
|
1520
|
+
nextSibling.remove();
|
1521
|
+
break;
|
1522
|
+
}
|
1523
|
+
compositionElement.remove();
|
1864
1524
|
if (text) {
|
1865
1525
|
this.commander.write(text);
|
1866
1526
|
}
|
@@ -1874,32 +1534,293 @@ let MagicInput = class MagicInput extends Input {
|
|
1874
1534
|
isCompositionEnd = false;
|
1875
1535
|
}));
|
1876
1536
|
}
|
1877
|
-
createEditableFrame() {
|
1878
|
-
return createElement('iframe', {
|
1879
|
-
attrs: {
|
1880
|
-
scrolling: 'no'
|
1881
|
-
},
|
1537
|
+
createEditableFrame() {
|
1538
|
+
return createElement('iframe', {
|
1539
|
+
attrs: {
|
1540
|
+
scrolling: 'no'
|
1541
|
+
},
|
1542
|
+
styles: {
|
1543
|
+
border: 'none',
|
1544
|
+
width: '100%',
|
1545
|
+
display: 'block',
|
1546
|
+
height: '100%',
|
1547
|
+
position: 'relative',
|
1548
|
+
top: this.isWindows ? '3px' : '0'
|
1549
|
+
}
|
1550
|
+
});
|
1551
|
+
}
|
1552
|
+
};
|
1553
|
+
MagicInput = __decorate([
|
1554
|
+
Injectable(),
|
1555
|
+
__metadata("design:paramtypes", [Parser,
|
1556
|
+
Keyboard,
|
1557
|
+
Commander,
|
1558
|
+
Selection,
|
1559
|
+
Controller,
|
1560
|
+
Scheduler,
|
1561
|
+
Injector])
|
1562
|
+
], MagicInput);
|
1563
|
+
|
1564
|
+
/**
|
1565
|
+
* 远程光标绘制范围计算代理类,可用于定制特定场景下的远程选区绘制,如表格有选区,不会遵守常见的文档流形式
|
1566
|
+
*/
|
1567
|
+
class CollaborateSelectionAwarenessDelegate {
|
1568
|
+
}
|
1569
|
+
/**
|
1570
|
+
* 协作光标绘制类
|
1571
|
+
*/
|
1572
|
+
let CollaborateCursor = class CollaborateCursor {
|
1573
|
+
constructor(injector, nativeSelection, scheduler, selection, awarenessDelegate) {
|
1574
|
+
this.nativeSelection = nativeSelection;
|
1575
|
+
this.scheduler = scheduler;
|
1576
|
+
this.selection = selection;
|
1577
|
+
this.awarenessDelegate = awarenessDelegate;
|
1578
|
+
this.host = createElement('div', {
|
1579
|
+
styles: {
|
1580
|
+
position: 'absolute',
|
1581
|
+
left: 0,
|
1582
|
+
top: 0,
|
1583
|
+
width: '100%',
|
1584
|
+
height: '100%',
|
1585
|
+
pointerEvents: 'none',
|
1586
|
+
zIndex: 1
|
1587
|
+
}
|
1588
|
+
});
|
1589
|
+
this.canvasContainer = createElement('div', {
|
1590
|
+
styles: {
|
1591
|
+
position: 'absolute',
|
1592
|
+
left: 0,
|
1593
|
+
top: 0,
|
1594
|
+
width: '100%',
|
1595
|
+
height: '100%',
|
1596
|
+
overflow: 'hidden'
|
1597
|
+
}
|
1598
|
+
});
|
1599
|
+
this.canvas = createElement('canvas', {
|
1600
|
+
styles: {
|
1601
|
+
position: 'absolute',
|
1602
|
+
opacity: 0.5,
|
1603
|
+
left: 0,
|
1604
|
+
top: 0,
|
1605
|
+
width: '100%',
|
1606
|
+
height: document.documentElement.clientHeight + 'px',
|
1607
|
+
pointerEvents: 'none',
|
1608
|
+
}
|
1609
|
+
});
|
1610
|
+
this.context = this.canvas.getContext('2d');
|
1611
|
+
this.tooltips = createElement('div', {
|
1612
|
+
styles: {
|
1613
|
+
position: 'absolute',
|
1614
|
+
left: 0,
|
1615
|
+
top: 0,
|
1616
|
+
width: '100%',
|
1617
|
+
height: '100%',
|
1618
|
+
pointerEvents: 'none',
|
1619
|
+
fontSize: '12px',
|
1620
|
+
zIndex: 10
|
1621
|
+
}
|
1622
|
+
});
|
1623
|
+
this.onRectsChange = new Subject();
|
1624
|
+
this.subscription = new Subscription();
|
1625
|
+
this.currentSelection = [];
|
1626
|
+
this.container = injector.get(VIEW_CONTAINER);
|
1627
|
+
this.canvasContainer.append(this.canvas);
|
1628
|
+
this.host.append(this.canvasContainer, this.tooltips);
|
1629
|
+
this.container.prepend(this.host);
|
1630
|
+
this.subscription.add(this.onRectsChange.subscribe(rects => {
|
1631
|
+
for (const rect of rects) {
|
1632
|
+
this.context.fillStyle = rect.color;
|
1633
|
+
this.context.beginPath();
|
1634
|
+
this.context.rect(rect.left, rect.top, rect.width, rect.height);
|
1635
|
+
this.context.fill();
|
1636
|
+
this.context.closePath();
|
1637
|
+
}
|
1638
|
+
}), fromEvent(window, 'resize').subscribe(() => {
|
1639
|
+
this.canvas.style.height = document.documentElement.clientHeight + 'px';
|
1640
|
+
this.refresh();
|
1641
|
+
}), this.scheduler.onDocChanged.subscribe(() => {
|
1642
|
+
this.refresh();
|
1643
|
+
}));
|
1644
|
+
}
|
1645
|
+
/**
|
1646
|
+
* 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
|
1647
|
+
*/
|
1648
|
+
refresh() {
|
1649
|
+
this.draw(this.currentSelection);
|
1650
|
+
}
|
1651
|
+
destroy() {
|
1652
|
+
this.subscription.unsubscribe();
|
1653
|
+
}
|
1654
|
+
/**
|
1655
|
+
* 根据远程用户光标位置,绘制协作光标
|
1656
|
+
* @param paths
|
1657
|
+
*/
|
1658
|
+
draw(paths) {
|
1659
|
+
this.currentSelection = paths;
|
1660
|
+
const containerRect = this.container.getBoundingClientRect();
|
1661
|
+
this.canvas.style.top = containerRect.top * -1 + 'px';
|
1662
|
+
this.canvas.width = this.canvas.offsetWidth;
|
1663
|
+
this.canvas.height = this.canvas.offsetHeight;
|
1664
|
+
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
1665
|
+
const users = [];
|
1666
|
+
paths.filter(i => {
|
1667
|
+
return i.paths.anchor.length && i.paths.focus.length;
|
1668
|
+
}).forEach(item => {
|
1669
|
+
const anchorPaths = [...item.paths.anchor];
|
1670
|
+
const focusPaths = [...item.paths.focus];
|
1671
|
+
const anchorOffset = anchorPaths.pop();
|
1672
|
+
const anchorSlot = this.selection.findSlotByPaths(anchorPaths);
|
1673
|
+
const focusOffset = focusPaths.pop();
|
1674
|
+
const focusSlot = this.selection.findSlotByPaths(focusPaths);
|
1675
|
+
if (!anchorSlot || !focusSlot) {
|
1676
|
+
return;
|
1677
|
+
}
|
1678
|
+
const { focus, anchor } = this.nativeSelection.getPositionByRange({
|
1679
|
+
focusOffset,
|
1680
|
+
anchorOffset,
|
1681
|
+
focusSlot,
|
1682
|
+
anchorSlot
|
1683
|
+
});
|
1684
|
+
if (!focus || !anchor) {
|
1685
|
+
return;
|
1686
|
+
}
|
1687
|
+
const nativeRange = document.createRange();
|
1688
|
+
nativeRange.setStart(anchor.node, anchor.offset);
|
1689
|
+
nativeRange.setEnd(focus.node, focus.offset);
|
1690
|
+
if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
|
1691
|
+
nativeRange.setStart(focus.node, focus.offset);
|
1692
|
+
nativeRange.setEnd(anchor.node, anchor.offset);
|
1693
|
+
}
|
1694
|
+
let rects = false;
|
1695
|
+
if (this.awarenessDelegate) {
|
1696
|
+
rects = this.awarenessDelegate.getRects({
|
1697
|
+
focusOffset,
|
1698
|
+
anchorOffset,
|
1699
|
+
focusSlot,
|
1700
|
+
anchorSlot
|
1701
|
+
}, nativeRange);
|
1702
|
+
}
|
1703
|
+
if (!rects) {
|
1704
|
+
rects = nativeRange.getClientRects();
|
1705
|
+
}
|
1706
|
+
const selectionRects = [];
|
1707
|
+
for (let i = rects.length - 1; i >= 0; i--) {
|
1708
|
+
const rect = rects[i];
|
1709
|
+
selectionRects.push({
|
1710
|
+
id: item.id,
|
1711
|
+
color: item.color,
|
1712
|
+
username: item.username,
|
1713
|
+
left: rect.left - containerRect.left,
|
1714
|
+
top: rect.top,
|
1715
|
+
width: rect.width,
|
1716
|
+
height: rect.height,
|
1717
|
+
});
|
1718
|
+
}
|
1719
|
+
this.onRectsChange.next(selectionRects);
|
1720
|
+
const cursorRange = nativeRange.cloneRange();
|
1721
|
+
cursorRange.setStart(focus.node, focus.offset);
|
1722
|
+
cursorRange.collapse(true);
|
1723
|
+
const cursorRect = getLayoutRectByRange(cursorRange);
|
1724
|
+
const rect = {
|
1725
|
+
id: item.id,
|
1726
|
+
username: item.username,
|
1727
|
+
color: item.color,
|
1728
|
+
left: cursorRect.left - containerRect.left,
|
1729
|
+
top: cursorRect.top - containerRect.top,
|
1730
|
+
width: 1,
|
1731
|
+
height: cursorRect.height
|
1732
|
+
};
|
1733
|
+
if (rect.left < 0 || rect.top < 0 || rect.left > containerRect.width) {
|
1734
|
+
return;
|
1735
|
+
}
|
1736
|
+
users.push(rect);
|
1737
|
+
});
|
1738
|
+
this.drawUserCursor(users);
|
1739
|
+
}
|
1740
|
+
drawUserCursor(rects) {
|
1741
|
+
for (let i = 0; i < rects.length; i++) {
|
1742
|
+
const rect = rects[i];
|
1743
|
+
const { cursor, userTip, anchor } = this.getUserCursor(i);
|
1744
|
+
Object.assign(cursor.style, {
|
1745
|
+
left: rect.left + 'px',
|
1746
|
+
top: rect.top + 'px',
|
1747
|
+
width: rect.width + 'px',
|
1748
|
+
height: rect.height + 'px',
|
1749
|
+
background: rect.color,
|
1750
|
+
display: 'block'
|
1751
|
+
});
|
1752
|
+
anchor.style.background = rect.color;
|
1753
|
+
userTip.innerText = rect.username;
|
1754
|
+
userTip.style.background = rect.color;
|
1755
|
+
}
|
1756
|
+
for (let i = rects.length; i < this.tooltips.children.length; i++) {
|
1757
|
+
this.tooltips.removeChild(this.tooltips.children[i]);
|
1758
|
+
}
|
1759
|
+
}
|
1760
|
+
getUserCursor(index) {
|
1761
|
+
let child = this.tooltips.children[index];
|
1762
|
+
if (child) {
|
1763
|
+
const anchor = child.children[0];
|
1764
|
+
return {
|
1765
|
+
cursor: child,
|
1766
|
+
anchor,
|
1767
|
+
userTip: anchor.children[0]
|
1768
|
+
};
|
1769
|
+
}
|
1770
|
+
const userTip = createElement('span', {
|
1882
1771
|
styles: {
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1772
|
+
position: 'absolute',
|
1773
|
+
left: '50%',
|
1774
|
+
transform: 'translateX(-50%)',
|
1775
|
+
marginBottom: '2px',
|
1776
|
+
bottom: '100%',
|
1777
|
+
whiteSpace: 'nowrap',
|
1778
|
+
color: '#fff',
|
1779
|
+
boxShadow: '0 1px 2px rgba(0,0,0,.1)',
|
1780
|
+
opacity: 0.8,
|
1781
|
+
borderRadius: '3px',
|
1782
|
+
padding: '3px 5px',
|
1783
|
+
pointerEvents: 'none',
|
1889
1784
|
}
|
1890
1785
|
});
|
1786
|
+
const anchor = createElement('span', {
|
1787
|
+
styles: {
|
1788
|
+
position: 'absolute',
|
1789
|
+
top: '-2px',
|
1790
|
+
left: '-2px',
|
1791
|
+
width: '5px',
|
1792
|
+
height: '5px',
|
1793
|
+
borderRadius: '50%',
|
1794
|
+
pointerEvents: 'auto',
|
1795
|
+
pointer: 'cursor',
|
1796
|
+
},
|
1797
|
+
children: [userTip]
|
1798
|
+
});
|
1799
|
+
child = createElement('span', {
|
1800
|
+
styles: {
|
1801
|
+
position: 'absolute',
|
1802
|
+
},
|
1803
|
+
children: [
|
1804
|
+
anchor
|
1805
|
+
]
|
1806
|
+
});
|
1807
|
+
this.tooltips.append(child);
|
1808
|
+
return {
|
1809
|
+
cursor: child,
|
1810
|
+
anchor,
|
1811
|
+
userTip
|
1812
|
+
};
|
1891
1813
|
}
|
1892
1814
|
};
|
1893
|
-
|
1815
|
+
CollaborateCursor = __decorate([
|
1894
1816
|
Injectable(),
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
Selection,
|
1899
|
-
Controller,
|
1817
|
+
__param(4, Optional()),
|
1818
|
+
__metadata("design:paramtypes", [Injector,
|
1819
|
+
SelectionBridge,
|
1900
1820
|
Scheduler,
|
1901
|
-
|
1902
|
-
]
|
1821
|
+
Selection,
|
1822
|
+
CollaborateSelectionAwarenessDelegate])
|
1823
|
+
], CollaborateCursor);
|
1903
1824
|
|
1904
1825
|
class NativeCaret {
|
1905
1826
|
set nativeRange(range) {
|
@@ -2015,14 +1936,13 @@ let NativeInput = class NativeInput extends Input {
|
|
2015
1936
|
get disabled() {
|
2016
1937
|
return this._disabled;
|
2017
1938
|
}
|
2018
|
-
constructor(injector, parser, scheduler, selection, keyboard,
|
1939
|
+
constructor(injector, parser, scheduler, selection, keyboard, domAdapter, commander, controller) {
|
2019
1940
|
super();
|
2020
|
-
this.injector = injector;
|
2021
1941
|
this.parser = parser;
|
2022
1942
|
this.scheduler = scheduler;
|
2023
1943
|
this.selection = selection;
|
2024
1944
|
this.keyboard = keyboard;
|
2025
|
-
this.
|
1945
|
+
this.domAdapter = domAdapter;
|
2026
1946
|
this.commander = commander;
|
2027
1947
|
this.controller = controller;
|
2028
1948
|
this.caret = new NativeCaret(this.scheduler);
|
@@ -2250,7 +2170,7 @@ let NativeInput = class NativeInput extends Input {
|
|
2250
2170
|
if (!range) {
|
2251
2171
|
break;
|
2252
2172
|
}
|
2253
|
-
const location = this.
|
2173
|
+
const location = this.domAdapter.getLocationByNativeNode(range.startContainer);
|
2254
2174
|
const startSlot = this.selection.startSlot;
|
2255
2175
|
if (startSlot) {
|
2256
2176
|
this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
|
@@ -2261,7 +2181,7 @@ let NativeInput = class NativeInput extends Input {
|
|
2261
2181
|
case 'insertReplacementText': {
|
2262
2182
|
this.composition = false;
|
2263
2183
|
const range = ev.getTargetRanges()[0];
|
2264
|
-
const location = this.
|
2184
|
+
const location = this.domAdapter.getLocationByNativeNode(range.startContainer);
|
2265
2185
|
const startSlot = this.selection.startSlot;
|
2266
2186
|
this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
|
2267
2187
|
this.commander.delete();
|
@@ -2315,7 +2235,7 @@ let NativeInput = class NativeInput extends Input {
|
|
2315
2235
|
}
|
2316
2236
|
if (ev.inputType === 'insertReplacementText') {
|
2317
2237
|
const range = ev.getTargetRanges()[0];
|
2318
|
-
const location = this.
|
2238
|
+
const location = this.domAdapter.getLocationByNativeNode(range.startContainer);
|
2319
2239
|
const startSlot = this.selection.startSlot;
|
2320
2240
|
this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
|
2321
2241
|
this.commander.delete();
|
@@ -2373,561 +2293,59 @@ NativeInput = __decorate([
|
|
2373
2293
|
Scheduler,
|
2374
2294
|
Selection,
|
2375
2295
|
Keyboard,
|
2376
|
-
|
2296
|
+
DomAdapter,
|
2377
2297
|
Commander,
|
2378
2298
|
Controller])
|
2379
2299
|
], NativeInput);
|
2380
2300
|
|
2381
|
-
|
2382
|
-
|
2383
|
-
|
2384
|
-
|
2385
|
-
|
2386
|
-
|
2387
|
-
|
2388
|
-
|
2389
|
-
|
2390
|
-
|
2391
|
-
* @param vDom 虚拟 DOM 节点
|
2392
|
-
*/
|
2393
|
-
transform(vDom) {
|
2394
|
-
return vDom.children.map(child => {
|
2395
|
-
return this.vDomToHTMLString(child);
|
2396
|
-
}).join('');
|
2397
|
-
}
|
2398
|
-
vDomToHTMLString(vDom) {
|
2399
|
-
const xssFilter = OutputTranslator_1.simpleXSSFilter;
|
2400
|
-
if (vDom instanceof VTextNode) {
|
2401
|
-
return this.replaceEmpty(xssFilter.text(vDom.textContent), ' ');
|
2402
|
-
}
|
2403
|
-
const styles = Array.from(vDom.styles.keys()).filter(key => {
|
2404
|
-
const v = vDom.styles.get(key);
|
2405
|
-
return !(v === undefined || v === null || v === '');
|
2406
|
-
}).map(key => {
|
2407
|
-
const k = key.replace(/(?=[A-Z])/g, '-').toLowerCase();
|
2408
|
-
return xssFilter.attrValue(`${k}:${vDom.styles.get(key)}`);
|
2409
|
-
}).join(';');
|
2410
|
-
const attrs = Array.from(vDom.attrs.keys()).filter(key => key !== 'ref' && vDom.attrs.get(key) !== false).map(k => {
|
2411
|
-
const key = xssFilter.attrName(k);
|
2412
|
-
const value = vDom.attrs.get(k);
|
2413
|
-
return (value === true ? `${key}` : `${key}="${xssFilter.attrValue(`${value}`)}"`);
|
2414
|
-
});
|
2415
|
-
if (styles) {
|
2416
|
-
attrs.push(`style="${styles}"`);
|
2417
|
-
}
|
2418
|
-
if (vDom.classes && vDom.classes.size) {
|
2419
|
-
attrs.push(`class="${xssFilter.attrValue(Array.from(vDom.classes).join(' '))}"`);
|
2420
|
-
}
|
2421
|
-
let attrStr = attrs.join(' ');
|
2422
|
-
attrStr = attrStr ? ' ' + attrStr : '';
|
2423
|
-
if (this.singleTagTest.test(vDom.tagName)) {
|
2424
|
-
return `<${vDom.tagName}${attrStr}>`;
|
2425
|
-
}
|
2426
|
-
const childHTML = vDom.children.map(child => {
|
2427
|
-
return this.vDomToHTMLString(child);
|
2428
|
-
}).join('');
|
2429
|
-
return [
|
2430
|
-
`<${vDom.tagName}${attrStr}>`,
|
2431
|
-
childHTML,
|
2432
|
-
`</${vDom.tagName}>`
|
2433
|
-
].join('');
|
2434
|
-
}
|
2435
|
-
replaceEmpty(s, target) {
|
2436
|
-
return s.replace(/\s\s+/g, str => {
|
2437
|
-
return ' ' + Array.from({
|
2438
|
-
length: str.length - 1
|
2439
|
-
}).fill(target).join('');
|
2440
|
-
}).replace(/^\s|\s$/g, target);
|
2441
|
-
}
|
2442
|
-
};
|
2443
|
-
OutputTranslator.singleTags = 'br,img,hr'.split(',');
|
2444
|
-
OutputTranslator.simpleXSSFilter = {
|
2445
|
-
text(text) {
|
2446
|
-
return text.replace(/[><&]/g, str => {
|
2447
|
-
return {
|
2448
|
-
'<': '<',
|
2449
|
-
'>': '>',
|
2450
|
-
'&': '&'
|
2451
|
-
}[str];
|
2452
|
-
});
|
2453
|
-
},
|
2454
|
-
attrName(text) {
|
2455
|
-
return text.replace(/[><"'&]/g, str => {
|
2456
|
-
return {
|
2457
|
-
'<': '<',
|
2458
|
-
'>': '>',
|
2459
|
-
'"': '"',
|
2460
|
-
'\'': ''',
|
2461
|
-
'&': '&'
|
2462
|
-
}[str];
|
2463
|
-
});
|
2464
|
-
},
|
2465
|
-
attrValue(text) {
|
2466
|
-
return text.replace(/["']/g, str => {
|
2467
|
-
return {
|
2468
|
-
'"': '"',
|
2469
|
-
'\'': '''
|
2470
|
-
}[str];
|
2471
|
-
});
|
2472
|
-
}
|
2473
|
-
};
|
2474
|
-
OutputTranslator = OutputTranslator_1 = __decorate([
|
2475
|
-
Injectable()
|
2476
|
-
], OutputTranslator);
|
2477
|
-
|
2478
|
-
const editorError = makeError('CoreEditor');
|
2479
|
-
/**
|
2480
|
-
* Textbus PC 端编辑器
|
2481
|
-
*/
|
2482
|
-
class Viewer extends Starter {
|
2483
|
-
get readonly() {
|
2484
|
-
return this.controller.readonly;
|
2485
|
-
}
|
2486
|
-
set readonly(b) {
|
2487
|
-
this.controller.readonly = b;
|
2488
|
-
}
|
2489
|
-
isFocus() {
|
2490
|
-
return this._isFocus;
|
2491
|
-
}
|
2492
|
-
constructor(rootComponent, rootComponentLoader, options = {}) {
|
2493
|
-
const id = 'textbus-' + Number((Math.random() + '').substring(2)).toString(16);
|
2494
|
-
const { doc, mask, wrapper } = Viewer.createLayout(id, options.minHeight);
|
2495
|
-
const staticProviders = [{
|
2301
|
+
class BrowserModule {
|
2302
|
+
constructor(host, config) {
|
2303
|
+
this.host = host;
|
2304
|
+
this.config = config;
|
2305
|
+
const { mask, wrapper } = BrowserModule.createLayout();
|
2306
|
+
wrapper.prepend(config.adapter.host);
|
2307
|
+
if (config.minHeight) {
|
2308
|
+
config.adapter.host.style.minHeight = config.minHeight;
|
2309
|
+
}
|
2310
|
+
this.providers = [{
|
2496
2311
|
provide: EDITOR_OPTIONS,
|
2497
|
-
useValue:
|
2312
|
+
useValue: config
|
2498
2313
|
}, {
|
2499
2314
|
provide: VIEW_CONTAINER,
|
2500
2315
|
useValue: wrapper
|
2501
2316
|
}, {
|
2502
2317
|
provide: VIEW_DOCUMENT,
|
2503
|
-
useValue:
|
2318
|
+
useValue: config.adapter.host
|
2504
2319
|
}, {
|
2505
2320
|
provide: VIEW_MASK,
|
2506
2321
|
useValue: mask
|
2507
|
-
}, {
|
2508
|
-
provide: NativeRenderer,
|
2509
|
-
useExisting: DomRenderer
|
2510
2322
|
}, {
|
2511
2323
|
provide: NativeSelectionBridge,
|
2512
2324
|
useExisting: SelectionBridge
|
2513
2325
|
}, {
|
2514
2326
|
provide: Input,
|
2515
|
-
useClass:
|
2327
|
+
useClass: config.useContentEditable ? NativeInput : MagicInput
|
2516
2328
|
}, {
|
2517
|
-
provide:
|
2518
|
-
useFactory
|
2519
|
-
|
2520
|
-
|
2521
|
-
|
2522
|
-
|
2523
|
-
|
2524
|
-
|
2525
|
-
SelectionBridge,
|
2526
|
-
OutputTranslator,
|
2527
|
-
CollaborateCursor
|
2528
|
-
], setup: options.setup }));
|
2529
|
-
this.rootComponent = rootComponent;
|
2530
|
-
this.rootComponentLoader = rootComponentLoader;
|
2531
|
-
this.options = options;
|
2532
|
-
/** 编辑器是否已销毁 */
|
2533
|
-
this.destroyed = false;
|
2534
|
-
/** 编辑器是否已准备好 */
|
2535
|
-
this.isReady = false;
|
2536
|
-
this.changeEvent = new Subject();
|
2537
|
-
this.subs = [];
|
2538
|
-
this._isFocus = false;
|
2539
|
-
this.resourceNodes = [];
|
2540
|
-
this.focusEvent = new Subject();
|
2541
|
-
this.blurEvent = new Subject();
|
2542
|
-
this.saveEvent = new Subject();
|
2543
|
-
this.styleSheet = '';
|
2544
|
-
this.scripts = [];
|
2545
|
-
this.links = [];
|
2546
|
-
this.id = id;
|
2547
|
-
this.workbench = wrapper;
|
2548
|
-
this.onChange = this.changeEvent.asObservable();
|
2549
|
-
this.onFocus = this.focusEvent.asObservable();
|
2550
|
-
this.onBlur = this.blurEvent.asObservable();
|
2551
|
-
this.onSave = this.saveEvent.asObservable();
|
2552
|
-
this.controller = this.get(Controller);
|
2553
|
-
}
|
2554
|
-
/**
|
2555
|
-
* 初始化编辑器
|
2556
|
-
* @param host 编辑器容器
|
2557
|
-
*/
|
2558
|
-
mount(host) {
|
2559
|
-
const _super = Object.create(null, {
|
2560
|
-
mount: { get: () => super.mount }
|
2561
|
-
});
|
2562
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2563
|
-
if (this.destroyed) {
|
2564
|
-
throw editorError('the editor instance is destroyed!');
|
2565
|
-
}
|
2566
|
-
if (this.destroyed) {
|
2567
|
-
return this;
|
2568
|
-
}
|
2569
|
-
const parser = this.get(Parser);
|
2570
|
-
const registry = this.get(Registry);
|
2571
|
-
const doc = this.get(VIEW_DOCUMENT);
|
2572
|
-
this.initDefaultShortcut();
|
2573
|
-
let component;
|
2574
|
-
const content = this.options.content;
|
2575
|
-
if (content) {
|
2576
|
-
if (typeof content === 'string') {
|
2577
|
-
component = parser.parseDoc(content, this.rootComponentLoader);
|
2578
|
-
}
|
2579
|
-
else {
|
2580
|
-
component = registry.createComponentByFactory(content, this.rootComponent);
|
2581
|
-
}
|
2582
|
-
}
|
2583
|
-
else {
|
2584
|
-
component = this.rootComponent.createInstance(this);
|
2585
|
-
}
|
2586
|
-
this.initDocStyleSheetsAndScripts(this.options);
|
2587
|
-
host.appendChild(this.workbench);
|
2588
|
-
yield _super.mount.call(this, doc, component);
|
2589
|
-
const renderer = this.get(Renderer);
|
2590
|
-
const input = this.get(Input);
|
2591
|
-
this.subs.push(renderer.onViewUpdated.subscribe(() => {
|
2592
|
-
this.changeEvent.next();
|
2593
|
-
}), input.caret.onPositionChange.pipe(map(p => !!p), distinctUntilChanged()).subscribe(b => {
|
2594
|
-
if (b) {
|
2595
|
-
this._isFocus = true;
|
2596
|
-
this.focusEvent.next();
|
2597
|
-
}
|
2598
|
-
else {
|
2599
|
-
this._isFocus = false;
|
2600
|
-
this.blurEvent.next();
|
2601
|
-
}
|
2602
|
-
}));
|
2603
|
-
this.isReady = true;
|
2604
|
-
if (this.options.autoFocus) {
|
2605
|
-
input.onReady.then(() => {
|
2606
|
-
this.focus();
|
2607
|
-
});
|
2608
|
-
}
|
2609
|
-
return this;
|
2610
|
-
});
|
2611
|
-
}
|
2612
|
-
/**
|
2613
|
-
* 获取焦点
|
2614
|
-
*/
|
2615
|
-
focus() {
|
2616
|
-
this.guardReady();
|
2617
|
-
const selection = this.get(Selection);
|
2618
|
-
const rootComponentRef = this.get(RootComponentRef);
|
2619
|
-
if (selection.commonAncestorSlot) {
|
2620
|
-
selection.restore();
|
2621
|
-
return;
|
2622
|
-
}
|
2623
|
-
const location = selection.findFirstPosition(rootComponentRef.component.slots.get(0));
|
2624
|
-
selection.setPosition(location.slot, location.offset);
|
2625
|
-
selection.restore();
|
2626
|
-
}
|
2627
|
-
/**
|
2628
|
-
* 取消编辑器焦点
|
2629
|
-
*/
|
2630
|
-
blur() {
|
2631
|
-
if (this.isReady) {
|
2632
|
-
const selection = this.get(Selection);
|
2633
|
-
selection.unSelect();
|
2634
|
-
selection.restore();
|
2635
|
-
}
|
2636
|
-
}
|
2637
|
-
/**
|
2638
|
-
* 获取编辑器所有资源
|
2639
|
-
*/
|
2640
|
-
getResources() {
|
2641
|
-
var _a;
|
2642
|
-
return {
|
2643
|
-
styleSheets: ((_a = this.options) === null || _a === void 0 ? void 0 : _a.styleSheets) || [],
|
2644
|
-
styleSheet: this.styleSheet,
|
2645
|
-
links: this.links,
|
2646
|
-
scripts: this.scripts
|
2647
|
-
};
|
2648
|
-
}
|
2649
|
-
/**
|
2650
|
-
* 获取 HTML 格式的内容
|
2651
|
-
*/
|
2652
|
-
getHTML() {
|
2653
|
-
this.guardReady();
|
2654
|
-
const outputRenderer = this.get(OutputRenderer);
|
2655
|
-
const outputTranslator = this.get(OutputTranslator);
|
2656
|
-
const vDom = outputRenderer.render();
|
2657
|
-
return outputTranslator.transform(vDom);
|
2658
|
-
}
|
2659
|
-
/**
|
2660
|
-
* 获取 JSON 格式的内容
|
2661
|
-
*/
|
2662
|
-
getJSON() {
|
2663
|
-
this.guardReady();
|
2664
|
-
const rootComponentRef = this.get(RootComponentRef);
|
2665
|
-
return rootComponentRef.component.toJSON();
|
2666
|
-
}
|
2667
|
-
/**
|
2668
|
-
* 清空内容
|
2669
|
-
*/
|
2670
|
-
clear() {
|
2671
|
-
this.replaceContent('');
|
2672
|
-
const history = this.get(History);
|
2673
|
-
history.clear();
|
2674
|
-
}
|
2675
|
-
/**
|
2676
|
-
* 销毁编辑器
|
2677
|
-
*/
|
2678
|
-
destroy() {
|
2679
|
-
var _a;
|
2680
|
-
if (this.destroyed) {
|
2681
|
-
return;
|
2682
|
-
}
|
2683
|
-
this.destroyed = true;
|
2684
|
-
this.subs.forEach(i => i.unsubscribe());
|
2685
|
-
const types = [
|
2686
|
-
Input
|
2687
|
-
];
|
2688
|
-
types.forEach(i => {
|
2689
|
-
this.get(i).destroy();
|
2690
|
-
});
|
2691
|
-
super.destroy();
|
2692
|
-
(_a = this.workbench.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.workbench);
|
2693
|
-
this.resourceNodes.forEach(node => {
|
2694
|
-
var _a;
|
2695
|
-
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
|
2696
|
-
});
|
2697
|
-
}
|
2698
|
-
/**
|
2699
|
-
* 替换编辑的内容
|
2700
|
-
* @param content
|
2701
|
-
*/
|
2702
|
-
replaceContent(content) {
|
2703
|
-
this.guardReady();
|
2704
|
-
const parser = this.get(Parser);
|
2705
|
-
const registry = this.get(Registry);
|
2706
|
-
const rootComponentRef = this.get(RootComponentRef);
|
2707
|
-
const selection = this.get(Selection);
|
2708
|
-
const rootComponentLoader = this.rootComponentLoader;
|
2709
|
-
let component;
|
2710
|
-
if (typeof content === 'string') {
|
2711
|
-
component = parser.parseDoc(content, rootComponentLoader);
|
2712
|
-
}
|
2713
|
-
else {
|
2714
|
-
component = registry.createComponentByFactory(content, this.rootComponent);
|
2715
|
-
}
|
2716
|
-
selection.unSelect();
|
2717
|
-
rootComponentRef.component.slots.clean();
|
2718
|
-
rootComponentRef.component.slots.push(...component.slots.toArray());
|
2719
|
-
invokeListener(component, 'onDestroy');
|
2720
|
-
}
|
2721
|
-
guardReady() {
|
2722
|
-
if (this.destroyed) {
|
2723
|
-
throw editorError('the editor instance is destroyed!');
|
2724
|
-
}
|
2725
|
-
if (!this.isReady) {
|
2726
|
-
throw editorError('please wait for the editor to initialize before getting the content!');
|
2727
|
-
}
|
2728
|
-
}
|
2729
|
-
initDefaultShortcut() {
|
2730
|
-
const selection = this.get(Selection);
|
2731
|
-
const keyboard = this.get(Keyboard);
|
2732
|
-
const history = this.get(History);
|
2733
|
-
const commander = this.get(Commander);
|
2734
|
-
keyboard.addShortcut({
|
2735
|
-
keymap: {
|
2736
|
-
key: 's',
|
2737
|
-
ctrlKey: true
|
2738
|
-
},
|
2739
|
-
action: () => {
|
2740
|
-
this.saveEvent.next();
|
2741
|
-
}
|
2742
|
-
});
|
2743
|
-
keyboard.addShortcut({
|
2744
|
-
keymap: {
|
2745
|
-
key: 'Enter'
|
2746
|
-
},
|
2747
|
-
action: () => {
|
2748
|
-
commander.break();
|
2749
|
-
}
|
2750
|
-
});
|
2751
|
-
keyboard.addShortcut({
|
2752
|
-
keymap: {
|
2753
|
-
key: 'Enter',
|
2754
|
-
shiftKey: true
|
2755
|
-
},
|
2756
|
-
action: () => {
|
2757
|
-
const startOffset = selection.startOffset;
|
2758
|
-
const startSlot = selection.startSlot;
|
2759
|
-
const isToEnd = startOffset === startSlot.length || startSlot.isEmpty;
|
2760
|
-
const content = isToEnd ? '\n\n' : '\n';
|
2761
|
-
const isInserted = commander.insert(content);
|
2762
|
-
if (isInserted && isToEnd) {
|
2763
|
-
selection.setPosition(startSlot, startOffset + 1);
|
2764
|
-
}
|
2765
|
-
}
|
2766
|
-
});
|
2767
|
-
keyboard.addShortcut({
|
2768
|
-
keymap: {
|
2769
|
-
key: ['Delete', 'Backspace']
|
2770
|
-
},
|
2771
|
-
action: (key) => {
|
2772
|
-
commander.delete(key === 'Backspace');
|
2773
|
-
}
|
2774
|
-
});
|
2775
|
-
keyboard.addShortcut({
|
2776
|
-
keymap: {
|
2777
|
-
key: ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']
|
2778
|
-
},
|
2779
|
-
action: (key) => {
|
2780
|
-
switch (key) {
|
2781
|
-
case 'ArrowLeft':
|
2782
|
-
selection.toPrevious();
|
2783
|
-
break;
|
2784
|
-
case 'ArrowRight':
|
2785
|
-
selection.toNext();
|
2786
|
-
break;
|
2787
|
-
case 'ArrowUp':
|
2788
|
-
selection.toPreviousLine();
|
2789
|
-
break;
|
2790
|
-
case 'ArrowDown':
|
2791
|
-
selection.toNextLine();
|
2792
|
-
break;
|
2793
|
-
}
|
2794
|
-
}
|
2795
|
-
});
|
2796
|
-
keyboard.addShortcut({
|
2797
|
-
keymap: {
|
2798
|
-
key: ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'],
|
2799
|
-
shiftKey: true
|
2800
|
-
},
|
2801
|
-
action: (key) => {
|
2802
|
-
switch (key) {
|
2803
|
-
case 'ArrowLeft':
|
2804
|
-
selection.wrapToBefore();
|
2805
|
-
break;
|
2806
|
-
case 'ArrowRight':
|
2807
|
-
selection.wrapToAfter();
|
2808
|
-
break;
|
2809
|
-
case 'ArrowUp':
|
2810
|
-
selection.wrapToPreviousLine();
|
2811
|
-
break;
|
2812
|
-
case 'ArrowDown':
|
2813
|
-
selection.wrapToNextLine();
|
2814
|
-
break;
|
2815
|
-
}
|
2816
|
-
}
|
2817
|
-
});
|
2818
|
-
keyboard.addShortcut({
|
2819
|
-
keymap: {
|
2820
|
-
key: 'Tab'
|
2821
|
-
},
|
2822
|
-
action: () => {
|
2823
|
-
commander.insert(' ');
|
2824
|
-
}
|
2825
|
-
});
|
2826
|
-
keyboard.addShortcut({
|
2827
|
-
keymap: {
|
2828
|
-
key: 'a',
|
2829
|
-
ctrlKey: true
|
2830
|
-
},
|
2831
|
-
action: () => {
|
2832
|
-
selection.selectAll();
|
2833
|
-
}
|
2834
|
-
});
|
2835
|
-
keyboard.addShortcut({
|
2836
|
-
keymap: {
|
2837
|
-
key: 'c',
|
2838
|
-
ctrlKey: true
|
2839
|
-
},
|
2840
|
-
action: () => {
|
2841
|
-
commander.copy();
|
2842
|
-
}
|
2843
|
-
});
|
2844
|
-
keyboard.addShortcut({
|
2845
|
-
keymap: {
|
2846
|
-
key: 'x',
|
2847
|
-
ctrlKey: true
|
2848
|
-
},
|
2849
|
-
action: () => {
|
2850
|
-
commander.cut();
|
2851
|
-
}
|
2852
|
-
});
|
2853
|
-
keyboard.addShortcut({
|
2854
|
-
keymap: {
|
2855
|
-
key: 'z',
|
2856
|
-
ctrlKey: true
|
2857
|
-
},
|
2858
|
-
action: () => {
|
2859
|
-
history.back();
|
2860
|
-
}
|
2861
|
-
});
|
2862
|
-
keyboard.addShortcut({
|
2863
|
-
keymap: {
|
2864
|
-
key: 'z',
|
2865
|
-
ctrlKey: true,
|
2866
|
-
shiftKey: true
|
2329
|
+
provide: ViewAdapter,
|
2330
|
+
useFactory(v) {
|
2331
|
+
return v;
|
2332
|
+
},
|
2333
|
+
deps: [DomAdapter]
|
2334
|
+
}, {
|
2335
|
+
provide: DomAdapter,
|
2336
|
+
useValue: config.adapter
|
2867
2337
|
},
|
2868
|
-
|
2869
|
-
|
2870
|
-
|
2871
|
-
|
2338
|
+
Parser,
|
2339
|
+
SelectionBridge,
|
2340
|
+
CollaborateCursor
|
2341
|
+
];
|
2342
|
+
this.workbench = wrapper;
|
2343
|
+
this.host.append(wrapper);
|
2872
2344
|
}
|
2873
|
-
|
2874
|
-
|
2875
|
-
const loaders = [];
|
2876
|
-
(_a = options.imports) === null || _a === void 0 ? void 0 : _a.forEach(module => {
|
2877
|
-
loaders.push(...(module.componentLoaders || []));
|
2878
|
-
});
|
2879
|
-
loaders.push(...(options.componentLoaders || []));
|
2880
|
-
const resources = loaders.filter(i => i.resources).map(i => i.resources);
|
2881
|
-
const docStyles = [];
|
2882
|
-
const editModeStyles = [];
|
2883
|
-
resources.forEach(metadata => {
|
2884
|
-
var _a, _b;
|
2885
|
-
if (Array.isArray(metadata.links)) {
|
2886
|
-
this.links.push(...metadata.links);
|
2887
|
-
}
|
2888
|
-
docStyles.push(((_a = metadata.styles) === null || _a === void 0 ? void 0 : _a.join('')) || '');
|
2889
|
-
editModeStyles.push(((_b = metadata.editModeStyles) === null || _b === void 0 ? void 0 : _b.join('')) || '');
|
2890
|
-
});
|
2891
|
-
this.links.forEach(link => {
|
2892
|
-
const linkEle = document.createElement('link');
|
2893
|
-
Object.assign(linkEle, link);
|
2894
|
-
this.resourceNodes.push(linkEle);
|
2895
|
-
document.head.appendChild(linkEle);
|
2896
|
-
});
|
2897
|
-
const styleEl = document.createElement('style');
|
2898
|
-
docStyles.push(...(options.styleSheets || []));
|
2899
|
-
editModeStyles.push(`#${this.id} *::selection{background-color: rgba(18, 150, 219, .2); color:inherit}`, ...(options.editingStyleSheets || []));
|
2900
|
-
this.styleSheet = Viewer.cssMin(docStyles.join(''));
|
2901
|
-
styleEl.innerHTML = this.styleSheet + Viewer.cssMin(editModeStyles.join(''));
|
2902
|
-
this.resourceNodes.push(styleEl);
|
2903
|
-
document.head.append(styleEl);
|
2904
|
-
resources.filter(i => { var _a; return (_a = i.scripts) === null || _a === void 0 ? void 0 : _a.length; }).map(i => i.scripts).flat().forEach(src => {
|
2905
|
-
if (src) {
|
2906
|
-
const script = document.createElement('script');
|
2907
|
-
script.src = src;
|
2908
|
-
this.scripts.push(src);
|
2909
|
-
document.head.appendChild(script);
|
2910
|
-
this.resourceNodes.push(script);
|
2911
|
-
}
|
2912
|
-
});
|
2345
|
+
onDestroy() {
|
2346
|
+
this.workbench.remove();
|
2913
2347
|
}
|
2914
|
-
static createLayout(
|
2915
|
-
const doc = createElement('div', {
|
2916
|
-
styles: {
|
2917
|
-
cursor: 'text',
|
2918
|
-
wordBreak: 'break-all',
|
2919
|
-
boxSizing: 'border-box',
|
2920
|
-
minHeight,
|
2921
|
-
flex: 1,
|
2922
|
-
outline: 'none'
|
2923
|
-
},
|
2924
|
-
attrs: {
|
2925
|
-
'data-textbus-view': VIEW_DOCUMENT,
|
2926
|
-
},
|
2927
|
-
props: {
|
2928
|
-
id
|
2929
|
-
}
|
2930
|
-
});
|
2348
|
+
static createLayout() {
|
2931
2349
|
const mask = createElement('div', {
|
2932
2350
|
attrs: {
|
2933
2351
|
'data-textbus-view': VIEW_MASK,
|
@@ -2953,20 +2371,13 @@ class Viewer extends Starter {
|
|
2953
2371
|
position: 'relative',
|
2954
2372
|
flexDirection: 'column'
|
2955
2373
|
},
|
2956
|
-
children: [
|
2374
|
+
children: [mask]
|
2957
2375
|
});
|
2958
2376
|
return {
|
2959
2377
|
wrapper,
|
2960
|
-
doc,
|
2961
2378
|
mask
|
2962
2379
|
};
|
2963
2380
|
}
|
2964
|
-
static cssMin(str) {
|
2965
|
-
return str
|
2966
|
-
.replace(/\s*(?=[>{}:;,[])/g, '')
|
2967
|
-
.replace(/([>{}:;,])\s*/g, '$1')
|
2968
|
-
.replace(/;}/g, '}').replace(/\s+/, ' ').trim();
|
2969
|
-
}
|
2970
2381
|
}
|
2971
2382
|
|
2972
|
-
export { CollaborateCursor, CollaborateSelectionAwarenessDelegate,
|
2383
|
+
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 };
|