@cocreate/text 1.13.2 → 1.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/demo/demos.1.html +24 -0
- package/package.json +10 -9
- package/src/index.js +79 -18
- package/src/updateDom.js +19 -4
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
## [1.14.1](https://github.com/CoCreate-app/CoCreate-text/compare/v1.14.0...v1.14.1) (2021-12-14)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* update dependencies ([423ec14](https://github.com/CoCreate-app/CoCreate-text/commit/423ec14a075157e1b525956e45428d1ea75da72e))
|
7
|
+
|
8
|
+
# [1.14.0](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.4...v1.14.0) (2021-12-14)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* update dependencies ([4d71711](https://github.com/CoCreate-app/CoCreate-text/commit/4d71711bedf21a3dfa4f28e54b568362d919b535))
|
14
|
+
|
15
|
+
|
16
|
+
### Features
|
17
|
+
|
18
|
+
* support nested contenteditable and cursor positions ([30cc76d](https://github.com/CoCreate-app/CoCreate-text/commit/30cc76d669203e6b55e271e2a3b26398e9764359))
|
19
|
+
|
20
|
+
## [1.13.4](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.3...v1.13.4) (2021-12-08)
|
21
|
+
|
22
|
+
|
23
|
+
### Bug Fixes
|
24
|
+
|
25
|
+
* observer attribute contenteditable, get element to update using selection range.element ([2bb32bf](https://github.com/CoCreate-app/CoCreate-text/commit/2bb32bf5650505c76efb44d2f941b1b249deaebf))
|
26
|
+
|
27
|
+
## [1.13.3](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.2...v1.13.3) (2021-11-29)
|
28
|
+
|
29
|
+
|
30
|
+
### Bug Fixes
|
31
|
+
|
32
|
+
* sendPosition if no element return ([fec4fbb](https://github.com/CoCreate-app/CoCreate-text/commit/fec4fbb20b574af0995f1f49ad16501a83c52b98))
|
33
|
+
|
1
34
|
## [1.13.2](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.1...v1.13.2) (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.1",
|
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.
|
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.3.0",
|
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,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) {
|
@@ -38,11 +36,9 @@ function initElement (element) {
|
|
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,21 +223,40 @@ function _removeEventListeners (element) {
|
|
181
223
|
element.removeEventListener('beforeinput', _beforeinput);
|
182
224
|
}
|
183
225
|
|
226
|
+
let previousPosition = {};
|
184
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
|
+
}
|
185
238
|
if (!element) return;
|
186
|
-
const { start, end } = getSelection(element);
|
187
|
-
if (element.tagName == 'HTML' && !element.hasAttribute('collection') || !element.hasAttribute('collection'))
|
188
|
-
element = element.ownerDocument.defaultView.frameElement;
|
189
239
|
const { collection, document_id, name, isCrdt } = crud.getAttr(element);
|
190
|
-
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;
|
191
246
|
cursors.sendPosition({ collection, document_id, name, start, end });
|
192
247
|
}
|
193
248
|
|
194
249
|
function updateText ({element, value, start, end, range}) {
|
195
|
-
if
|
196
|
-
|
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
|
+
}
|
197
257
|
const { collection, document_id, name, isCrud, isCrdt, isSave } = crud.getAttr(element);
|
198
258
|
if(isCrdt == "false") return;
|
259
|
+
|
199
260
|
let length = end - start;
|
200
261
|
if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
|
201
262
|
crdt.updateText({ collection, document_id, name, value, start, length, crud: isCrud, save: isSave });
|
@@ -259,8 +320,8 @@ async function updateElement ({element, collection, document_id, name, value, st
|
|
259
320
|
}
|
260
321
|
if (value) {
|
261
322
|
if (element.innerHTML != value) {
|
262
|
-
|
263
|
-
updateDom({ domTextEditor, value, start, end: start });
|
323
|
+
// domTextEditor.htmlString = html;
|
324
|
+
updateDom({ domTextEditor, value, start, end: start, html });
|
264
325
|
}
|
265
326
|
}
|
266
327
|
}
|
@@ -309,7 +370,7 @@ observer.init({
|
|
309
370
|
observer.init({
|
310
371
|
name: 'CoCreateTextAttribtes',
|
311
372
|
observe: ['attributes'],
|
312
|
-
attributeName: ['collection', 'document_id', 'name'],
|
373
|
+
attributeName: ['collection', 'document_id', 'name', 'contenteditable'],
|
313
374
|
target: selectors,
|
314
375
|
callback (mutation) {
|
315
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 {
|