@cocreate/cursors 1.10.17 → 1.11.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,39 @@
1
+ ## [1.11.2](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.11.1...v1.11.2) (2021-12-19)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * if pos.start and if pos.path case ([fdf7372](https://github.com/CoCreate-app/CoCreate-cursors/commit/fdf7372a59963548c421edfb080184de61e60e00))
7
+
8
+ ## [1.11.1](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.11.0...v1.11.1) (2021-12-15)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * update dependencies ([186f745](https://github.com/CoCreate-app/CoCreate-cursors/commit/186f74551897f424450a5b3e31df2769d030bf01))
14
+
15
+ # [1.11.0](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.10.18...v1.11.0) (2021-12-14)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * add style top to cursor ([1e6d26c](https://github.com/CoCreate-app/CoCreate-cursors/commit/1e6d26c31919700399b3473a938f49f3cc2978b0))
21
+ * update dependencies ([9895f14](https://github.com/CoCreate-app/CoCreate-cursors/commit/9895f14bf1de1c133f0477134ccb654fb31f79d0))
22
+ * update dependencies ([2307656](https://github.com/CoCreate-app/CoCreate-cursors/commit/2307656877e1936cb8b5d978414df898a1de0b27))
23
+
24
+
25
+ ### Features
26
+
27
+ * multi cursor support between many elements in window.top ([3b2dab9](https://github.com/CoCreate-app/CoCreate-cursors/commit/3b2dab9e1a6886026b7976eed44180d89a70ad83))
28
+
29
+ ## [1.10.18](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.10.17...v1.10.18) (2021-12-08)
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * check contenteditable element then iframe ([29bd7b4](https://github.com/CoCreate-app/CoCreate-cursors/commit/29bd7b4e7460c478cec37916fe9bb7439d2b8805))
35
+ * use attribute for socket_id instead of id ([db901da](https://github.com/CoCreate-app/CoCreate-cursors/commit/db901daa270551cd6b1b6b95124d785ed81643c9))
36
+
1
37
  ## [1.10.17](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.10.16...v1.10.17) (2021-11-27)
2
38
 
3
39
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/cursors",
3
- "version": "1.10.17",
3
+ "version": "1.11.2",
4
4
  "description": "Collaborative user cursor position for inputs, textarea's and contenteditable elements.",
5
5
  "keywords": [
6
6
  "cursors",
@@ -62,12 +62,12 @@
62
62
  "webpack-log": "^3.0.1"
63
63
  },
64
64
  "dependencies": {
65
- "@cocreate/crud-client": "^1.4.38",
66
- "@cocreate/docs": "^1.2.60",
67
- "@cocreate/message-client": "^1.1.56",
68
- "@cocreate/observer": "^1.3.52",
69
- "@cocreate/random-color": "^1.2.13",
70
- "@cocreate/selection": "^1.2.19",
71
- "@cocreate/uuid": "^1.1.49"
65
+ "@cocreate/crud-client": "^1.4.40",
66
+ "@cocreate/docs": "^1.2.62",
67
+ "@cocreate/message-client": "^1.1.58",
68
+ "@cocreate/observer": "^1.3.54",
69
+ "@cocreate/random-color": "^1.2.15",
70
+ "@cocreate/selection": "^1.3.1",
71
+ "@cocreate/uuid": "^1.1.51"
72
72
  }
73
73
  }
package/src/index.css CHANGED
@@ -1,4 +1,4 @@
1
- .cursor-container {
1
+ cursor {
2
2
  position: absolute;
3
3
  display: inline-block;
4
4
  width: 2px;
@@ -6,7 +6,7 @@
6
6
  /*z-index:10;*/
7
7
  }
8
8
 
9
- .cursor-flag {
9
+ cursor-flag {
10
10
  position: absolute;
11
11
  background-color: inherit;
12
12
  top: 0px;
@@ -18,7 +18,7 @@
18
18
  pointer-events: auto;
19
19
  }
20
20
 
21
- .cursor-flag:hover {
21
+ cursor-flag:hover {
22
22
  height: 14px;
23
23
  width: unset;
24
24
  padding: 1px 5px 0px 5px;
@@ -27,13 +27,8 @@
27
27
  white-space: nowrap;
28
28
  }
29
29
 
30
- .selection {
31
- background-color: #ecd44;
32
- opacity: 0.6;
33
- }
34
-
35
- .cursor-selection {
36
- position: absolute;
30
+ selected-text {
31
+ opacity: 0.4;
37
32
  }
38
33
 
39
34
  .mirror {
@@ -49,7 +44,3 @@
49
44
  background: rgba(0, 0, 0, 0.00);
50
45
  width: 0px;
51
46
  }
52
-
53
- .users_selections {
54
- opacity: 0.4;
55
- }
package/src/index.js CHANGED
@@ -10,7 +10,6 @@ const clientId = window.CoCreateSockets.clientId || uuid.generate(12);
10
10
  const cursorBackground = randomColor();
11
11
 
12
12
  let enviroment_prod = true;
13
- let documents = new Map();
14
13
 
15
14
  let selector = "[collection][document_id][name]:not([contentEditable='false'])";
16
15
 
@@ -34,120 +33,17 @@ function initElement(element) {
34
33
  }
35
34
 
36
35
  function initDocument(doc) {
37
- if (!documents.has(doc.window)) {
36
+ let documents = window.top.cursorDocuments;
37
+ if (!documents){
38
+ documents = new Map();
39
+ window.top.cursorDocuments = documents;
40
+ }
41
+ if (!documents.has(doc)) {
38
42
  initResizeObserver(doc.documentElement);
39
43
  documents.set(doc);
40
44
  }
41
45
  }
42
46
 
43
- var getCoordinates = function(element, position_start, position_end) {
44
- var mirrorDiv;
45
- let ID_MIRROR = element.getAttribute('mirror_id');
46
- let document = element.ownerDocument;
47
- mirrorDiv = document.getElementById(ID_MIRROR);
48
-
49
- if (!mirrorDiv) {
50
- mirrorDiv = document.createElement('div');
51
- mirrorDiv.id = ID_MIRROR;
52
- mirrorDiv.className = (enviroment_prod) ? 'mirror mirror_scroll mirror_color' : 'mirror mirror_scroll';
53
- mirrorDiv.contentEditable = false;
54
- mirrorDiv.element = element;
55
- element.insertAdjacentElement('afterend', mirrorDiv);
56
- _initEvents(element);
57
- initDocument(document);
58
- }
59
-
60
- let computed = getComputedStyle(element);
61
- let rect = element.getBoundingClientRect();
62
- let scrollBarWidth = 0;
63
- if (element.clientWidth != 0)
64
- scrollBarWidth = element.offsetWidth - element.clientWidth;
65
- let style = mirrorDiv.style;
66
-
67
- style.position = 'absolute';
68
- style.top = element.offsetTop + 'px';
69
- style.left = element.offsetLeft + 'px';
70
- style.width = rect.width + 'px';
71
- style.height = rect.height + 'px';
72
- style.visibility = 'visible';
73
- style.overflowX = computed['overflowX'];
74
- style.overflowY = computed['overflowY'];
75
- style.margin = '0px';
76
- style.paddingRight = parseInt(computed['paddingRight']) + scrollBarWidth + 'px';
77
- style.border = computed['border'];
78
- style.borderColor = 'transparent';
79
-
80
- if (element.nodeName !== 'INPUT') {
81
- style.wordWrap = 'break-word';
82
- style.whiteSpace = 'pre-wrap';
83
- }
84
- else {
85
- style.whiteSpace = 'pre';
86
- }
87
-
88
- let properties = ['boxSizing', 'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'paddingTop', 'paddingBottom', 'paddingLeft', 'fontStyle', 'fontVariant', 'fontWeight', 'fontStretch', 'fontSize', 'lineHeight', 'fontFamily', 'textAlign', 'textTransform', 'textIndent', 'textDecoration', 'letterSpacing', 'wordSpacing', 'textRendering', 'webkitWritingMode', 'textTransform', 'textIndent', 'overflowWrap'];
89
-
90
- properties.forEach(function(prop) {
91
- if (['left', 'top'].indexOf(prop.toLowerCase()) === -1)
92
- style[prop] = computed[prop];
93
- });
94
-
95
-
96
- let cursor_container = mirrorDiv.querySelectorAll('.cursor-container');
97
- let users_selections = mirrorDiv.querySelectorAll('.users_selections');
98
-
99
- let value_element = (['TEXTAREA', 'INPUT'].indexOf(element.nodeName) == -1) ? element.innerHTML : element.value;
100
- mirrorDiv.textContent = value_element.substring(0, position_start);
101
-
102
- if (element.nodeName === 'INPUT')
103
- mirrorDiv.textContent = mirrorDiv.textContent.replace(/\s/g, " ");
104
-
105
-
106
- var span = document.createElement('span');
107
- span.id = element.nodeName + 'span_selections';
108
- let value_span = value_element.substring(position_start, position_end) || '';
109
- span.textContent = value_span;
110
- mirrorDiv.appendChild(span);
111
-
112
- if (cursor_container) {
113
- cursor_container.forEach(function(child_cursor, index, array) {
114
- mirrorDiv.appendChild(child_cursor);
115
- });
116
- }
117
-
118
- if (users_selections) {
119
- users_selections.forEach(function(child_selection, index, array) {
120
- mirrorDiv.appendChild(child_selection);
121
- });
122
- }
123
-
124
- // create mirror text end
125
- let value_end = value_element.substring(position_end) || '';
126
- var span_end = document.createElement('span');
127
- mirrorDiv.appendChild(span_end);
128
- span_end.textContent = value_end;
129
-
130
-
131
- var coordinates = {
132
- start: {
133
- top: span.offsetTop,
134
- left: span.offsetLeft
135
- },
136
- end: {
137
- top: span_end.offsetTop,
138
- left: span_end.offsetLeft
139
- }
140
- };
141
-
142
- return coordinates;
143
- };
144
-
145
- function getStyle(el, styleProp) {
146
- if (window.getComputedStyle)
147
- var y = document.defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
148
- return y;
149
- }
150
-
151
47
  function drawCursors(selection) {
152
48
  const socket_id = selection['clientId'];
153
49
  const collection = selection['collection'];
@@ -162,99 +58,155 @@ function drawCursors(selection) {
162
58
  elements = document.querySelectorAll(selector);
163
59
  }
164
60
  for (let element of elements) {
61
+ if (element.activeElement) {
62
+ element.activeElement = '';
63
+ continue;
64
+ }
165
65
  let realtime = element.getAttribute('realtime');
166
66
  let cursors = element.getAttribute('cursors');
167
67
  if (realtime == 'false' || cursors == 'false') continue;
168
- if (element.tagName == 'IFRAME') {
169
- let domTextEditor = element.contentDocument.documentElement;
68
+ if (element.hasAttribute('contenteditable')) {
69
+ let domTextEditor = element;
70
+ if (element.tagName == 'IFRAME'){
71
+ let frameClientId = element.contentDocument.defaultView.CoCreateSockets.clientId;
72
+ if (frameClientId == selection.clientId) continue;
73
+ domTextEditor = element.contentDocument.documentElement;
74
+ }
170
75
  let pos = getElementPosition(domTextEditor.htmlString, start, end);
171
- element = domTextEditor.querySelector(pos.path);
172
- let endPos = end - start;
173
- if (endPos > 0)
174
- end = pos.start + endPos;
175
- else
176
- end = pos.start;
177
- start = pos.start;
76
+ if (pos.start){
77
+ if(pos.path)
78
+ element = domTextEditor.querySelector(pos.path);
79
+ let endPos = end - start;
80
+ if (endPos > 0)
81
+ end = pos.start + endPos;
82
+ else
83
+ end = pos.start;
84
+ start = pos.start;
85
+ }
178
86
  }
179
- if(!element) return;
87
+ if(!element) continue;
180
88
  let document = element.ownerDocument;
89
+ let mirrorDiv;
181
90
  let id_mirror = element.getAttribute('mirror_id');
182
- if (!id_mirror)
183
- element.setAttribute('mirror_id', uuid.generate(8));
184
- id_mirror = element.getAttribute('mirror_id');
185
- let coordinates = getCoordinates(element, start, end);
186
- if (!coordinates) return false;
187
-
188
- let elementMirror = document.getElementById(id_mirror);
189
- let cursor;
190
- // let selection_user = false;
191
- // let user = (typeof(selection) != 'undefined' && selection.hasOwnProperty('user')) ? selection.user : false;
192
- // let user_id = (typeof(selection) != 'undefined' && selection.hasOwnProperty('user_id')) ? user.user_id : false;
91
+ if (!id_mirror){
92
+ id_mirror = uuid.generate(8);
93
+ element.setAttribute('mirror_id', id_mirror);
94
+
95
+ mirrorDiv = document.createElement('cursor-container');
96
+ mirrorDiv.id = id_mirror;
97
+ mirrorDiv.className = (enviroment_prod) ? 'mirror mirror_scroll mirror_color' : 'mirror mirror_scroll';
98
+ mirrorDiv.contentEditable = false;
99
+ mirrorDiv.element = element;
100
+ element.insertAdjacentElement('afterend', mirrorDiv);
101
+ _initEvents(element);
102
+ initDocument(document);
103
+ }
104
+ else
105
+ mirrorDiv = document.getElementById(id_mirror);
106
+
107
+ let computed = getComputedStyle(element);
108
+ let rect = element.getBoundingClientRect();
109
+ let borderWidth = parseInt(computed['border-width']) * 2;
110
+ let scrollBarWidth = 0;
111
+ if (element.clientWidth != 0)
112
+ scrollBarWidth = element.offsetWidth - element.clientWidth - borderWidth;
113
+ let style = mirrorDiv.style;
114
+
115
+ style.position = 'absolute';
116
+ style.top = element.offsetTop + 'px';
117
+ style.left = element.offsetLeft + 'px';
118
+ style.width = rect.width + 'px';
119
+ style.height = rect.height + 'px';
120
+ style.visibility = 'visible';
121
+ style.overflowX = computed['overflowX'];
122
+ style.overflowY = computed['overflowY'];
123
+ style.margin = '0px';
124
+ style.paddingRight = parseInt(computed['paddingRight']) + scrollBarWidth + 'px';
125
+ style.border = computed['border'];
126
+ style.borderColor = 'transparent';
127
+
128
+ if (element.nodeName !== 'INPUT') {
129
+ style.wordWrap = 'break-word';
130
+ style.whiteSpace = 'pre-wrap';
131
+ }
132
+ else {
133
+ style.whiteSpace = 'pre';
134
+ }
135
+
136
+ let properties = ['boxSizing', 'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'paddingTop', 'paddingBottom', 'paddingLeft', 'fontStyle', 'fontVariant', 'fontWeight', 'fontStretch', 'fontSize', 'lineHeight', 'fontFamily', 'textAlign', 'textTransform', 'textIndent', 'textDecoration', 'letterSpacing', 'wordSpacing', 'textRendering', 'webkitWritingMode', 'textTransform', 'textIndent', 'overflowWrap'];
137
+
138
+ properties.forEach(function(prop) {
139
+ if (['left', 'top'].indexOf(prop.toLowerCase()) === -1)
140
+ style[prop] = computed[prop];
141
+ });
142
+
143
+ let spanText = mirrorDiv.querySelector('span-text');
144
+ if (!spanText)
145
+ spanText = document.createElement('span-text');
146
+ spanText.style['display'] = 'block';
147
+ let value_element = (['TEXTAREA', 'INPUT'].indexOf(element.nodeName) == -1) ? element.innerHTML : element.value;
148
+
149
+ spanText.textContent = value_element;
150
+ if (element.nodeName === 'INPUT')
151
+ spanText.textContent = mirrorDiv.textContent.replace(/\s/g, " ");
152
+ mirrorDiv.appendChild(spanText);
153
+ let cursor, cursorFlag;
154
+ let details = {collection, document_id, name};
193
155
  if (socket_id) {
194
- var cursores_other_elements = document.querySelectorAll('#socket_' + socket_id);
195
- cursores_other_elements.forEach(function(child_cursor, index, array) {
196
- if (child_cursor.parentElement.getAttribute('id') != id_mirror) {
197
- child_cursor.remove();
156
+ let userSelections = document.querySelectorAll(`selection[socket_id="${socket_id}"]`);
157
+ if (userSelections) {
158
+ for (let userSelection of userSelections){
159
+ if (userSelection.details != details)
160
+ userSelection.remove();
198
161
  }
199
- });
200
- cursor = elementMirror.querySelector('.cursor-container#socket_' + socket_id);
201
- if (!cursor) {
202
- let cursor_template = '<div class="cursor-container" \
203
- id="socket_' + socket_id + '" \
204
- style="background-color:' + selection.background + '"> \
205
- <div class="cursor-flag" \
206
- collection="users" \
207
- document_id="' + selection.user_id + '" \
208
- name="name">' + selection.userName + '</div>\
209
- </div>';
210
- elementMirror.innerHTML = cursor_template + elementMirror.innerHTML;
211
162
  }
212
- }
213
- cursor = elementMirror.querySelector('.cursor-container#socket_' + socket_id);
214
- if (cursor) {
215
- let font_size = getStyle(element, 'font-size');
216
- font_size = parseFloat(font_size.substring(0, font_size.length - 2));
217
- let cursor_height = ((font_size * 112.5) / 100);
218
- // let my_cursor = cursor.querySelector('.cursor');
219
- let cursorFlag = cursor.querySelector('.cursor-flag');
163
+ let selection_user = mirrorDiv.querySelector(`selection[socket_id="${socket_id}"]`);
164
+ if (!selection_user){
165
+ selection_user = document.createElement('selection');
166
+ selection_user.setAttribute('socket_id', socket_id);
167
+ selection_user.style["position"] = "absolute";
168
+ let style_mirror = getComputedStyle(mirrorDiv);
169
+ selection_user.style["top"] = style_mirror.paddingTop;
170
+ selection_user.style["left"] = style_mirror.paddingLeft;
171
+ selection_user.style["width"] = mirrorDiv.clientWidth - parseInt(computed['padding-left']) - parseInt(computed['padding-right']) - scrollBarWidth + 'px';
172
+ selection_user.details = {collection, document_id, name};
173
+
174
+ mirrorDiv.appendChild(selection_user);
175
+ }
176
+
177
+ let value_element = (['TEXTAREA', 'INPUT'].indexOf(element.nodeName) == -1) ? element.innerHTML : element.value;
178
+ selection_user.textContent = value_element.substring(0, start);
179
+
180
+ let value_end = value_element.substring(end) || '';
181
+ let span_end = document.createElement('span-end');
182
+ span_end.textContent = value_end;
183
+
184
+ cursor = document.createElement('cursor');
185
+ cursor.setAttribute('socket_id', socket_id);
220
186
  cursor.dataset.start = start;
221
187
  cursor.dataset.end = end;
222
- cursor.setAttribute('socket_id', socket_id);
223
188
  cursor.setAttribute('user-name', selection.userName);
224
189
  cursor.setAttribute('user-background', selection.background);
225
190
  cursor.setAttribute('user-color', selection.color);
226
- cursor.style["height"] = cursor_height + "px";
227
191
  cursor.style["background"] = selection.background;
192
+ cursor.details = {collection, document_id, name};
193
+ cursor.textContent = "1";
194
+ span_end.prepend(cursor);
195
+
196
+ let selectedText = document.createElement('selected-text');
197
+ selectedText.style["backgroundColor"] = selection.background;
198
+ selectedText.textContent = value_element.substring(start, end) || '';
199
+ span_end.prepend(selectedText);
200
+
201
+ cursorFlag = document.createElement('cursor-flag');
202
+ cursorFlag.setAttribute('collection', 'users');
203
+ cursorFlag.setAttribute('document_id', selection.user_id);
204
+ cursorFlag.setAttribute('name', 'name');
228
205
  cursorFlag.style["background"] = selection.background;
229
206
  cursorFlag.innerHTML = selection.userName;
230
- cursor.style["left"] = coordinates.end.left + "px";
231
-
232
- let selection_user = document.getElementById('sel-' + socket_id);
233
- if (selection_user) {
234
- selection_user.remove();
235
- }
236
- if ((start != end)) {
237
- var scrollwidth = element.offsetWidth - element.scrollWidth;
238
- var padding_right = parseInt(getComputedStyle(element)["paddingRight"]);
239
-
240
- selection_user = document.createElement('span');
241
- selection_user.id = 'sel-' + socket_id;
242
- selection_user.className = 'users_selections';
243
- let style_mirror = getComputedStyle(elementMirror);
244
- selection_user.style["position"] = "absolute";
245
- selection_user.style["top"] = style_mirror.paddingTop;
246
- selection_user.style["left"] = style_mirror.paddingLeft;
247
- selection_user.style["padding-right"] = scrollwidth + padding_right + "px";
248
- elementMirror.insertBefore(selection_user, elementMirror.firstChild);
249
- let selection_span_by_user = document.createElement('span');
250
- selection_span_by_user.id = 'selection-' + socket_id;
251
- selection_span_by_user.style.backgroundColor = selection.background;
252
- let value_element = (['TEXTAREA', 'INPUT'].indexOf(element.nodeName) == -1) ? element.innerHTML : element.value;
253
- selection_user.textContent = value_element.substring(0, start);
254
- let value_span_selection = value_element.substring(start, end) || '';
255
- selection_span_by_user.textContent = value_span_selection;
256
- selection_user.appendChild(selection_span_by_user);
257
- }
207
+ cursor.appendChild(cursorFlag);
208
+
209
+ selection_user.appendChild(span_end);
258
210
  }
259
211
  scrollMirror(element);
260
212
  }
@@ -273,9 +225,9 @@ function updateCursors(element) {
273
225
  }
274
226
  for (let mirrorDiv of mirrorDivs) {
275
227
  element = mirrorDiv.element;
276
- let cursor_containers = mirrorDiv.querySelectorAll('.cursor-container');
228
+ let cursors = mirrorDiv.querySelectorAll('cursor');
277
229
 
278
- cursor_containers.forEach(function(child_cursor, index, array) {
230
+ cursors.forEach(function(child_cursor, index, array) {
279
231
  let clientId = child_cursor.getAttribute('socket_id');
280
232
  let userName = child_cursor.getAttribute('user-name');
281
233
  let background = child_cursor.getAttribute('user-background');
@@ -297,12 +249,12 @@ function updateCursors(element) {
297
249
  }
298
250
 
299
251
  function removeCursor(clientId) {
300
- let elements = document.querySelectorAll('[id*="socket_' + clientId + '"]');
252
+ let elements = document.querySelectorAll(`cursor[socket_id="${clientId}"]`);
301
253
  elements.forEach(function(element, index, array) {
302
254
  element.parentNode.removeChild(element);
303
255
  });
304
256
 
305
- let sel_elements = document.querySelectorAll('[id*="sel-' + clientId + '"]');
257
+ let sel_elements = document.querySelectorAll(`selection[socket_id="${clientId}"]`);
306
258
  sel_elements.forEach(function(sel_element, index, array) {
307
259
  sel_element.parentNode.removeChild(sel_element);
308
260
  });
@@ -361,7 +313,7 @@ function sendPosition(info) {
361
313
 
362
314
 
363
315
  message.listen('cursor', function(selection) {
364
- if (selection.clientId == clientId) return;
316
+ // if (selection.clientId == clientId) return;
365
317
  if (selection.start != null && selection.end != null)
366
318
  drawCursors(selection);
367
319
  else