@cocreate/cursors 1.23.4 → 1.23.5
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 +15 -0
- package/demo/index.html +1 -3
- package/docs/index.html +9 -23
- package/package.json +8 -8
- package/src/index.css +10 -2
- package/src/index.js +158 -74
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [1.23.5](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.23.4...v1.23.5) (2024-06-12)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* bump cocreate dependencies ([004badc](https://github.com/CoCreate-app/CoCreate-cursors/commit/004badc58b9eaec4b3b7c9e7f4a6933da5420121))
|
|
7
|
+
* contenteditable element selections ([8f16a74](https://github.com/CoCreate-app/CoCreate-cursors/commit/8f16a7465c027e78b63fa450675877ac827fcdc8))
|
|
8
|
+
* cursor selections on contenteditable elements ([8fc58e0](https://github.com/CoCreate-app/CoCreate-cursors/commit/8fc58e0dce113844876858244160de6c1ed3efaf))
|
|
9
|
+
* fix cursors and selection between contenteditable and textareas ([2e12fec](https://github.com/CoCreate-app/CoCreate-cursors/commit/2e12fece9f37a54d82731ef59bf03536b845a3b0))
|
|
10
|
+
* improved handling of contenteditable cursors using innerHtml ([36b0b40](https://github.com/CoCreate-app/CoCreate-cursors/commit/36b0b4073eb46763dfec1d955aae2cdcf707430c))
|
|
11
|
+
* improved whitespace handling ([0fe857e](https://github.com/CoCreate-app/CoCreate-cursors/commit/0fe857ef526b19e65f524ca2b0adc88bc6f807eb))
|
|
12
|
+
* set transparent!important ([e728c56](https://github.com/CoCreate-app/CoCreate-cursors/commit/e728c5692d5022d839e41375339089e93da3bb3c))
|
|
13
|
+
* svg icon class ([b7512a5](https://github.com/CoCreate-app/CoCreate-cursors/commit/b7512a5d272dfb62e0a4537c96c426f879b73340))
|
|
14
|
+
* use framId to determin if should continue element loop ([bb865cf](https://github.com/CoCreate-app/CoCreate-cursors/commit/bb865cf859a0ae319f45330bec9ba8532ab5cd91))
|
|
15
|
+
|
|
1
16
|
## [1.23.4](https://github.com/CoCreate-app/CoCreate-cursors/compare/v1.23.3...v1.23.4) (2024-04-29)
|
|
2
17
|
|
|
3
18
|
|
package/demo/index.html
CHANGED
package/docs/index.html
CHANGED
|
@@ -72,41 +72,31 @@
|
|
|
72
72
|
href="https://github.com/CoCreate-app/CoCreate-cursor"
|
|
73
73
|
target="_blank"
|
|
74
74
|
class="margin-right:15px"
|
|
75
|
-
><i
|
|
76
|
-
class="height:20px fill:#505050"
|
|
77
|
-
src="/assets/svg/github.svg"></i
|
|
75
|
+
><i src="/assets/svg/github.svg"></i
|
|
78
76
|
></a>
|
|
79
77
|
<a
|
|
80
78
|
class="margin-right:15px share"
|
|
81
79
|
share-network="twitter"
|
|
82
80
|
title="Share on twitter"
|
|
83
|
-
><i
|
|
84
|
-
class="height:20px fill:#505050"
|
|
85
|
-
src="/assets/svg/twitter.svg"></i
|
|
81
|
+
><i src="/assets/svg/twitter.svg"></i
|
|
86
82
|
></a>
|
|
87
83
|
<a
|
|
88
84
|
class="margin-right:15px share"
|
|
89
85
|
share-network="facebook"
|
|
90
86
|
title="Share on Facebook"
|
|
91
|
-
><i
|
|
92
|
-
class="height:20px fill:#505050"
|
|
93
|
-
src="/assets/svg/facebook.svg"></i
|
|
87
|
+
><i src="/assets/svg/facebook.svg"></i
|
|
94
88
|
></a>
|
|
95
89
|
<a
|
|
96
90
|
class="margin-right:15px share"
|
|
97
91
|
share-network="instagram"
|
|
98
92
|
title="Share on instagram"
|
|
99
|
-
><i
|
|
100
|
-
class="height:20px fill:#505050"
|
|
101
|
-
src="/assets/svg/instagram.svg"></i
|
|
93
|
+
><i src="/assets/svg/instagram.svg"></i
|
|
102
94
|
></a>
|
|
103
95
|
<a
|
|
104
96
|
class="margin-right:15px share"
|
|
105
97
|
share-network="share"
|
|
106
98
|
title="Share on share"
|
|
107
|
-
><i
|
|
108
|
-
class="height:20px fill:#505050"
|
|
109
|
-
src="/assets/svg/share-alt.svg"></i
|
|
99
|
+
><i src="/assets/svg/share-alt.svg"></i
|
|
110
100
|
></a>
|
|
111
101
|
</div>
|
|
112
102
|
</div>
|
|
@@ -223,7 +213,7 @@
|
|
|
223
213
|
toggle="code-height"
|
|
224
214
|
toggle-selector="#demo-code"
|
|
225
215
|
><i
|
|
226
|
-
class="height:18px
|
|
216
|
+
class="height:18px"
|
|
227
217
|
src="/assets/svg/eye.svg"></i
|
|
228
218
|
></a>
|
|
229
219
|
<a
|
|
@@ -234,18 +224,14 @@
|
|
|
234
224
|
hide="#eye-slash"
|
|
235
225
|
toggle="code-height"
|
|
236
226
|
toggle-selector="#demo-code"
|
|
237
|
-
><i
|
|
238
|
-
class="height:20px fill:#505050"
|
|
239
|
-
src="/assets/svg/eye-slash.svg"></i
|
|
227
|
+
><i src="/assets/svg/eye-slash.svg"></i
|
|
240
228
|
></a>
|
|
241
229
|
<a
|
|
242
230
|
class="margin-right:10px"
|
|
243
231
|
id="code"
|
|
244
232
|
show="#code-slash"
|
|
245
233
|
hide="#code, #demo-code"
|
|
246
|
-
><i
|
|
247
|
-
class="height:20px fill:#505050"
|
|
248
|
-
src="/assets/svg/code.svg"></i
|
|
234
|
+
><i src="/assets/svg/code.svg"></i
|
|
249
235
|
></a>
|
|
250
236
|
<a
|
|
251
237
|
class="margin-right:10px"
|
|
@@ -254,7 +240,7 @@
|
|
|
254
240
|
show="#code, #demo-code"
|
|
255
241
|
hide="#code-slash"
|
|
256
242
|
><i
|
|
257
|
-
class="
|
|
243
|
+
class="height:18px"
|
|
258
244
|
src="/assets/svg/code.svg"></i
|
|
259
245
|
></a>
|
|
260
246
|
<a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/cursors",
|
|
3
|
-
"version": "1.23.
|
|
3
|
+
"version": "1.23.5",
|
|
4
4
|
"description": "Collaborative user cursor position for inputs, textarea's and contenteditable elements.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cursors",
|
|
@@ -59,12 +59,12 @@
|
|
|
59
59
|
"webpack-log": "^3.0.1"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@cocreate/local-storage": "^1.
|
|
63
|
-
"@cocreate/observer": "^1.16.
|
|
64
|
-
"@cocreate/random-color": "^1.10.
|
|
65
|
-
"@cocreate/selection": "^1.12.
|
|
66
|
-
"@cocreate/socket-client": "^1.39.
|
|
67
|
-
"@cocreate/utils": "^1.33.
|
|
68
|
-
"@cocreate/uuid": "^1.11.
|
|
62
|
+
"@cocreate/local-storage": "^1.15.0",
|
|
63
|
+
"@cocreate/observer": "^1.16.1",
|
|
64
|
+
"@cocreate/random-color": "^1.10.1",
|
|
65
|
+
"@cocreate/selection": "^1.12.2",
|
|
66
|
+
"@cocreate/socket-client": "^1.39.1",
|
|
67
|
+
"@cocreate/utils": "^1.33.7",
|
|
68
|
+
"@cocreate/uuid": "^1.11.2"
|
|
69
69
|
}
|
|
70
70
|
}
|
package/src/index.css
CHANGED
|
@@ -3,6 +3,7 @@ cursor {
|
|
|
3
3
|
display: inline-block;
|
|
4
4
|
width: 2px;
|
|
5
5
|
background-color: dodgerblue;
|
|
6
|
+
white-space: pre-wrap
|
|
6
7
|
/*z-index:10;*/
|
|
7
8
|
}
|
|
8
9
|
|
|
@@ -36,11 +37,18 @@ selected-text {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
.mirror_color {
|
|
39
|
-
color: transparent;
|
|
40
|
-
pointer-events: none;
|
|
40
|
+
color: transparent!important;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
.mirror_scroll::-webkit-scrollbar {
|
|
44
44
|
background: rgba(0, 0, 0, 0.00);
|
|
45
45
|
width: 0px;
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
[mirror_id][contenteditable] {
|
|
49
|
+
white-space: pre-wrap
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
selected-text * {
|
|
53
|
+
background-color: inherit;
|
|
54
|
+
}
|
package/src/index.js
CHANGED
|
@@ -83,16 +83,16 @@ function drawCursors(selection) {
|
|
|
83
83
|
const array = selection['array'];
|
|
84
84
|
const object = selection['object'];
|
|
85
85
|
const key = selection['key'];
|
|
86
|
-
let start = selection['start'];
|
|
87
|
-
let end = selection['end'];
|
|
88
86
|
let elements = selection.element;
|
|
89
87
|
if (!elements) {
|
|
90
88
|
let selector = '[array="' + array + '"][object="' + object + '"][key="' + key + '"]';
|
|
91
|
-
selector += ':not(
|
|
89
|
+
selector += ':not([actions])';
|
|
92
90
|
elements = document.querySelectorAll(selector);
|
|
93
91
|
}
|
|
94
92
|
for (let element of elements) {
|
|
95
|
-
|
|
93
|
+
let start = selection['start']
|
|
94
|
+
let end = selection['end']
|
|
95
|
+
if (window.activeElement == element && socket.frameId === selection.frameId) {
|
|
96
96
|
continue;
|
|
97
97
|
}
|
|
98
98
|
let realtime = element.getAttribute('realtime');
|
|
@@ -100,29 +100,33 @@ function drawCursors(selection) {
|
|
|
100
100
|
let contenteditable = element.getAttribute('contenteditable');
|
|
101
101
|
if (!realtime || realtime == 'false' || cursors == 'false') continue;
|
|
102
102
|
if (element.tagName != 'INPUT' && element.tagName != 'TEXTAREA')
|
|
103
|
-
if (contenteditable == 'false' || contenteditable
|
|
103
|
+
if (contenteditable == 'false' || contenteditable === null) {
|
|
104
104
|
if (cursors != 'true') continue;
|
|
105
|
+
}
|
|
105
106
|
|
|
106
107
|
if (element.hasAttribute('contenteditable')) {
|
|
107
|
-
|
|
108
|
+
contenteditable = true
|
|
109
|
+
// let domTextEditor = element;
|
|
108
110
|
if (element.tagName == 'IFRAME') {
|
|
109
111
|
// let frameClientId = element.contentDocument.defaultView.CoCreateSockets.id;
|
|
110
112
|
// if (frameClientId == selection.socketId) continue;
|
|
111
|
-
|
|
113
|
+
element = element.contentDocument.documentElement;
|
|
112
114
|
}
|
|
113
|
-
if (!
|
|
115
|
+
if (!element.htmlString)
|
|
114
116
|
continue
|
|
115
|
-
let pos = getElementPosition(domTextEditor.htmlString, start, end);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
117
|
+
// let pos = getElementPosition(domTextEditor.htmlString, start, end);
|
|
118
|
+
|
|
119
|
+
// if (pos.path) {
|
|
120
|
+
// element = domTextEditor.querySelector(pos.path);
|
|
121
|
+
// if (pos.start) {
|
|
122
|
+
// let endPos = end - start;
|
|
123
|
+
// if (endPos > 0)
|
|
124
|
+
// end = pos.start + endPos;
|
|
125
|
+
// else
|
|
126
|
+
// end = pos.start;
|
|
127
|
+
// start = pos.start;
|
|
128
|
+
// }
|
|
129
|
+
// }
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
if (!element) continue;
|
|
@@ -150,10 +154,10 @@ function drawCursors(selection) {
|
|
|
150
154
|
|
|
151
155
|
_initEvents(element);
|
|
152
156
|
initDocument(document);
|
|
153
|
-
}
|
|
154
|
-
else
|
|
157
|
+
} else
|
|
155
158
|
mirrorDiv = document.getElementById(id_mirror);
|
|
156
159
|
|
|
160
|
+
|
|
157
161
|
let computed = getComputedStyle(element);
|
|
158
162
|
let rect = element.getBoundingClientRect();
|
|
159
163
|
|
|
@@ -166,16 +170,15 @@ function drawCursors(selection) {
|
|
|
166
170
|
style.position = 'absolute';
|
|
167
171
|
style.width = rect.width + 'px';
|
|
168
172
|
style.height = rect.height + 'px';
|
|
173
|
+
style.margin = '0px';
|
|
174
|
+
style.borderColor = 'transparent';
|
|
175
|
+
style.outlineColor = 'transparent';
|
|
176
|
+
|
|
169
177
|
style.overflowX = computed['overflowX'];
|
|
170
178
|
style.overflowY = computed['overflowY'];
|
|
171
|
-
style.margin = '0px';
|
|
172
179
|
style.padding = computed['padding'];
|
|
173
180
|
style.border = computed['border'];
|
|
174
|
-
style.borderColor = 'transparent';
|
|
175
181
|
style.outline = computed['outline'];
|
|
176
|
-
style.outlineColor = 'transparent';
|
|
177
|
-
style.boxSizing = computed['boxSizing'];
|
|
178
|
-
style.lineHeight = computed['lineHeight'];
|
|
179
182
|
|
|
180
183
|
if (element.parentElement.style['display'] == 'inline') {
|
|
181
184
|
style.top = element.clientTop + 'px';
|
|
@@ -185,56 +188,97 @@ function drawCursors(selection) {
|
|
|
185
188
|
style.left = element.offsetLeft + 'px';
|
|
186
189
|
}
|
|
187
190
|
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
+
if (contenteditable) {
|
|
192
|
+
const actualStyles = getActualStyles(element);
|
|
193
|
+
for (const [prop, value] of Object.entries(actualStyles)) {
|
|
194
|
+
style[prop] = value;
|
|
195
|
+
}
|
|
191
196
|
} else {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
let properties = ['fontStyle', 'fontVariant', 'fontWeight', 'fontStretch', 'fontSize', 'fontFamily', 'letterSpacing', 'lineHeight', 'textAlign', 'textTransform', 'textIndent', 'textDecoration', 'textRendering', 'textTransform', 'textIndent', 'overflowWrap', 'tabSize', 'webkitWritingMode', 'wordSpacing'];
|
|
196
|
-
|
|
197
|
-
properties.forEach(function (prop) {
|
|
198
|
-
if (['left', 'top'].indexOf(prop.toLowerCase()) === -1)
|
|
197
|
+
let properties = ['boxSizing', 'fontStyle', 'fontVariant', 'fontWeight', 'fontStretch', 'fontSize', 'fontFamily', 'letterSpacing', 'lineHeight', 'textAlign', 'textTransform', 'textIndent', 'textDecoration', 'textRendering', 'textTransform', 'textIndent', 'overflowWrap', 'tabSize', 'webkitWritingMode', 'whiteSpace', 'wordSpacing'];
|
|
198
|
+
properties.forEach(function (prop) {
|
|
199
199
|
style[prop] = computed[prop];
|
|
200
|
-
|
|
200
|
+
});
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
202
|
+
let paddingBottom = parseFloat(computed['padding-bottom'].replace('px', ''))
|
|
203
|
+
style.height = rect.height - paddingBottom + 'px';
|
|
204
|
+
|
|
205
|
+
if (element.nodeName === 'INPUT')
|
|
206
|
+
style.whiteSpace = 'pre';
|
|
207
|
+
}
|
|
207
208
|
|
|
208
|
-
spanText.textContent = value_element;
|
|
209
|
-
if (element.nodeName === 'INPUT')
|
|
210
|
-
spanText.textContent = mirrorDiv.textContent.replace(/\s/g, " ");
|
|
211
|
-
mirrorDiv.appendChild(spanText);
|
|
212
209
|
let cursor, cursorFlag;
|
|
213
210
|
let details = { array, object, key };
|
|
214
211
|
if (socket_id) {
|
|
215
|
-
let userSelection = mirrorDiv.querySelector(`selection[socket_id="${socket_id}"]`);
|
|
216
|
-
if (userSelection && userSelection.details != details)
|
|
217
|
-
userSelection.remove();
|
|
218
212
|
let selection_user = mirrorDiv.querySelector(`selection[socket_id="${socket_id}"]`);
|
|
219
|
-
if (
|
|
220
|
-
selection_user
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
213
|
+
if (selection_user && selection_user.details != details)
|
|
214
|
+
selection_user.remove();
|
|
215
|
+
|
|
216
|
+
selection_user = document.createElement('selection');
|
|
217
|
+
selection_user.setAttribute('socket_id', socket_id);
|
|
218
|
+
selection_user.style["position"] = "absolute";
|
|
219
|
+
let style_mirror = getComputedStyle(mirrorDiv);
|
|
220
|
+
selection_user.style["top"] = style_mirror.paddingTop;
|
|
221
|
+
selection_user.style["left"] = style_mirror.paddingLeft;
|
|
222
|
+
selection_user.style["width"] = mirrorDiv.clientWidth - parseInt(computed['padding-left']) - parseInt(computed['padding-right']) - scrollBarWidth + 'px';
|
|
223
|
+
selection_user.details = { array, object, key };
|
|
231
224
|
|
|
232
225
|
let value_element = (['TEXTAREA', 'INPUT'].indexOf(element.nodeName) == -1) ? element.innerHTML : element.value;
|
|
233
|
-
|
|
226
|
+
if (contenteditable) {
|
|
227
|
+
selection_user.innerHTML = value_element.substring(0, start);
|
|
228
|
+
} else
|
|
229
|
+
selection_user.textContent = value_element.substring(0, start);
|
|
230
|
+
|
|
231
|
+
let selectionElement
|
|
232
|
+
if (contenteditable) {
|
|
233
|
+
selectionElement = getElementPosition(element.htmlString, start, end);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
let lastChildTagName, lastChildElement
|
|
237
|
+
if (selectionElement && selectionElement.element && selectionElement.position !== 'afterend') {
|
|
238
|
+
lastChildElement = selection_user.lastElementChild;
|
|
239
|
+
lastChildTagName = lastChildElement.tagName.toLowerCase()
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
let selectedText = document.createElement('selected-text');
|
|
243
|
+
selectedText.style["backgroundColor"] = selection.background;
|
|
244
|
+
|
|
245
|
+
let setCursorInLastChild = false
|
|
246
|
+
if (contenteditable) {
|
|
247
|
+
if (lastChildTagName && start !== end) {
|
|
248
|
+
let selectedTextFrag = document.createElement('selected-text');
|
|
249
|
+
selectedTextFrag.style["backgroundColor"] = selection.background;
|
|
250
|
+
|
|
251
|
+
const closingTagRegex = new RegExp("</\\s*" + lastChildTagName + "\\s*>", "i");
|
|
252
|
+
let secondHalfString = value_element.substring(start, end) || '';
|
|
253
|
+
const closingTagMatch = secondHalfString.match(closingTagRegex);
|
|
254
|
+
// console.log('secondHalfString', secondHalfString)
|
|
255
|
+
|
|
256
|
+
let closingTagEnd
|
|
257
|
+
if (closingTagMatch) {
|
|
258
|
+
closingTagEnd = closingTagMatch.index + closingTagMatch[0].length;
|
|
259
|
+
// console.log('closingTagEnd', closingTagEnd)
|
|
260
|
+
|
|
261
|
+
selectedTextFrag.innerHTML = secondHalfString.substring(0, closingTagEnd) || '';
|
|
262
|
+
lastChildElement.appendChild(selectedTextFrag);
|
|
263
|
+
// console.log('selectedTextFrag', selectedTextFrag)
|
|
264
|
+
|
|
265
|
+
selectedText.innerHTML = value_element.substring(start + closingTagEnd, end) || '';
|
|
266
|
+
// console.log('selectedText', selectedText)
|
|
267
|
+
|
|
268
|
+
} else {
|
|
269
|
+
selectedText.innerHTML = value_element.substring(start, end) || '';
|
|
270
|
+
setCursorInLastChild = true
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
if (lastChildTagName)
|
|
274
|
+
setCursorInLastChild = true
|
|
275
|
+
|
|
276
|
+
selectedText.innerHTML = value_element.substring(start, end) || '';
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
selectedText.textContent = value_element.substring(start, end) || '';
|
|
280
|
+
}
|
|
234
281
|
|
|
235
|
-
let value_end = value_element.substring(end) || '';
|
|
236
|
-
let span_end = document.createElement('span-end');
|
|
237
|
-
span_end.textContent = value_end;
|
|
238
282
|
|
|
239
283
|
cursor = document.createElement('cursor');
|
|
240
284
|
cursor.setAttribute('socket_id', socket_id);
|
|
@@ -245,13 +289,7 @@ function drawCursors(selection) {
|
|
|
245
289
|
cursor.setAttribute('user-color', selection.color);
|
|
246
290
|
cursor.style["background"] = selection.background;
|
|
247
291
|
cursor.details = { array, object, key };
|
|
248
|
-
cursor.textContent = "
|
|
249
|
-
span_end.prepend(cursor);
|
|
250
|
-
|
|
251
|
-
let selectedText = document.createElement('selected-text');
|
|
252
|
-
selectedText.style["backgroundColor"] = selection.background;
|
|
253
|
-
selectedText.textContent = value_element.substring(start, end) || '';
|
|
254
|
-
span_end.prepend(selectedText);
|
|
292
|
+
cursor.textContent = " ";
|
|
255
293
|
|
|
256
294
|
cursorFlag = document.createElement('cursor-flag');
|
|
257
295
|
cursorFlag.setAttribute('array', 'users');
|
|
@@ -261,12 +299,57 @@ function drawCursors(selection) {
|
|
|
261
299
|
cursorFlag.innerHTML = selection.userName;
|
|
262
300
|
cursor.appendChild(cursorFlag);
|
|
263
301
|
|
|
302
|
+
if (setCursorInLastChild) {
|
|
303
|
+
lastChildElement.appendChild(selectedText);
|
|
304
|
+
lastChildElement.appendChild(cursor);
|
|
305
|
+
} else {
|
|
306
|
+
selection_user.appendChild(selectedText);
|
|
307
|
+
selection_user.appendChild(cursor);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
let span_end = document.createElement('span-end');
|
|
311
|
+
let value_end = value_element.substring(end) || '';
|
|
312
|
+
if (contenteditable)
|
|
313
|
+
span_end.innerHTML = value_end
|
|
314
|
+
else
|
|
315
|
+
span_end.textContent = value_end
|
|
316
|
+
|
|
264
317
|
selection_user.appendChild(span_end);
|
|
318
|
+
|
|
319
|
+
mirrorDiv.appendChild(selection_user);
|
|
265
320
|
}
|
|
266
321
|
scrollMirror(element);
|
|
267
322
|
}
|
|
268
323
|
}
|
|
269
324
|
|
|
325
|
+
function getActualStyles(element) {
|
|
326
|
+
const actualStyles = {};
|
|
327
|
+
|
|
328
|
+
// Copy styles that are directly applied to the element (inline styles)
|
|
329
|
+
for (const prop in element.style) {
|
|
330
|
+
if (element.style[prop]) {
|
|
331
|
+
actualStyles[prop] = element.style[prop];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Get styles from classes, IDs, attributes, and tag names
|
|
336
|
+
for (const sheet of document.styleSheets) {
|
|
337
|
+
try {
|
|
338
|
+
for (const rule of sheet.cssRules) {
|
|
339
|
+
if (element.matches(rule.selectorText)) {
|
|
340
|
+
for (const prop of rule.style) {
|
|
341
|
+
actualStyles[prop] = rule.style.getPropertyValue(prop);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
} catch (e) {
|
|
346
|
+
console.warn("Unable to access stylesheet:", e);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return actualStyles;
|
|
351
|
+
}
|
|
352
|
+
|
|
270
353
|
function updateCursors(element) {
|
|
271
354
|
let mirrorDivs = [];
|
|
272
355
|
let id_mirror = element.getAttribute('mirror_id');
|
|
@@ -274,10 +357,10 @@ function updateCursors(element) {
|
|
|
274
357
|
let mirrorDiv = element.ownerDocument.getElementById(id_mirror);
|
|
275
358
|
if (mirrorDiv)
|
|
276
359
|
mirrorDivs = [mirrorDiv];
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
360
|
+
} else {
|
|
279
361
|
mirrorDivs = element.querySelectorAll('.mirror');
|
|
280
362
|
}
|
|
363
|
+
|
|
281
364
|
for (let mirrorDiv of mirrorDivs) {
|
|
282
365
|
element = mirrorDiv.element;
|
|
283
366
|
let cursors = mirrorDiv.querySelectorAll('cursor');
|
|
@@ -368,6 +451,7 @@ socket.listen('cursor', function (response) {
|
|
|
368
451
|
// if (socket.has(selection.socketId)) return;
|
|
369
452
|
let selection = response.data
|
|
370
453
|
selection.socketId = response.socketId
|
|
454
|
+
selection.frameId = response.frameId
|
|
371
455
|
if (selection.start != null && selection.end != null)
|
|
372
456
|
drawCursors(selection);
|
|
373
457
|
else
|