@textbus/platform-browser 3.5.0 → 4.0.0-alpha.0
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 +37 -0
- package/bundles/index.esm.js +662 -1275
- package/bundles/index.js +714 -1326
- 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, VElement, VTextNode, ComponentInstance, 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,289 @@ 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 端浏览器渲染能力实现
|
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 = new WeakMap();
|
326
|
+
this.slotRootNativeElementCaches = createBidirectionalMapping(a => {
|
327
|
+
return a instanceof Slot;
|
328
|
+
});
|
329
|
+
this.slotRootVElementCaches = new WeakMap();
|
330
|
+
}
|
331
|
+
render(rootComponent) {
|
332
|
+
const view = this.componentRender(rootComponent);
|
333
|
+
return this.mount(this.host, view);
|
334
|
+
}
|
335
|
+
copy() {
|
336
|
+
document.execCommand('copy');
|
337
|
+
}
|
338
|
+
getNativeNodeByComponent(component) {
|
339
|
+
return this.componentRootElementCaches.get(component) || null;
|
340
|
+
}
|
341
|
+
getNativeNodeBySlot(slot) {
|
342
|
+
return this.slotRootNativeElementCaches.get(slot) || null;
|
343
|
+
}
|
344
|
+
/**
|
345
|
+
* 获取插槽内容节点集合
|
346
|
+
* @param slot
|
347
|
+
*/
|
348
|
+
getNodesBySlot(slot) {
|
349
|
+
const rootNativeNode = this.getNativeNodeBySlot(slot);
|
350
|
+
if (!rootNativeNode) {
|
351
|
+
return [];
|
352
|
+
}
|
353
|
+
const rootVNode = this.slotRootVElementCaches.get(slot);
|
354
|
+
const getNodes = (vElement, nativeNode, result) => {
|
355
|
+
if (vElement.location) {
|
356
|
+
result.push(nativeNode);
|
357
|
+
}
|
358
|
+
for (let i = 0; i < vElement.children.length; i++) {
|
359
|
+
const vChild = vElement.children[i];
|
360
|
+
const nativeChild = nativeNode.childNodes[i];
|
361
|
+
if (vChild instanceof VElement) {
|
362
|
+
getNodes(vChild, nativeChild, result);
|
363
|
+
}
|
364
|
+
else if (vChild instanceof VTextNode) {
|
365
|
+
result.push(nativeChild);
|
366
|
+
}
|
367
|
+
else {
|
368
|
+
result.push(this.getNativeNodeByComponent(vChild));
|
369
|
+
}
|
370
|
+
}
|
371
|
+
return result;
|
372
|
+
};
|
373
|
+
return getNodes(rootVNode, rootNativeNode, []);
|
374
|
+
}
|
375
|
+
/**
|
376
|
+
* 获取原生节点的原始数据在文档中的位置
|
377
|
+
* @param node
|
378
|
+
*/
|
379
|
+
getLocationByNativeNode(node) {
|
380
|
+
let slotRootNode = node;
|
381
|
+
while (!this.slotRootNativeElementCaches.get(slotRootNode)) {
|
382
|
+
slotRootNode = slotRootNode.parentNode;
|
383
|
+
if (!slotRootNode) {
|
384
|
+
return null;
|
385
|
+
}
|
386
|
+
}
|
387
|
+
const slot = this.slotRootNativeElementCaches.get(slotRootNode);
|
388
|
+
const rootVNode = this.slotRootVElementCaches.get(slot);
|
389
|
+
const getLocation = (target, tree, vNodeTree) => {
|
390
|
+
if (target === tree) {
|
391
|
+
return Object.assign({}, vNodeTree.location);
|
392
|
+
}
|
393
|
+
const childNodes = tree.childNodes;
|
394
|
+
for (let i = 0; i < childNodes.length; i++) {
|
395
|
+
const child = vNodeTree.children[i];
|
396
|
+
const nativeChild = tree.childNodes[i];
|
397
|
+
if (nativeChild === target) {
|
398
|
+
if (child instanceof ComponentInstance) {
|
399
|
+
const index = child.parent.indexOf(child);
|
400
|
+
return {
|
401
|
+
slot: child.parent,
|
402
|
+
startIndex: index,
|
403
|
+
endIndex: index + 1
|
404
|
+
};
|
405
|
+
}
|
406
|
+
return child.location;
|
407
|
+
}
|
408
|
+
else if (child instanceof VElement) {
|
409
|
+
let r = null;
|
410
|
+
if (nativeChild.nodeType === Node.ELEMENT_NODE) {
|
411
|
+
r = getLocation(target, nativeChild, child);
|
412
|
+
}
|
413
|
+
if (r) {
|
414
|
+
return r;
|
415
|
+
}
|
416
|
+
}
|
417
|
+
}
|
418
|
+
return null;
|
419
|
+
};
|
420
|
+
return getLocation(node, slotRootNode, rootVNode);
|
421
|
+
}
|
422
|
+
}
|
423
|
+
|
167
424
|
/**
|
168
425
|
* Textbus PC 端选区桥接实现
|
169
426
|
*/
|
170
427
|
let SelectionBridge = class SelectionBridge {
|
171
|
-
constructor(config, injector, controller, selection, rootComponentRef, input,
|
428
|
+
constructor(config, injector, controller, selection, rootComponentRef, input, domAdapter) {
|
172
429
|
this.config = config;
|
173
|
-
this.injector = injector;
|
174
|
-
this.controller = controller;
|
175
430
|
this.selection = selection;
|
176
431
|
this.rootComponentRef = rootComponentRef;
|
177
432
|
this.input = input;
|
178
|
-
this.
|
433
|
+
this.domAdapter = domAdapter;
|
179
434
|
this.nativeSelection = document.getSelection();
|
180
|
-
this.selectionMaskElement = createElement('style');
|
181
435
|
this.selectionChangeEvent = new Subject();
|
182
436
|
this.subs = [];
|
183
437
|
this.connector = null;
|
184
438
|
this.ignoreSelectionChange = false;
|
185
439
|
this.changeFromUser = false;
|
186
440
|
this.docContainer = injector.get(VIEW_DOCUMENT);
|
187
|
-
this.maskContainer = injector.get(VIEW_MASK);
|
188
441
|
this.onSelectionChange = this.selectionChangeEvent.asObservable().pipe(filter(() => {
|
189
442
|
return !controller.readonly;
|
190
443
|
}));
|
191
|
-
document.head.appendChild(this.selectionMaskElement);
|
192
444
|
this.sub = this.onSelectionChange.subscribe((r) => {
|
193
445
|
if (r) {
|
194
446
|
input.focus(r, this.changeFromUser);
|
@@ -484,22 +736,14 @@ let SelectionBridge = class SelectionBridge {
|
|
484
736
|
const isFocusStart = selection.focusNode === nativeRange.startContainer && selection.focusOffset === nativeRange.startOffset;
|
485
737
|
if (!this.docContainer.contains(selection.focusNode)) {
|
486
738
|
if (isFocusEnd) {
|
487
|
-
const
|
488
|
-
if (!vEle) {
|
489
|
-
return;
|
490
|
-
}
|
491
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vEle);
|
739
|
+
const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.first);
|
492
740
|
if (!nativeNode) {
|
493
741
|
return;
|
494
742
|
}
|
495
743
|
nativeRange.setEndAfter(nativeNode.lastChild);
|
496
744
|
}
|
497
745
|
else {
|
498
|
-
const
|
499
|
-
if (!vEle) {
|
500
|
-
return;
|
501
|
-
}
|
502
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vEle);
|
746
|
+
const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.last);
|
503
747
|
if (!nativeNode) {
|
504
748
|
return;
|
505
749
|
}
|
@@ -556,30 +800,28 @@ let SelectionBridge = class SelectionBridge {
|
|
556
800
|
}
|
557
801
|
findSelectedNodeAndOffset(slot, offset) {
|
558
802
|
const prev = slot.getContentAtIndex(offset - 1);
|
559
|
-
const
|
803
|
+
const nodes = this.domAdapter.getNodesBySlot(slot);
|
560
804
|
if (prev) {
|
561
805
|
if (typeof prev !== 'string') {
|
562
|
-
const
|
563
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
|
806
|
+
const nativeNode = this.domAdapter.getNativeNodeByComponent(prev);
|
564
807
|
return {
|
565
808
|
node: nativeNode.parentNode,
|
566
809
|
offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode) + 1
|
567
810
|
};
|
568
811
|
}
|
569
812
|
else if (prev === '\n') {
|
570
|
-
for (const
|
571
|
-
if (
|
813
|
+
for (const node of nodes) {
|
814
|
+
if (node instanceof Text) {
|
572
815
|
continue;
|
573
816
|
}
|
574
|
-
if (
|
575
|
-
const position = this.
|
817
|
+
if (node.nodeName === 'BR') {
|
818
|
+
const position = this.domAdapter.getLocationByNativeNode(node);
|
576
819
|
if (position) {
|
577
820
|
if (position.endIndex === offset) {
|
578
|
-
const
|
579
|
-
const parentNode = nativeNode.parentNode;
|
821
|
+
const parentNode = node.parentNode;
|
580
822
|
return {
|
581
823
|
node: parentNode,
|
582
|
-
offset: Array.from(parentNode.childNodes).indexOf(
|
824
|
+
offset: Array.from(parentNode.childNodes).indexOf(node) + 1
|
583
825
|
};
|
584
826
|
}
|
585
827
|
}
|
@@ -589,36 +831,33 @@ let SelectionBridge = class SelectionBridge {
|
|
589
831
|
}
|
590
832
|
const current = slot.getContentAtIndex(offset);
|
591
833
|
if (current && typeof current !== 'string') {
|
592
|
-
const
|
593
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
|
834
|
+
const nativeNode = this.domAdapter.getNativeNodeByComponent(current);
|
594
835
|
return {
|
595
836
|
node: nativeNode.parentNode,
|
596
837
|
offset: Array.from(nativeNode.parentNode.childNodes).indexOf(nativeNode)
|
597
838
|
};
|
598
839
|
}
|
599
|
-
for (const
|
600
|
-
if (
|
601
|
-
if (
|
602
|
-
const position = this.
|
840
|
+
for (const node of nodes) {
|
841
|
+
if (node instanceof Element) {
|
842
|
+
if (node.tagName === 'BR') {
|
843
|
+
const position = this.domAdapter.getLocationByNativeNode(node);
|
603
844
|
if (position) {
|
604
845
|
if (position.startIndex === offset) {
|
605
|
-
const
|
606
|
-
const parentNode = nativeNode.parentNode;
|
846
|
+
const parentNode = node.parentNode;
|
607
847
|
return {
|
608
848
|
node: parentNode,
|
609
|
-
offset: Array.from(parentNode.childNodes).indexOf(
|
849
|
+
offset: Array.from(parentNode.childNodes).indexOf(node)
|
610
850
|
};
|
611
851
|
}
|
612
852
|
}
|
613
853
|
}
|
614
854
|
continue;
|
615
855
|
}
|
616
|
-
const position = this.
|
856
|
+
const position = this.domAdapter.getLocationByNativeNode(node);
|
617
857
|
if (position) {
|
618
858
|
if (offset >= position.startIndex && offset <= position.endIndex) {
|
619
|
-
const nativeNode = this.renderer.getNativeNodeByVNode(vNode);
|
620
859
|
return {
|
621
|
-
node:
|
860
|
+
node: node,
|
622
861
|
offset: offset - position.startIndex
|
623
862
|
};
|
624
863
|
}
|
@@ -629,10 +868,10 @@ let SelectionBridge = class SelectionBridge {
|
|
629
868
|
getCorrectedPosition(node, offset, toAfter, excludeNodes = []) {
|
630
869
|
excludeNodes.push(node);
|
631
870
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
632
|
-
const containerPosition = this.
|
871
|
+
const containerPosition = this.domAdapter.getLocationByNativeNode(node);
|
633
872
|
const childNode = node.childNodes[offset];
|
634
873
|
if (childNode) {
|
635
|
-
const childPosition = this.
|
874
|
+
const childPosition = this.domAdapter.getLocationByNativeNode(childNode);
|
636
875
|
if (childPosition) {
|
637
876
|
if (containerPosition) {
|
638
877
|
return {
|
@@ -646,7 +885,7 @@ let SelectionBridge = class SelectionBridge {
|
|
646
885
|
}
|
647
886
|
const prevNode = node.childNodes[offset - 1];
|
648
887
|
if (prevNode) {
|
649
|
-
const prevPosition = this.
|
888
|
+
const prevPosition = this.domAdapter.getLocationByNativeNode(prevNode);
|
650
889
|
if (prevPosition && containerPosition) {
|
651
890
|
return {
|
652
891
|
slot: prevPosition.slot,
|
@@ -667,7 +906,7 @@ let SelectionBridge = class SelectionBridge {
|
|
667
906
|
return this.findFocusNodeByParent(node, toAfter, excludeNodes);
|
668
907
|
}
|
669
908
|
else if (node.nodeType === Node.TEXT_NODE) {
|
670
|
-
const containerPosition = this.
|
909
|
+
const containerPosition = this.domAdapter.getLocationByNativeNode(node);
|
671
910
|
if (containerPosition) {
|
672
911
|
return {
|
673
912
|
slot: containerPosition.slot,
|
@@ -691,7 +930,7 @@ let SelectionBridge = class SelectionBridge {
|
|
691
930
|
return this.findFocusNodeByParent(node, toAfter, excludeNodes);
|
692
931
|
}
|
693
932
|
excludeNodes.push(node);
|
694
|
-
const position = this.
|
933
|
+
const position = this.domAdapter.getLocationByNativeNode(node);
|
695
934
|
if (position) {
|
696
935
|
return {
|
697
936
|
slot: position.slot,
|
@@ -711,7 +950,7 @@ let SelectionBridge = class SelectionBridge {
|
|
711
950
|
findFocusNodeByParent(node, toAfter, excludeNodes) {
|
712
951
|
const parentNode = node.parentNode;
|
713
952
|
if (parentNode) {
|
714
|
-
const parentPosition = this.
|
953
|
+
const parentPosition = this.domAdapter.getLocationByNativeNode(parentNode);
|
715
954
|
if (parentPosition) {
|
716
955
|
return {
|
717
956
|
slot: parentPosition.slot,
|
@@ -732,660 +971,46 @@ SelectionBridge = __decorate([
|
|
732
971
|
Selection,
|
733
972
|
RootComponentRef,
|
734
973
|
Input,
|
735
|
-
|
974
|
+
DomAdapter])
|
736
975
|
], SelectionBridge);
|
737
976
|
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
977
|
+
const iframeHTML = `
|
978
|
+
<!DOCTYPE html>
|
979
|
+
<html>
|
980
|
+
<head>
|
981
|
+
<meta charset="UTF-8">
|
982
|
+
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
983
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
984
|
+
<title>Textbus</title>
|
985
|
+
<style>
|
986
|
+
html {position: fixed; left:0; overflow: hidden}
|
987
|
+
html, body{height: 100%;width:100%}
|
988
|
+
body{margin:0; overflow: hidden}
|
989
|
+
textarea{width: 2000px;height: 100%;opacity: 0; padding: 0; outline: none; border: none; position: absolute; left:0; top:0;}
|
990
|
+
</style>
|
991
|
+
</head>
|
992
|
+
<body>
|
993
|
+
</body>
|
994
|
+
</html>
|
995
|
+
`;
|
996
|
+
class ExperimentalCaret {
|
997
|
+
get rect() {
|
998
|
+
return this.caret.getBoundingClientRect();
|
999
|
+
}
|
1000
|
+
set display(v) {
|
1001
|
+
this._display = v;
|
1002
|
+
this.caret.style.visibility = v ? 'visible' : 'hidden';
|
1003
|
+
}
|
1004
|
+
get display() {
|
1005
|
+
return this._display;
|
1006
|
+
}
|
1007
|
+
constructor(scheduler, editorMask) {
|
750
1008
|
this.scheduler = scheduler;
|
751
|
-
this.
|
752
|
-
this.
|
753
|
-
this.
|
1009
|
+
this.editorMask = editorMask;
|
1010
|
+
this.compositionState = null;
|
1011
|
+
this.compositionElement = createElement('span', {
|
754
1012
|
styles: {
|
755
|
-
|
756
|
-
left: 0,
|
757
|
-
top: 0,
|
758
|
-
width: '100%',
|
759
|
-
height: '100%',
|
760
|
-
pointerEvents: 'none',
|
761
|
-
zIndex: 1
|
762
|
-
}
|
763
|
-
});
|
764
|
-
this.canvasContainer = createElement('div', {
|
765
|
-
styles: {
|
766
|
-
position: 'absolute',
|
767
|
-
left: 0,
|
768
|
-
top: 0,
|
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) {
|
1383
|
-
this.scheduler = scheduler;
|
1384
|
-
this.editorMask = editorMask;
|
1385
|
-
this.compositionState = null;
|
1386
|
-
this.compositionElement = createElement('span', {
|
1387
|
-
styles: {
|
1388
|
-
textDecoration: 'underline'
|
1013
|
+
textDecoration: 'underline'
|
1389
1014
|
}
|
1390
1015
|
});
|
1391
1016
|
this.timer = null;
|
@@ -1857,10 +1482,21 @@ let MagicInput = class MagicInput extends Input {
|
|
1857
1482
|
textarea.value = '';
|
1858
1483
|
return ev.data;
|
1859
1484
|
}))).subscribe(text => {
|
1860
|
-
var _a;
|
1861
1485
|
this.composition = false;
|
1862
1486
|
this.caret.compositionState = this.compositionState = null;
|
1863
|
-
|
1487
|
+
const compositionElement = this.caret.compositionElement;
|
1488
|
+
let nextSibling = compositionElement.nextSibling;
|
1489
|
+
while (nextSibling) {
|
1490
|
+
if (!nextSibling.textContent) {
|
1491
|
+
const next = nextSibling.nextSibling;
|
1492
|
+
nextSibling.remove();
|
1493
|
+
nextSibling = next;
|
1494
|
+
continue;
|
1495
|
+
}
|
1496
|
+
nextSibling.remove();
|
1497
|
+
break;
|
1498
|
+
}
|
1499
|
+
compositionElement.remove();
|
1864
1500
|
if (text) {
|
1865
1501
|
this.commander.write(text);
|
1866
1502
|
}
|
@@ -1874,32 +1510,293 @@ let MagicInput = class MagicInput extends Input {
|
|
1874
1510
|
isCompositionEnd = false;
|
1875
1511
|
}));
|
1876
1512
|
}
|
1877
|
-
createEditableFrame() {
|
1878
|
-
return createElement('iframe', {
|
1879
|
-
attrs: {
|
1880
|
-
scrolling: 'no'
|
1881
|
-
},
|
1513
|
+
createEditableFrame() {
|
1514
|
+
return createElement('iframe', {
|
1515
|
+
attrs: {
|
1516
|
+
scrolling: 'no'
|
1517
|
+
},
|
1518
|
+
styles: {
|
1519
|
+
border: 'none',
|
1520
|
+
width: '100%',
|
1521
|
+
display: 'block',
|
1522
|
+
height: '100%',
|
1523
|
+
position: 'relative',
|
1524
|
+
top: this.isWindows ? '3px' : '0'
|
1525
|
+
}
|
1526
|
+
});
|
1527
|
+
}
|
1528
|
+
};
|
1529
|
+
MagicInput = __decorate([
|
1530
|
+
Injectable(),
|
1531
|
+
__metadata("design:paramtypes", [Parser,
|
1532
|
+
Keyboard,
|
1533
|
+
Commander,
|
1534
|
+
Selection,
|
1535
|
+
Controller,
|
1536
|
+
Scheduler,
|
1537
|
+
Injector])
|
1538
|
+
], MagicInput);
|
1539
|
+
|
1540
|
+
/**
|
1541
|
+
* 远程光标绘制范围计算代理类,可用于定制特定场景下的远程选区绘制,如表格有选区,不会遵守常见的文档流形式
|
1542
|
+
*/
|
1543
|
+
class CollaborateSelectionAwarenessDelegate {
|
1544
|
+
}
|
1545
|
+
/**
|
1546
|
+
* 协作光标绘制类
|
1547
|
+
*/
|
1548
|
+
let CollaborateCursor = class CollaborateCursor {
|
1549
|
+
constructor(injector, nativeSelection, scheduler, selection, awarenessDelegate) {
|
1550
|
+
this.nativeSelection = nativeSelection;
|
1551
|
+
this.scheduler = scheduler;
|
1552
|
+
this.selection = selection;
|
1553
|
+
this.awarenessDelegate = awarenessDelegate;
|
1554
|
+
this.host = createElement('div', {
|
1555
|
+
styles: {
|
1556
|
+
position: 'absolute',
|
1557
|
+
left: 0,
|
1558
|
+
top: 0,
|
1559
|
+
width: '100%',
|
1560
|
+
height: '100%',
|
1561
|
+
pointerEvents: 'none',
|
1562
|
+
zIndex: 1
|
1563
|
+
}
|
1564
|
+
});
|
1565
|
+
this.canvasContainer = createElement('div', {
|
1566
|
+
styles: {
|
1567
|
+
position: 'absolute',
|
1568
|
+
left: 0,
|
1569
|
+
top: 0,
|
1570
|
+
width: '100%',
|
1571
|
+
height: '100%',
|
1572
|
+
overflow: 'hidden'
|
1573
|
+
}
|
1574
|
+
});
|
1575
|
+
this.canvas = createElement('canvas', {
|
1576
|
+
styles: {
|
1577
|
+
position: 'absolute',
|
1578
|
+
opacity: 0.5,
|
1579
|
+
left: 0,
|
1580
|
+
top: 0,
|
1581
|
+
width: '100%',
|
1582
|
+
height: document.documentElement.clientHeight + 'px',
|
1583
|
+
pointerEvents: 'none',
|
1584
|
+
}
|
1585
|
+
});
|
1586
|
+
this.context = this.canvas.getContext('2d');
|
1587
|
+
this.tooltips = createElement('div', {
|
1588
|
+
styles: {
|
1589
|
+
position: 'absolute',
|
1590
|
+
left: 0,
|
1591
|
+
top: 0,
|
1592
|
+
width: '100%',
|
1593
|
+
height: '100%',
|
1594
|
+
pointerEvents: 'none',
|
1595
|
+
fontSize: '12px',
|
1596
|
+
zIndex: 10
|
1597
|
+
}
|
1598
|
+
});
|
1599
|
+
this.onRectsChange = new Subject();
|
1600
|
+
this.subscription = new Subscription();
|
1601
|
+
this.currentSelection = [];
|
1602
|
+
this.container = injector.get(VIEW_CONTAINER);
|
1603
|
+
this.canvasContainer.append(this.canvas);
|
1604
|
+
this.host.append(this.canvasContainer, this.tooltips);
|
1605
|
+
this.container.prepend(this.host);
|
1606
|
+
this.subscription.add(this.onRectsChange.subscribe(rects => {
|
1607
|
+
for (const rect of rects) {
|
1608
|
+
this.context.fillStyle = rect.color;
|
1609
|
+
this.context.beginPath();
|
1610
|
+
this.context.rect(rect.left, rect.top, rect.width, rect.height);
|
1611
|
+
this.context.fill();
|
1612
|
+
this.context.closePath();
|
1613
|
+
}
|
1614
|
+
}), fromEvent(window, 'resize').subscribe(() => {
|
1615
|
+
this.canvas.style.height = document.documentElement.clientHeight + 'px';
|
1616
|
+
this.refresh();
|
1617
|
+
}), this.scheduler.onDocChanged.subscribe(() => {
|
1618
|
+
this.refresh();
|
1619
|
+
}));
|
1620
|
+
}
|
1621
|
+
/**
|
1622
|
+
* 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
|
1623
|
+
*/
|
1624
|
+
refresh() {
|
1625
|
+
this.draw(this.currentSelection);
|
1626
|
+
}
|
1627
|
+
destroy() {
|
1628
|
+
this.subscription.unsubscribe();
|
1629
|
+
}
|
1630
|
+
/**
|
1631
|
+
* 根据远程用户光标位置,绘制协作光标
|
1632
|
+
* @param paths
|
1633
|
+
*/
|
1634
|
+
draw(paths) {
|
1635
|
+
this.currentSelection = paths;
|
1636
|
+
const containerRect = this.container.getBoundingClientRect();
|
1637
|
+
this.canvas.style.top = containerRect.top * -1 + 'px';
|
1638
|
+
this.canvas.width = this.canvas.offsetWidth;
|
1639
|
+
this.canvas.height = this.canvas.offsetHeight;
|
1640
|
+
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
1641
|
+
const users = [];
|
1642
|
+
paths.filter(i => {
|
1643
|
+
return i.paths.anchor.length && i.paths.focus.length;
|
1644
|
+
}).forEach(item => {
|
1645
|
+
const anchorPaths = [...item.paths.anchor];
|
1646
|
+
const focusPaths = [...item.paths.focus];
|
1647
|
+
const anchorOffset = anchorPaths.pop();
|
1648
|
+
const anchorSlot = this.selection.findSlotByPaths(anchorPaths);
|
1649
|
+
const focusOffset = focusPaths.pop();
|
1650
|
+
const focusSlot = this.selection.findSlotByPaths(focusPaths);
|
1651
|
+
if (!anchorSlot || !focusSlot) {
|
1652
|
+
return;
|
1653
|
+
}
|
1654
|
+
const { focus, anchor } = this.nativeSelection.getPositionByRange({
|
1655
|
+
focusOffset,
|
1656
|
+
anchorOffset,
|
1657
|
+
focusSlot,
|
1658
|
+
anchorSlot
|
1659
|
+
});
|
1660
|
+
if (!focus || !anchor) {
|
1661
|
+
return;
|
1662
|
+
}
|
1663
|
+
const nativeRange = document.createRange();
|
1664
|
+
nativeRange.setStart(anchor.node, anchor.offset);
|
1665
|
+
nativeRange.setEnd(focus.node, focus.offset);
|
1666
|
+
if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
|
1667
|
+
nativeRange.setStart(focus.node, focus.offset);
|
1668
|
+
nativeRange.setEnd(anchor.node, anchor.offset);
|
1669
|
+
}
|
1670
|
+
let rects = false;
|
1671
|
+
if (this.awarenessDelegate) {
|
1672
|
+
rects = this.awarenessDelegate.getRects({
|
1673
|
+
focusOffset,
|
1674
|
+
anchorOffset,
|
1675
|
+
focusSlot,
|
1676
|
+
anchorSlot
|
1677
|
+
}, nativeRange);
|
1678
|
+
}
|
1679
|
+
if (!rects) {
|
1680
|
+
rects = nativeRange.getClientRects();
|
1681
|
+
}
|
1682
|
+
const selectionRects = [];
|
1683
|
+
for (let i = rects.length - 1; i >= 0; i--) {
|
1684
|
+
const rect = rects[i];
|
1685
|
+
selectionRects.push({
|
1686
|
+
id: item.id,
|
1687
|
+
color: item.color,
|
1688
|
+
username: item.username,
|
1689
|
+
left: rect.left - containerRect.left,
|
1690
|
+
top: rect.top,
|
1691
|
+
width: rect.width,
|
1692
|
+
height: rect.height,
|
1693
|
+
});
|
1694
|
+
}
|
1695
|
+
this.onRectsChange.next(selectionRects);
|
1696
|
+
const cursorRange = nativeRange.cloneRange();
|
1697
|
+
cursorRange.setStart(focus.node, focus.offset);
|
1698
|
+
cursorRange.collapse(true);
|
1699
|
+
const cursorRect = getLayoutRectByRange(cursorRange);
|
1700
|
+
const rect = {
|
1701
|
+
id: item.id,
|
1702
|
+
username: item.username,
|
1703
|
+
color: item.color,
|
1704
|
+
left: cursorRect.left - containerRect.left,
|
1705
|
+
top: cursorRect.top - containerRect.top,
|
1706
|
+
width: 1,
|
1707
|
+
height: cursorRect.height
|
1708
|
+
};
|
1709
|
+
if (rect.left < 0 || rect.top < 0 || rect.left > containerRect.width) {
|
1710
|
+
return;
|
1711
|
+
}
|
1712
|
+
users.push(rect);
|
1713
|
+
});
|
1714
|
+
this.drawUserCursor(users);
|
1715
|
+
}
|
1716
|
+
drawUserCursor(rects) {
|
1717
|
+
for (let i = 0; i < rects.length; i++) {
|
1718
|
+
const rect = rects[i];
|
1719
|
+
const { cursor, userTip, anchor } = this.getUserCursor(i);
|
1720
|
+
Object.assign(cursor.style, {
|
1721
|
+
left: rect.left + 'px',
|
1722
|
+
top: rect.top + 'px',
|
1723
|
+
width: rect.width + 'px',
|
1724
|
+
height: rect.height + 'px',
|
1725
|
+
background: rect.color,
|
1726
|
+
display: 'block'
|
1727
|
+
});
|
1728
|
+
anchor.style.background = rect.color;
|
1729
|
+
userTip.innerText = rect.username;
|
1730
|
+
userTip.style.background = rect.color;
|
1731
|
+
}
|
1732
|
+
for (let i = rects.length; i < this.tooltips.children.length; i++) {
|
1733
|
+
this.tooltips.removeChild(this.tooltips.children[i]);
|
1734
|
+
}
|
1735
|
+
}
|
1736
|
+
getUserCursor(index) {
|
1737
|
+
let child = this.tooltips.children[index];
|
1738
|
+
if (child) {
|
1739
|
+
const anchor = child.children[0];
|
1740
|
+
return {
|
1741
|
+
cursor: child,
|
1742
|
+
anchor,
|
1743
|
+
userTip: anchor.children[0]
|
1744
|
+
};
|
1745
|
+
}
|
1746
|
+
const userTip = createElement('span', {
|
1882
1747
|
styles: {
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1748
|
+
position: 'absolute',
|
1749
|
+
left: '50%',
|
1750
|
+
transform: 'translateX(-50%)',
|
1751
|
+
marginBottom: '2px',
|
1752
|
+
bottom: '100%',
|
1753
|
+
whiteSpace: 'nowrap',
|
1754
|
+
color: '#fff',
|
1755
|
+
boxShadow: '0 1px 2px rgba(0,0,0,.1)',
|
1756
|
+
opacity: 0.8,
|
1757
|
+
borderRadius: '3px',
|
1758
|
+
padding: '3px 5px',
|
1759
|
+
pointerEvents: 'none',
|
1889
1760
|
}
|
1890
1761
|
});
|
1762
|
+
const anchor = createElement('span', {
|
1763
|
+
styles: {
|
1764
|
+
position: 'absolute',
|
1765
|
+
top: '-2px',
|
1766
|
+
left: '-2px',
|
1767
|
+
width: '5px',
|
1768
|
+
height: '5px',
|
1769
|
+
borderRadius: '50%',
|
1770
|
+
pointerEvents: 'auto',
|
1771
|
+
pointer: 'cursor',
|
1772
|
+
},
|
1773
|
+
children: [userTip]
|
1774
|
+
});
|
1775
|
+
child = createElement('span', {
|
1776
|
+
styles: {
|
1777
|
+
position: 'absolute',
|
1778
|
+
},
|
1779
|
+
children: [
|
1780
|
+
anchor
|
1781
|
+
]
|
1782
|
+
});
|
1783
|
+
this.tooltips.append(child);
|
1784
|
+
return {
|
1785
|
+
cursor: child,
|
1786
|
+
anchor,
|
1787
|
+
userTip
|
1788
|
+
};
|
1891
1789
|
}
|
1892
1790
|
};
|
1893
|
-
|
1791
|
+
CollaborateCursor = __decorate([
|
1894
1792
|
Injectable(),
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
Selection,
|
1899
|
-
Controller,
|
1793
|
+
__param(4, Optional()),
|
1794
|
+
__metadata("design:paramtypes", [Injector,
|
1795
|
+
SelectionBridge,
|
1900
1796
|
Scheduler,
|
1901
|
-
|
1902
|
-
]
|
1797
|
+
Selection,
|
1798
|
+
CollaborateSelectionAwarenessDelegate])
|
1799
|
+
], CollaborateCursor);
|
1903
1800
|
|
1904
1801
|
class NativeCaret {
|
1905
1802
|
set nativeRange(range) {
|
@@ -2015,14 +1912,13 @@ let NativeInput = class NativeInput extends Input {
|
|
2015
1912
|
get disabled() {
|
2016
1913
|
return this._disabled;
|
2017
1914
|
}
|
2018
|
-
constructor(injector, parser, scheduler, selection, keyboard,
|
1915
|
+
constructor(injector, parser, scheduler, selection, keyboard, domAdapter, commander, controller) {
|
2019
1916
|
super();
|
2020
|
-
this.injector = injector;
|
2021
1917
|
this.parser = parser;
|
2022
1918
|
this.scheduler = scheduler;
|
2023
1919
|
this.selection = selection;
|
2024
1920
|
this.keyboard = keyboard;
|
2025
|
-
this.
|
1921
|
+
this.domAdapter = domAdapter;
|
2026
1922
|
this.commander = commander;
|
2027
1923
|
this.controller = controller;
|
2028
1924
|
this.caret = new NativeCaret(this.scheduler);
|
@@ -2250,7 +2146,7 @@ let NativeInput = class NativeInput extends Input {
|
|
2250
2146
|
if (!range) {
|
2251
2147
|
break;
|
2252
2148
|
}
|
2253
|
-
const location = this.
|
2149
|
+
const location = this.domAdapter.getLocationByNativeNode(range.startContainer);
|
2254
2150
|
const startSlot = this.selection.startSlot;
|
2255
2151
|
if (startSlot) {
|
2256
2152
|
this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
|
@@ -2261,7 +2157,7 @@ let NativeInput = class NativeInput extends Input {
|
|
2261
2157
|
case 'insertReplacementText': {
|
2262
2158
|
this.composition = false;
|
2263
2159
|
const range = ev.getTargetRanges()[0];
|
2264
|
-
const location = this.
|
2160
|
+
const location = this.domAdapter.getLocationByNativeNode(range.startContainer);
|
2265
2161
|
const startSlot = this.selection.startSlot;
|
2266
2162
|
this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
|
2267
2163
|
this.commander.delete();
|
@@ -2315,7 +2211,7 @@ let NativeInput = class NativeInput extends Input {
|
|
2315
2211
|
}
|
2316
2212
|
if (ev.inputType === 'insertReplacementText') {
|
2317
2213
|
const range = ev.getTargetRanges()[0];
|
2318
|
-
const location = this.
|
2214
|
+
const location = this.domAdapter.getLocationByNativeNode(range.startContainer);
|
2319
2215
|
const startSlot = this.selection.startSlot;
|
2320
2216
|
this.selection.setBaseAndExtent(startSlot, location.startIndex + range.startOffset, startSlot, location.startIndex + range.endOffset);
|
2321
2217
|
this.commander.delete();
|
@@ -2373,561 +2269,59 @@ NativeInput = __decorate([
|
|
2373
2269
|
Scheduler,
|
2374
2270
|
Selection,
|
2375
2271
|
Keyboard,
|
2376
|
-
|
2272
|
+
DomAdapter,
|
2377
2273
|
Commander,
|
2378
2274
|
Controller])
|
2379
2275
|
], NativeInput);
|
2380
2276
|
|
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 = [{
|
2277
|
+
class BrowserModule {
|
2278
|
+
constructor(host, config) {
|
2279
|
+
this.host = host;
|
2280
|
+
this.config = config;
|
2281
|
+
const { mask, wrapper } = BrowserModule.createLayout();
|
2282
|
+
wrapper.prepend(config.adapter.host);
|
2283
|
+
if (config.minHeight) {
|
2284
|
+
config.adapter.host.style.minHeight = config.minHeight;
|
2285
|
+
}
|
2286
|
+
this.providers = [{
|
2496
2287
|
provide: EDITOR_OPTIONS,
|
2497
|
-
useValue:
|
2288
|
+
useValue: config
|
2498
2289
|
}, {
|
2499
2290
|
provide: VIEW_CONTAINER,
|
2500
2291
|
useValue: wrapper
|
2501
2292
|
}, {
|
2502
2293
|
provide: VIEW_DOCUMENT,
|
2503
|
-
useValue:
|
2294
|
+
useValue: config.adapter.host
|
2504
2295
|
}, {
|
2505
2296
|
provide: VIEW_MASK,
|
2506
2297
|
useValue: mask
|
2507
|
-
}, {
|
2508
|
-
provide: NativeRenderer,
|
2509
|
-
useExisting: DomRenderer
|
2510
2298
|
}, {
|
2511
2299
|
provide: NativeSelectionBridge,
|
2512
2300
|
useExisting: SelectionBridge
|
2513
2301
|
}, {
|
2514
2302
|
provide: Input,
|
2515
|
-
useClass:
|
2303
|
+
useClass: config.useContentEditable ? NativeInput : MagicInput
|
2516
2304
|
}, {
|
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
|
2305
|
+
provide: ViewAdapter,
|
2306
|
+
useFactory(v) {
|
2307
|
+
return v;
|
2308
|
+
},
|
2309
|
+
deps: [DomAdapter]
|
2310
|
+
}, {
|
2311
|
+
provide: DomAdapter,
|
2312
|
+
useValue: config.adapter
|
2867
2313
|
},
|
2868
|
-
|
2869
|
-
|
2870
|
-
|
2871
|
-
|
2314
|
+
Parser,
|
2315
|
+
SelectionBridge,
|
2316
|
+
CollaborateCursor
|
2317
|
+
];
|
2318
|
+
this.workbench = wrapper;
|
2319
|
+
this.host.append(wrapper);
|
2872
2320
|
}
|
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
|
-
});
|
2321
|
+
onDestroy() {
|
2322
|
+
this.workbench.remove();
|
2913
2323
|
}
|
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
|
-
});
|
2324
|
+
static createLayout() {
|
2931
2325
|
const mask = createElement('div', {
|
2932
2326
|
attrs: {
|
2933
2327
|
'data-textbus-view': VIEW_MASK,
|
@@ -2953,20 +2347,13 @@ class Viewer extends Starter {
|
|
2953
2347
|
position: 'relative',
|
2954
2348
|
flexDirection: 'column'
|
2955
2349
|
},
|
2956
|
-
children: [
|
2350
|
+
children: [mask]
|
2957
2351
|
});
|
2958
2352
|
return {
|
2959
2353
|
wrapper,
|
2960
|
-
doc,
|
2961
2354
|
mask
|
2962
2355
|
};
|
2963
2356
|
}
|
2964
|
-
static cssMin(str) {
|
2965
|
-
return str
|
2966
|
-
.replace(/\s*(?=[>{}:;,[])/g, '')
|
2967
|
-
.replace(/([>{}:;,])\s*/g, '$1')
|
2968
|
-
.replace(/;}/g, '}').replace(/\s+/, ' ').trim();
|
2969
|
-
}
|
2970
2357
|
}
|
2971
2358
|
|
2972
|
-
export { CollaborateCursor, CollaborateSelectionAwarenessDelegate,
|
2359
|
+
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 };
|