@cocreate/cursors 1.10.18 → 1.11.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,38 @@
1
+ ## [1.11.3](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.11.2...v1.11.3) (2021-12-23)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * if elementActive and clientId is self return ([170ee7a](https://github.com/CoCreate-app/CoCreate-cursors/commit/170ee7a233f32e4fda9010e1ae18b9328489c6ed))
7
+
8
+ ## [1.11.2](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.11.1...v1.11.2) (2021-12-19)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * if pos.start and if pos.path case ([fdf7372](https://github.com/CoCreate-app/CoCreate-cursors/commit/fdf7372a59963548c421edfb080184de61e60e00))
14
+
15
+ ## [1.11.1](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.11.0...v1.11.1) (2021-12-15)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * update dependencies ([186f745](https://github.com/CoCreate-app/CoCreate-cursors/commit/186f74551897f424450a5b3e31df2769d030bf01))
21
+
22
+ # [1.11.0](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.10.18...v1.11.0) (2021-12-14)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * add style top to cursor ([1e6d26c](https://github.com/CoCreate-app/CoCreate-cursors/commit/1e6d26c31919700399b3473a938f49f3cc2978b0))
28
+ * update dependencies ([9895f14](https://github.com/CoCreate-app/CoCreate-cursors/commit/9895f14bf1de1c133f0477134ccb654fb31f79d0))
29
+ * update dependencies ([2307656](https://github.com/CoCreate-app/CoCreate-cursors/commit/2307656877e1936cb8b5d978414df898a1de0b27))
30
+
31
+
32
+ ### Features
33
+
34
+ * multi cursor support between many elements in window.top ([3b2dab9](https://github.com/CoCreate-app/CoCreate-cursors/commit/3b2dab9e1a6886026b7976eed44180d89a70ad83))
35
+
1
36
  ## [1.10.18](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.10.17...v1.10.18) (2021-12-08)
2
37
 
3
38
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/cursors",
3
- "version": "1.10.18",
3
+ "version": "1.11.3",
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,8 +27,7 @@
27
27
  white-space: nowrap;
28
28
  }
29
29
 
30
- .cursor-selection {
31
- position: absolute;
30
+ selected-text {
32
31
  opacity: 0.4;
33
32
  }
34
33
 
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('.cursor-selection');
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,103 +58,155 @@ function drawCursors(selection) {
162
58
  elements = document.querySelectorAll(selector);
163
59
  }
164
60
  for (let element of elements) {
61
+ if (element.activeElement && selection.clientId == clientId) {
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
68
  if (element.hasAttribute('contenteditable')) {
169
69
  let domTextEditor = element;
170
- if (element.tagName == 'IFRAME')
70
+ if (element.tagName == 'IFRAME'){
71
+ let frameClientId = element.contentDocument.defaultView.CoCreateSockets.clientId;
72
+ if (frameClientId == selection.clientId) continue;
171
73
  domTextEditor = element.contentDocument.documentElement;
74
+ }
172
75
  let pos = getElementPosition(domTextEditor.htmlString, start, end);
173
- element = domTextEditor.querySelector(pos.path);
174
- let endPos = end - start;
175
- if (endPos > 0)
176
- end = pos.start + endPos;
177
- else
178
- end = pos.start;
179
- 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
+ }
180
86
  }
181
- if(!element) return;
87
+ if(!element) continue;
182
88
  let document = element.ownerDocument;
89
+ let mirrorDiv;
183
90
  let id_mirror = element.getAttribute('mirror_id');
184
- if (!id_mirror)
185
- element.setAttribute('mirror_id', uuid.generate(8));
186
- id_mirror = element.getAttribute('mirror_id');
187
- let coordinates = getCoordinates(element, start, end);
188
- if (!coordinates) return false;
189
-
190
- let elementMirror = document.getElementById(id_mirror);
191
- let cursor;
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;
192
154
  let details = {collection, document_id, name};
193
155
  if (socket_id) {
194
- let cursores_other_elements = document.querySelectorAll(`.cursor-container[socket_id="${socket_id}"]`);
195
- if (cursores_other_elements) {
196
- for (cursor of cursores_other_elements){
197
- if (cursor.details != details)
198
- 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();
199
161
  }
200
162
  }
201
- cursor = elementMirror.querySelector(`.cursor-container[socket_id="${socket_id}"]`);
202
- if (!cursor) {
203
- let cursor_template = '<div class="cursor-container" socket_id="' + 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;
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);
211
175
  }
212
- }
213
- cursor = elementMirror.querySelector(`.cursor-container[socket_id="${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 cursorFlag = cursor.querySelector('.cursor-flag');
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);
219
186
  cursor.dataset.start = start;
220
187
  cursor.dataset.end = end;
221
188
  cursor.setAttribute('user-name', selection.userName);
222
189
  cursor.setAttribute('user-background', selection.background);
223
190
  cursor.setAttribute('user-color', selection.color);
224
- cursor.style["height"] = cursor_height + "px";
225
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');
226
205
  cursorFlag.style["background"] = selection.background;
227
206
  cursorFlag.innerHTML = selection.userName;
228
- cursor.style["left"] = coordinates.end.left + "px";
229
- cursor.details = {collection, document_id, name};
230
-
231
- let userSelections = document.querySelectorAll(`.cursor-selection[socket_id="${socket_id}"]`);
232
- if (userSelections) {
233
- for (selection of userSelections){
234
- if (selection.details != details)
235
- selection.remove();
236
- }
237
- }
238
- if ((start != end)) {
239
- var scrollwidth = element.offsetWidth - element.scrollWidth;
240
- var padding_right = parseInt(getComputedStyle(element)["paddingRight"]);
241
-
242
- let selection_user = document.createElement('span');
243
- selection_user.id = 'sel-' + socket_id;
244
- selection_user.setAttribute('socket_id', socket_id);
245
- selection_user.className = 'cursor-selection';
246
- let style_mirror = getComputedStyle(elementMirror);
247
- selection_user.style["position"] = "absolute";
248
- selection_user.style["top"] = style_mirror.paddingTop;
249
- selection_user.style["left"] = style_mirror.paddingLeft;
250
- selection_user.style["padding-right"] = scrollwidth + padding_right + "px";
251
- selection_user.details = {collection, document_id, name};
252
- elementMirror.insertBefore(selection_user, elementMirror.firstChild);
253
-
254
- let selection_span_by_user = document.createElement('span');
255
- selection_span_by_user.style.backgroundColor = selection.background;
256
- let value_element = (['TEXTAREA', 'INPUT'].indexOf(element.nodeName) == -1) ? element.innerHTML : element.value;
257
- selection_user.textContent = value_element.substring(0, start);
258
- let value_span_selection = value_element.substring(start, end) || '';
259
- selection_span_by_user.textContent = value_span_selection;
260
- selection_user.appendChild(selection_span_by_user);
261
- }
207
+ cursor.appendChild(cursorFlag);
208
+
209
+ selection_user.appendChild(span_end);
262
210
  }
263
211
  scrollMirror(element);
264
212
  }
@@ -277,9 +225,9 @@ function updateCursors(element) {
277
225
  }
278
226
  for (let mirrorDiv of mirrorDivs) {
279
227
  element = mirrorDiv.element;
280
- let cursor_containers = mirrorDiv.querySelectorAll('.cursor-container');
228
+ let cursors = mirrorDiv.querySelectorAll('cursor');
281
229
 
282
- cursor_containers.forEach(function(child_cursor, index, array) {
230
+ cursors.forEach(function(child_cursor, index, array) {
283
231
  let clientId = child_cursor.getAttribute('socket_id');
284
232
  let userName = child_cursor.getAttribute('user-name');
285
233
  let background = child_cursor.getAttribute('user-background');
@@ -301,12 +249,12 @@ function updateCursors(element) {
301
249
  }
302
250
 
303
251
  function removeCursor(clientId) {
304
- let elements = document.querySelectorAll(`.cursor-container[socket_id="${clientId}"]`);
252
+ let elements = document.querySelectorAll(`cursor[socket_id="${clientId}"]`);
305
253
  elements.forEach(function(element, index, array) {
306
254
  element.parentNode.removeChild(element);
307
255
  });
308
256
 
309
- let sel_elements = document.querySelectorAll('[id*="sel-' + clientId + '"]');
257
+ let sel_elements = document.querySelectorAll(`selection[socket_id="${clientId}"]`);
310
258
  sel_elements.forEach(function(sel_element, index, array) {
311
259
  sel_element.parentNode.removeChild(sel_element);
312
260
  });
@@ -365,7 +313,7 @@ function sendPosition(info) {
365
313
 
366
314
 
367
315
  message.listen('cursor', function(selection) {
368
- if (selection.clientId == clientId) return;
316
+ // if (selection.clientId == clientId) return;
369
317
  if (selection.start != null && selection.end != null)
370
318
  drawCursors(selection);
371
319
  else