@cocreate/text 1.13.3 → 1.14.2

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.2](https://github.com/CoCreate-app/CoCreate-text/compare/v1.14.1...v1.14.2) (2021-12-15)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * update dependencies ([4280fbe](https://github.com/CoCreate-app/CoCreate-text/commit/4280fbef8700fc9cd7cfb39e2737561f04921ee4))
7
+
8
+ ## [1.14.1](https://github.com/CoCreate-app/CoCreate-text/compare/v1.14.0...v1.14.1) (2021-12-14)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * update dependencies ([423ec14](https://github.com/CoCreate-app/CoCreate-text/commit/423ec14a075157e1b525956e45428d1ea75da72e))
14
+
15
+ # [1.14.0](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.4...v1.14.0) (2021-12-14)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * update dependencies ([4d71711](https://github.com/CoCreate-app/CoCreate-text/commit/4d71711bedf21a3dfa4f28e54b568362d919b535))
21
+
22
+
23
+ ### Features
24
+
25
+ * support nested contenteditable and cursor positions ([30cc76d](https://github.com/CoCreate-app/CoCreate-text/commit/30cc76d669203e6b55e271e2a3b26398e9764359))
26
+
27
+ ## [1.13.4](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.3...v1.13.4) (2021-12-08)
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * observer attribute contenteditable, get element to update using selection range.element ([2bb32bf](https://github.com/CoCreate-app/CoCreate-text/commit/2bb32bf5650505c76efb44d2f941b1b249deaebf))
33
+
1
34
  ## [1.13.3](https://github.com/CoCreate-app/CoCreate-text/compare/v1.13.2...v1.13.3) (2021-11-29)
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.3",
3
+ "version": "1.14.2",
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) {
@@ -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,22 +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
- const { start, end } = getSelection(element);
187
- if (element.tagName == 'HTML' && !element.hasAttribute('collection') || !element.hasAttribute('collection'))
188
- element = element.ownerDocument.defaultView.frameElement;
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
+ }
189
238
  if (!element) return;
190
239
  const { collection, document_id, name, isCrdt } = crud.getAttr(element);
191
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 {