@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 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.13.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.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.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.addEventListener('selectionchange', (e) => {
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.addEventListener('selectionchange', (e) => {
44
- let element = Document.activeElement;
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 (element.tagName == 'HTML' && !element.hasAttribute('collection'))
197
- 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
+ }
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
- domTextEditor.htmlString = html;
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, 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;
@@ -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(domTextEditor.htmlString);
113
+ function parseHtml(domTextEditor, html) {
114
+ var dom = domParser(html);
100
115
  if (domTextEditor.newHtml) {
101
116
  domTextEditor.oldHtml = domTextEditor.newHtml;
102
117
  } else {