@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 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.13.2",
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.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.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.addEventListener('selectionchange', (e) => {
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.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,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 (element.tagName == 'HTML' && !element.hasAttribute('collection'))
196
- 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
+ }
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
- domTextEditor.htmlString = html;
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, 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 {