@cocreate/text 1.13.1 → 1.14.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/CHANGELOG.md +33 -0
- package/demo/demos.1.html +24 -0
- package/package.json +10 -9
- package/src/index.js +79 -19
- package/src/updateDom.js +19 -4
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
# [1.14.0](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.4...v1.14.0) (2021-12-14)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* update dependencies ([4d71711](https://github.com/CoCreate-app/CoCreate-text/commit/4d71711bedf21a3dfa4f28e54b568362d919b535))
|
7
|
+
|
8
|
+
|
9
|
+
### Features
|
10
|
+
|
11
|
+
* support nested contenteditable and cursor positions ([30cc76d](https://github.com/CoCreate-app/CoCreate-text/commit/30cc76d669203e6b55e271e2a3b26398e9764359))
|
12
|
+
|
13
|
+
## [1.13.4](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.3...v1.13.4) (2021-12-08)
|
14
|
+
|
15
|
+
|
16
|
+
### Bug Fixes
|
17
|
+
|
18
|
+
* observer attribute contenteditable, get element to update using selection range.element ([2bb32bf](https://github.com/CoCreate-app/CoCreate-text/commit/2bb32bf5650505c76efb44d2f941b1b249deaebf))
|
19
|
+
|
20
|
+
## [1.13.3](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.2...v1.13.3) (2021-11-29)
|
21
|
+
|
22
|
+
|
23
|
+
### Bug Fixes
|
24
|
+
|
25
|
+
* sendPosition if no element return ([fec4fbb](https://github.com/CoCreate-app/CoCreate-text/commit/fec4fbb20b574af0995f1f49ad16501a83c52b98))
|
26
|
+
|
27
|
+
## [1.13.2](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.1...v1.13.2) (2021-11-28)
|
28
|
+
|
29
|
+
|
30
|
+
### Bug Fixes
|
31
|
+
|
32
|
+
* removed console.log ([81a07d4](https://github.com/CoCreate-app/CoCreate-text/commit/81a07d4be95acd507fa4047de38847069fd53d5c))
|
33
|
+
|
1
34
|
## [1.13.1](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.0...v1.13.1) (2021-11-28)
|
2
35
|
|
3
36
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
|
4
|
+
<head>
|
5
|
+
<meta charset="utf-8">
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
8
|
+
<title>Text | CoCreate</title>
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<body class="padding:20px">
|
12
|
+
<form collection="apples1" document_id="61ad22d7a8b6b4001aa360d1">
|
13
|
+
<textarea name="name1" class="width:100% padding:0px margin:0px border-width:0px" rows="10"></textarea>
|
14
|
+
<textarea name="name2" class="width:100%" rows="10"></textarea>
|
15
|
+
<iframe name='name2' width="100%" contenteditable></iframe>
|
16
|
+
|
17
|
+
</form>
|
18
|
+
|
19
|
+
<!--<script src="../dist/CoCreate-text.js" ></script>-->
|
20
|
+
<script src="../../../CoCreateJS/dist/CoCreate.js"></script>
|
21
|
+
|
22
|
+
</body>
|
23
|
+
|
24
|
+
</html>
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@cocreate/text",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.14.0",
|
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.10.
|
68
|
-
"@cocreate/docs": "^1.2.
|
69
|
-
"@cocreate/hosting": "^1.2.
|
70
|
-
"@cocreate/observer": "^1.3.
|
71
|
-
"@cocreate/selection": "^1.2.
|
64
|
+
"@cocreate/actions": "^1.3.24",
|
65
|
+
"@cocreate/crdt": "^1.8.27",
|
66
|
+
"@cocreate/crud-client": "^1.4.39",
|
67
|
+
"@cocreate/cursors": "^1.10.18",
|
68
|
+
"@cocreate/docs": "^1.2.61",
|
69
|
+
"@cocreate/hosting": "^1.2.57",
|
70
|
+
"@cocreate/observer": "^1.3.53",
|
71
|
+
"@cocreate/selection": "^1.2.21",
|
72
|
+
"@cocreate/uuid": "^1.1.50"
|
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,11 +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
|
-
console.log(element)
|
23
|
-
});
|
20
|
+
initDocument(document);
|
24
21
|
}
|
25
22
|
|
26
23
|
function initElements (elements) {
|
@@ -39,11 +36,9 @@ function initElement (element) {
|
|
39
36
|
if (!isCrdt) {
|
40
37
|
if (element.tagName == 'IFRAME'){
|
41
38
|
_addEventListeners(element.contentDocument.documentElement);
|
42
|
-
let Document = element.contentDocument
|
43
|
-
Document
|
44
|
-
|
45
|
-
sendPosition(element)
|
46
|
-
}); }
|
39
|
+
let Document = element.contentDocument;
|
40
|
+
initDocument(Document);
|
41
|
+
}
|
47
42
|
else{
|
48
43
|
_addEventListeners(element);
|
49
44
|
}
|
@@ -75,7 +70,30 @@ function initElement (element) {
|
|
75
70
|
}
|
76
71
|
}
|
77
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
|
+
|
78
95
|
export function _addEventListeners (element) {
|
96
|
+
element.addEventListener('mousedown', _mousedown);
|
79
97
|
element.addEventListener('blur', _blur);
|
80
98
|
element.addEventListener('cut', _cut);
|
81
99
|
element.addEventListener('paste', _paste);
|
@@ -84,6 +102,29 @@ export function _addEventListeners (element) {
|
|
84
102
|
element.addEventListener('input', _input);
|
85
103
|
}
|
86
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
|
+
|
87
128
|
function _blur (event) {
|
88
129
|
let element = event.currentTarget;
|
89
130
|
const { collection, document_id, name } = crud.getAttr(element);
|
@@ -182,21 +223,40 @@ function _removeEventListeners (element) {
|
|
182
223
|
element.removeEventListener('beforeinput', _beforeinput);
|
183
224
|
}
|
184
225
|
|
226
|
+
let previousPosition = {};
|
185
227
|
export function sendPosition (element) {
|
228
|
+
// if (!element) return;
|
229
|
+
const { start, end, range } = getSelection(element);
|
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
|
+
}
|
186
238
|
if (!element) return;
|
187
|
-
const { start, end } = getSelection(element);
|
188
|
-
if (element.tagName == 'HTML' && !element.hasAttribute('collection') || !element.hasAttribute('collection'))
|
189
|
-
element = element.ownerDocument.defaultView.frameElement;
|
190
239
|
const { collection, document_id, name, isCrdt } = crud.getAttr(element);
|
191
|
-
if (isCrdt == 'false') return;
|
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;
|
192
246
|
cursors.sendPosition({ collection, document_id, name, start, end });
|
193
247
|
}
|
194
248
|
|
195
249
|
function updateText ({element, value, start, end, range}) {
|
196
|
-
if
|
197
|
-
|
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
|
+
}
|
198
257
|
const { collection, document_id, name, isCrud, isCrdt, isSave } = crud.getAttr(element);
|
199
258
|
if(isCrdt == "false") return;
|
259
|
+
|
200
260
|
let length = end - start;
|
201
261
|
if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
|
202
262
|
crdt.updateText({ collection, document_id, name, value, start, length, crud: isCrud, save: isSave });
|
@@ -260,8 +320,8 @@ async function updateElement ({element, collection, document_id, name, value, st
|
|
260
320
|
}
|
261
321
|
if (value) {
|
262
322
|
if (element.innerHTML != value) {
|
263
|
-
|
264
|
-
updateDom({ domTextEditor, value, start, end: start });
|
323
|
+
// domTextEditor.htmlString = html;
|
324
|
+
updateDom({ domTextEditor, value, start, end: start, html });
|
265
325
|
}
|
266
326
|
}
|
267
327
|
}
|
@@ -310,7 +370,7 @@ observer.init({
|
|
310
370
|
observer.init({
|
311
371
|
name: 'CoCreateTextAttribtes',
|
312
372
|
observe: ['attributes'],
|
313
|
-
attributeName: ['collection', 'document_id', 'name'],
|
373
|
+
attributeName: ['collection', 'document_id', 'name', 'contenteditable'],
|
314
374
|
target: selectors,
|
315
375
|
callback (mutation) {
|
316
376
|
initElement(mutation.target);
|
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;
|
@@ -33,6 +45,8 @@ export function updateDom({domTextEditor, value, start, end, html}) {
|
|
33
45
|
curCaret = getSelection(activeElement);
|
34
46
|
else if (activeElement.tagName == 'BODY')
|
35
47
|
curCaret = getSelection(domEl);
|
48
|
+
else
|
49
|
+
curCaret = getSelection(activeElement);
|
36
50
|
|
37
51
|
if (!value && type != 'isStartTag' && type != 'textNode'){
|
38
52
|
type = 'innerHTML';
|
@@ -67,6 +81,7 @@ export function updateDom({domTextEditor, value, start, end, html}) {
|
|
67
81
|
else if (type == 'innerHTML') {
|
68
82
|
domEl.replaceChildren(...newEl.childNodes);
|
69
83
|
}
|
84
|
+
domTextEditor.htmlString = html;
|
70
85
|
}
|
71
86
|
if(curCaret && start >= 0 && end >= 0) {
|
72
87
|
if (curCaret.range && curCaret.start >= curCaret.range.startOffset) {
|
@@ -95,8 +110,8 @@ export function updateDom({domTextEditor, value, start, end, html}) {
|
|
95
110
|
}
|
96
111
|
}
|
97
112
|
|
98
|
-
function parseHtml(domTextEditor) {
|
99
|
-
var dom = domParser(
|
113
|
+
function parseHtml(domTextEditor, html) {
|
114
|
+
var dom = domParser(html);
|
100
115
|
if (domTextEditor.newHtml) {
|
101
116
|
domTextEditor.oldHtml = domTextEditor.newHtml;
|
102
117
|
} else {
|