@cocreate/text 1.13.4 → 1.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/demo/demos.1.html +1 -1
- package/package.json +10 -9
- package/src/index.js +77 -22
- package/src/updateDom.js +17 -4
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
## [1.14.3](https://github.com/CoCreate-app/CoCreate-text/compare/v1.14.2...v1.14.3) (2021-12-23)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* checkAttributeValue collection or document return ([500c156](https://github.com/CoCreate-app/CoCreate-text/commit/500c156c14fafec187ea40481a5f30f389ec4dc6))
|
7
|
+
|
8
|
+
## [1.14.2](https://github.com/CoCreate-app/CoCreate-text/compare/v1.14.1...v1.14.2) (2021-12-15)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* update dependencies ([4280fbe](https://github.com/CoCreate-app/CoCreate-text/commit/4280fbef8700fc9cd7cfb39e2737561f04921ee4))
|
14
|
+
|
15
|
+
## [1.14.1](https://github.com/CoCreate-app/CoCreate-text/compare/v1.14.0...v1.14.1) (2021-12-14)
|
16
|
+
|
17
|
+
|
18
|
+
### Bug Fixes
|
19
|
+
|
20
|
+
* update dependencies ([423ec14](https://github.com/CoCreate-app/CoCreate-text/commit/423ec14a075157e1b525956e45428d1ea75da72e))
|
21
|
+
|
22
|
+
# [1.14.0](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.4...v1.14.0) (2021-12-14)
|
23
|
+
|
24
|
+
|
25
|
+
### Bug Fixes
|
26
|
+
|
27
|
+
* update dependencies ([4d71711](https://github.com/CoCreate-app/CoCreate-text/commit/4d71711bedf21a3dfa4f28e54b568362d919b535))
|
28
|
+
|
29
|
+
|
30
|
+
### Features
|
31
|
+
|
32
|
+
* support nested contenteditable and cursor positions ([30cc76d](https://github.com/CoCreate-app/CoCreate-text/commit/30cc76d669203e6b55e271e2a3b26398e9764359))
|
33
|
+
|
1
34
|
## [1.13.4](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.3...v1.13.4) (2021-12-08)
|
2
35
|
|
3
36
|
|
package/demo/demos.1.html
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
|
11
11
|
<body class="padding:20px">
|
12
12
|
<form collection="apples1" document_id="61ad22d7a8b6b4001aa360d1">
|
13
|
-
<textarea name="name1" class="width:100%" rows="10"></textarea>
|
13
|
+
<textarea name="name1" class="width:100% padding:0px margin:0px" rows="10"></textarea>
|
14
14
|
<textarea name="name2" class="width:100%" rows="10"></textarea>
|
15
15
|
<iframe name='name2' width="100%" contenteditable></iframe>
|
16
16
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@cocreate/text",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.14.3",
|
4
4
|
"description": "A simple text component in vanilla javascript. Easily configured using HTML5 attributes and/or JavaScript API.",
|
5
5
|
"keywords": [
|
6
6
|
"text",
|
@@ -61,13 +61,14 @@
|
|
61
61
|
"webpack-log": "^3.0.1"
|
62
62
|
},
|
63
63
|
"dependencies": {
|
64
|
-
"@cocreate/actions": "^1.3.
|
65
|
-
"@cocreate/crdt": "^1.8.
|
66
|
-
"@cocreate/crud-client": "^1.4.
|
67
|
-
"@cocreate/cursors": "^1.
|
68
|
-
"@cocreate/docs": "^1.2.
|
69
|
-
"@cocreate/hosting": "^1.2.
|
70
|
-
"@cocreate/observer": "^1.3.
|
71
|
-
"@cocreate/selection": "^1.
|
64
|
+
"@cocreate/actions": "^1.3.25",
|
65
|
+
"@cocreate/crdt": "^1.8.28",
|
66
|
+
"@cocreate/crud-client": "^1.4.40",
|
67
|
+
"@cocreate/cursors": "^1.11.0",
|
68
|
+
"@cocreate/docs": "^1.2.62",
|
69
|
+
"@cocreate/hosting": "^1.2.58",
|
70
|
+
"@cocreate/observer": "^1.3.54",
|
71
|
+
"@cocreate/selection": "^1.3.1",
|
72
|
+
"@cocreate/uuid": "^1.1.51"
|
72
73
|
}
|
73
74
|
}
|
package/src/index.js
CHANGED
@@ -3,6 +3,7 @@ import observer from '@cocreate/observer';
|
|
3
3
|
import crud from '@cocreate/crud-client';
|
4
4
|
import crdt from '@cocreate/crdt';
|
5
5
|
import cursors from '@cocreate/cursors';
|
6
|
+
import uuid from '@cocreate/uuid';
|
6
7
|
import {updateDom} from './updateDom';
|
7
8
|
import {insertAdjacentElement, removeElement, setInnerText, setAttribute, removeAttribute, setClass, setStyle, setClassStyle, replaceInnerText} from './updateText';
|
8
9
|
import {getSelection, processSelection} from '@cocreate/selection';
|
@@ -16,10 +17,7 @@ function init() {
|
|
16
17
|
let elements = document.querySelectorAll(selectors);
|
17
18
|
initElements(elements);
|
18
19
|
_crdtUpdateListener();
|
19
|
-
document
|
20
|
-
let element = document.activeElement;
|
21
|
-
sendPosition(element)
|
22
|
-
});
|
20
|
+
initDocument(document);
|
23
21
|
}
|
24
22
|
|
25
23
|
function initElements (elements) {
|
@@ -31,18 +29,16 @@ function initElement (element) {
|
|
31
29
|
const { collection, document_id, name, isRealtime, isCrdt, isCrud, isSave, isRead } = crud.getAttr(element);
|
32
30
|
if(document_id == "pending") return;
|
33
31
|
if(isCrdt == "false" || isRealtime == "false" || element.type == 'number') return;
|
34
|
-
if(!crud.checkAttrValue(collection)
|
32
|
+
if(!crud.checkAttrValue(collection) || !crud.checkAttrValue(document_id)) return;
|
35
33
|
if(element.tagName === "INPUT" && ["text", "email", "tel", "url"].includes(element.type) || element.tagName === "TEXTAREA" || element.hasAttribute('contenteditable')) {
|
36
34
|
if(!collection || !document_id || !name) return;
|
37
35
|
|
38
36
|
if (!isCrdt) {
|
39
37
|
if (element.tagName == 'IFRAME'){
|
40
38
|
_addEventListeners(element.contentDocument.documentElement);
|
41
|
-
let Document = element.contentDocument
|
42
|
-
Document
|
43
|
-
|
44
|
-
sendPosition(element)
|
45
|
-
}); }
|
39
|
+
let Document = element.contentDocument;
|
40
|
+
initDocument(Document);
|
41
|
+
}
|
46
42
|
else{
|
47
43
|
_addEventListeners(element);
|
48
44
|
}
|
@@ -74,7 +70,30 @@ function initElement (element) {
|
|
74
70
|
}
|
75
71
|
}
|
76
72
|
|
73
|
+
function initDocument(doc) {
|
74
|
+
let documents = window.top.textDocuments;
|
75
|
+
if (!documents){
|
76
|
+
documents = new Map();
|
77
|
+
window.top.textDocuments = documents;
|
78
|
+
}
|
79
|
+
if (!documents.has(doc)) {
|
80
|
+
documents.set(doc);
|
81
|
+
doc.addEventListener('selectionchange', (e) => {
|
82
|
+
let element = doc.activeElement;
|
83
|
+
sendPosition(element);
|
84
|
+
});
|
85
|
+
// doc.removeEventListener('selectionchange', _selectionchange);
|
86
|
+
// doc.addEventListener('selectionchange', _selectionchange)
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
// function _selectionchange(event){
|
91
|
+
// let element = event.currentTarget.activeElement;
|
92
|
+
// sendPosition(element);
|
93
|
+
// }
|
94
|
+
|
77
95
|
export function _addEventListeners (element) {
|
96
|
+
element.addEventListener('mousedown', _mousedown);
|
78
97
|
element.addEventListener('blur', _blur);
|
79
98
|
element.addEventListener('cut', _cut);
|
80
99
|
element.addEventListener('paste', _paste);
|
@@ -83,6 +102,29 @@ export function _addEventListeners (element) {
|
|
83
102
|
element.addEventListener('input', _input);
|
84
103
|
}
|
85
104
|
|
105
|
+
function _mousedown (event) {
|
106
|
+
let domTextEditor = event.currentTarget;
|
107
|
+
if (domTextEditor.tagName === "INPUT" || domTextEditor.tagName === "TEXTAREA") return;
|
108
|
+
let target = event.target;
|
109
|
+
// const path = event.path || (event.composedPath && event.composedPath());
|
110
|
+
// console.log(path)
|
111
|
+
if(!target.id){
|
112
|
+
let eid = target.getAttribute('eid');
|
113
|
+
if(!eid){
|
114
|
+
eid = uuid.generate(6);
|
115
|
+
setAttribute({ domTextEditor, target, name: 'eid', value: eid });
|
116
|
+
}
|
117
|
+
}
|
118
|
+
let contentEditable = target.closest('[collection][document_id][name]');
|
119
|
+
if (contentEditable){
|
120
|
+
target = contentEditable;
|
121
|
+
const { collection, document_id, name } = crud.getAttr(target);
|
122
|
+
if (collection && document_id && name && !target.hasAttribute('contenteditable'))
|
123
|
+
target.setAttribute('contenteditable', 'true');
|
124
|
+
}
|
125
|
+
// sendPosition(element)
|
126
|
+
}
|
127
|
+
|
86
128
|
function _blur (event) {
|
87
129
|
let element = event.currentTarget;
|
88
130
|
const { collection, document_id, name } = crud.getAttr(element);
|
@@ -181,27 +223,40 @@ function _removeEventListeners (element) {
|
|
181
223
|
element.removeEventListener('beforeinput', _beforeinput);
|
182
224
|
}
|
183
225
|
|
226
|
+
let previousPosition = {};
|
184
227
|
export function sendPosition (element) {
|
185
|
-
if (!element) return;
|
186
|
-
|
228
|
+
// if (!element) return;
|
187
229
|
const { start, end, range } = getSelection(element);
|
188
|
-
if(range
|
189
|
-
|
190
|
-
|
191
|
-
|
230
|
+
if(range) {
|
231
|
+
if (range.element){
|
232
|
+
element = range.element;
|
233
|
+
}
|
234
|
+
if (element.tagName == 'HTML' && !element.hasAttribute('collection') || !element.hasAttribute('collection')) {
|
235
|
+
element = element.ownerDocument.defaultView.frameElement;
|
236
|
+
}
|
237
|
+
}
|
192
238
|
if (!element) return;
|
193
239
|
const { collection, document_id, name, isCrdt } = crud.getAttr(element);
|
194
240
|
if (isCrdt == 'false' || !collection || !document_id || !name) return;
|
241
|
+
let currentPosition = { collection, document_id, name, start, end };
|
242
|
+
if (JSON.stringify(currentPosition) === JSON.stringify(previousPosition))
|
243
|
+
return;
|
244
|
+
previousPosition = currentPosition;
|
245
|
+
element.activeElement = element;
|
195
246
|
cursors.sendPosition({ collection, document_id, name, start, end });
|
196
247
|
}
|
197
248
|
|
198
249
|
function updateText ({element, value, start, end, range}) {
|
199
|
-
if(range
|
200
|
-
|
201
|
-
|
202
|
-
|
250
|
+
if(range) {
|
251
|
+
if (range.element)
|
252
|
+
element = range.element;
|
253
|
+
|
254
|
+
if (element.tagName == 'HTML' && !element.hasAttribute('collection'))
|
255
|
+
element = element.ownerDocument.defaultView.frameElement;
|
256
|
+
}
|
203
257
|
const { collection, document_id, name, isCrud, isCrdt, isSave } = crud.getAttr(element);
|
204
258
|
if(isCrdt == "false") return;
|
259
|
+
|
205
260
|
let length = end - start;
|
206
261
|
if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
|
207
262
|
crdt.updateText({ collection, document_id, name, value, start, length, crud: isCrud, save: isSave });
|
@@ -265,8 +320,8 @@ async function updateElement ({element, collection, document_id, name, value, st
|
|
265
320
|
}
|
266
321
|
if (value) {
|
267
322
|
if (element.innerHTML != value) {
|
268
|
-
|
269
|
-
updateDom({ domTextEditor, value, start, end: start });
|
323
|
+
// domTextEditor.htmlString = html;
|
324
|
+
updateDom({ domTextEditor, value, start, end: start, html });
|
270
325
|
}
|
271
326
|
}
|
272
327
|
}
|
package/src/updateDom.js
CHANGED
@@ -3,13 +3,16 @@ import {getSelection, processSelection, getElementPosition} from '@cocreate/sele
|
|
3
3
|
import {domParser} from '@cocreate/utils';
|
4
4
|
|
5
5
|
export function updateDom({domTextEditor, value, start, end, html}) {
|
6
|
+
if (!domTextEditor.htmlString)
|
7
|
+
domTextEditor.htmlString = html;
|
6
8
|
if(start < 0 || start > domTextEditor.htmlString.length)
|
7
9
|
throw new Error('position is out of range');
|
8
10
|
|
9
11
|
let {element, path, position, type} = getElementPosition(domTextEditor.htmlString, start, end);
|
10
|
-
parseHtml(domTextEditor);
|
12
|
+
parseHtml(domTextEditor, html);
|
11
13
|
|
12
|
-
let domEl,
|
14
|
+
let domEl, oldEl, curCaret;
|
15
|
+
let newEl = domTextEditor.newHtml.querySelector(path);
|
13
16
|
if(!newEl){
|
14
17
|
newEl = domTextEditor.cloneNode(true);
|
15
18
|
if (html != undefined)
|
@@ -26,6 +29,15 @@ export function updateDom({domTextEditor, value, start, end, html}) {
|
|
26
29
|
else if(path) {
|
27
30
|
domEl = domTextEditor.querySelector(path);
|
28
31
|
oldEl = domTextEditor.oldHtml.querySelector(path);
|
32
|
+
if (!domEl || !oldEl){
|
33
|
+
let eid = newEl.getAttribute('eid');
|
34
|
+
if (!domEl && eid){
|
35
|
+
domEl = domTextEditor.querySelector(`[eid='${eid}']`);
|
36
|
+
}
|
37
|
+
if (!oldEl && eid){
|
38
|
+
oldEl = domTextEditor.oldHtml.querySelector(`[eid='${eid}']`);
|
39
|
+
}
|
40
|
+
}
|
29
41
|
}
|
30
42
|
|
31
43
|
let activeElement = domEl.ownerDocument.activeElement;
|
@@ -69,6 +81,7 @@ export function updateDom({domTextEditor, value, start, end, html}) {
|
|
69
81
|
else if (type == 'innerHTML') {
|
70
82
|
domEl.replaceChildren(...newEl.childNodes);
|
71
83
|
}
|
84
|
+
domTextEditor.htmlString = html;
|
72
85
|
}
|
73
86
|
if(curCaret && start >= 0 && end >= 0) {
|
74
87
|
if (curCaret.range && curCaret.start >= curCaret.range.startOffset) {
|
@@ -97,8 +110,8 @@ export function updateDom({domTextEditor, value, start, end, html}) {
|
|
97
110
|
}
|
98
111
|
}
|
99
112
|
|
100
|
-
function parseHtml(domTextEditor) {
|
101
|
-
var dom = domParser(
|
113
|
+
function parseHtml(domTextEditor, html) {
|
114
|
+
var dom = domParser(html);
|
102
115
|
if (domTextEditor.newHtml) {
|
103
116
|
domTextEditor.oldHtml = domTextEditor.newHtml;
|
104
117
|
} else {
|