@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 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.13.4",
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.23",
65
- "@cocreate/crdt": "^1.8.26",
66
- "@cocreate/crud-client": "^1.4.38",
67
- "@cocreate/cursors": "^1.10.16",
68
- "@cocreate/docs": "^1.2.60",
69
- "@cocreate/hosting": "^1.2.56",
70
- "@cocreate/observer": "^1.3.52",
71
- "@cocreate/selection": "^1.2.19"
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.addEventListener('selectionchange', (e) => {
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) && !crud.checkAttrValue(document_id)) return;
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.addEventListener('selectionchange', (e) => {
43
- let element = Document.activeElement;
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 && range.element)
189
- element = range.element;
190
- if (element.tagName == 'HTML' && !element.hasAttribute('collection') || !element.hasAttribute('collection'))
191
- element = element.ownerDocument.defaultView.frameElement;
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 && range.element)
200
- element = range.element;
201
- if (element.tagName == 'HTML' && !element.hasAttribute('collection'))
202
- element = element.ownerDocument.defaultView.frameElement;
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
- domTextEditor.htmlString = html;
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, newEl = element, oldEl, curCaret;
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(domTextEditor.htmlString);
113
+ function parseHtml(domTextEditor, html) {
114
+ var dom = domParser(html);
102
115
  if (domTextEditor.newHtml) {
103
116
  domTextEditor.oldHtml = domTextEditor.newHtml;
104
117
  } else {