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