@cocreate/selection 1.12.2 → 1.13.0

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,21 @@
1
+ # [1.13.0](https://github.com/CoCreate-app/CoCreate-selection/compare/v1.12.2...v1.13.0) (2024-06-12)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * bump cocreate dependencies ([338178a](https://github.com/CoCreate-app/CoCreate-selection/commit/338178a59acee9ac267c33e089388ee819220e79))
7
+ * conteneditable start end across multiple nodes ([ab1d6e2](https://github.com/CoCreate-app/CoCreate-selection/commit/ab1d6e2c5a8b00811e400e25550876c6a264ffe5))
8
+ * remove testing logs ([910e3ff](https://github.com/CoCreate-app/CoCreate-selection/commit/910e3ff5d08d843c4bdff28b7842f54c8358c61d))
9
+ * removed testing logs ([b2cf244](https://github.com/CoCreate-app/CoCreate-selection/commit/b2cf24406c14437f4c9082288649b890f52df51b))
10
+ * return if contenteditable not found ([8ecf10e](https://github.com/CoCreate-app/CoCreate-selection/commit/8ecf10e180ab46e2d36a7a435369201f0d71bc91))
11
+ * svg icon class ([20641ff](https://github.com/CoCreate-app/CoCreate-selection/commit/20641ff0426aa898153d99679069db01332f774e))
12
+ * textnode handling ([e22af17](https://github.com/CoCreate-app/CoCreate-selection/commit/e22af17799699d596c83b0974d3d9187fbc51f23))
13
+
14
+
15
+ ### Features
16
+
17
+ * parse text to reset selection ([7c367bb](https://github.com/CoCreate-app/CoCreate-selection/commit/7c367bbeccdaf07dfdec64d0811f5e5bd41fecb9))
18
+
1
19
  ## [1.12.2](https://github.com/CoCreate-app/CoCreate-selection/compare/v1.12.1...v1.12.2) (2024-04-29)
2
20
 
3
21
 
package/docs/index.html CHANGED
@@ -71,41 +71,31 @@
71
71
  href="https://github.com/CoCreate-app/CoCreate-selection"
72
72
  target="_blank"
73
73
  class="margin-right:15px"
74
- ><i
75
- class="height:20px fill:#505050"
76
- src="/assets/svg/github.svg"></i
74
+ ><i src="/assets/svg/github.svg"></i
77
75
  ></a>
78
76
  <a
79
77
  class="margin-right:15px share"
80
78
  share-network="twitter"
81
79
  title="Share on twitter"
82
- ><i
83
- class="height:20px fill:#505050"
84
- src="/assets/svg/twitter.svg"></i
80
+ ><i src="/assets/svg/twitter.svg"></i
85
81
  ></a>
86
82
  <a
87
83
  class="margin-right:15px share"
88
84
  share-network="facebook"
89
85
  title="Share on Facebook"
90
- ><i
91
- class="height:20px fill:#505050"
92
- src="/assets/svg/facebook.svg"></i
86
+ ><i src="/assets/svg/facebook.svg"></i
93
87
  ></a>
94
88
  <a
95
89
  class="margin-right:15px share"
96
90
  share-network="instagram"
97
91
  title="Share on instagram"
98
- ><i
99
- class="height:20px fill:#505050"
100
- src="/assets/svg/instagram.svg"></i
92
+ ><i src="/assets/svg/instagram.svg"></i
101
93
  ></a>
102
94
  <a
103
95
  class="margin-right:15px share"
104
96
  share-network="share"
105
97
  title="Share on share"
106
- ><i
107
- class="height:20px fill:#505050"
108
- src="/assets/svg/share-alt.svg"></i
98
+ ><i src="/assets/svg/share-alt.svg"></i
109
99
  ></a>
110
100
  </div>
111
101
  </div>
@@ -227,7 +217,7 @@
227
217
  toggle="code-height"
228
218
  toggle-selector="#demo-code"
229
219
  ><i
230
- class="height:18px fill:#505050"
220
+ class="height:18px"
231
221
  src="/assets/svg/eye.svg"></i
232
222
  ></a>
233
223
  <a
@@ -238,18 +228,14 @@
238
228
  hide="#eye-slash"
239
229
  toggle="code-height"
240
230
  toggle-selector="#demo-code"
241
- ><i
242
- class="height:20px fill:#505050"
243
- src="/assets/svg/eye-slash.svg"></i
231
+ ><i src="/assets/svg/eye-slash.svg"></i
244
232
  ></a>
245
233
  <a
246
234
  class="margin-right:10px"
247
235
  id="code"
248
236
  show="#code-slash"
249
237
  hide="#code, #demo-code"
250
- ><i
251
- class="height:20px fill:#505050"
252
- src="/assets/svg/code.svg"></i
238
+ ><i src="/assets/svg/code.svg"></i
253
239
  ></a>
254
240
  <a
255
241
  class="margin-right:10px"
@@ -258,7 +244,7 @@
258
244
  show="#code, #demo-code"
259
245
  hide="#code-slash"
260
246
  ><i
261
- class="display:flex height:18px fill:#505050"
247
+ class="height:18px"
262
248
  src="/assets/svg/code.svg"></i
263
249
  ></a>
264
250
  <a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/selection",
3
- "version": "1.12.2",
3
+ "version": "1.13.0",
4
4
  "description": "A simple selection component in vanilla javascript. Easily configured using HTML5 data-attributes and/or JavaScript API.",
5
5
  "keywords": [
6
6
  "selection",
@@ -58,6 +58,6 @@
58
58
  "webpack-log": "^3.0.1"
59
59
  },
60
60
  "dependencies": {
61
- "@cocreate/utils": "^1.33.6"
61
+ "@cocreate/utils": "^1.33.7"
62
62
  }
63
63
  }
package/src/index.js CHANGED
@@ -10,48 +10,33 @@ export function getSelection(element) {
10
10
  start: element.selectionStart,
11
11
  end: element.selectionEnd
12
12
  };
13
- }
14
- else {
13
+
14
+ } else {
15
15
  let Document = element.ownerDocument;
16
16
  let selection = Document.getSelection();
17
- if (!selection.rangeCount) return { start: 0, end: 0 };
17
+ if (!selection.rangeCount)
18
+ return { start: 0, end: 0 };
18
19
 
19
20
  let range = selection.getRangeAt(0);
20
- let start = range.startOffset;
21
- let end = range.endOffset;
22
- let previousSibling = range.startContainer.previousSibling;
23
- if (element.innerHTML && previousSibling && previousSibling.nodeType == 3) {
24
- let length = 0;
25
- do {
26
- length += previousSibling.length;
27
- previousSibling = previousSibling.previousSibling;
28
- } while (previousSibling);
29
- start += length;
30
- end += length;
31
- }
32
21
 
33
- if (range.startContainer != range.endContainer) {
34
- // TODO: replace common ancestor value
35
- }
36
22
  let contenteditable = range.startContainer.parentElement.closest('[contenteditable][array][object][key]');
37
23
  if (contenteditable) {
38
24
  element = contenteditable;
39
- }
25
+ } else return
26
+
40
27
  let domTextEditor = element;
41
28
  if (!domTextEditor.htmlString) {
42
- domTextEditor = element.closest('[contenteditable]');
43
- }
44
- let elementStart = start, elementEnd = end;
45
- if (domTextEditor && domTextEditor.htmlString) {
46
- let nodePos = getStringPosition({ string: domTextEditor.htmlString, target: range.startContainer.parentElement, position: 'afterbegin' });
47
- if (nodePos) {
48
- elementStart = nodePos.start;
49
- elementEnd = nodePos.end;
50
- start = start + nodePos.start;
51
- end = end + nodePos.end;
52
- }
29
+ domTextEditor = domTextEditor.closest('[contenteditable]');
53
30
  }
54
31
 
32
+
33
+ let start = getNodePosition(range.startContainer, domTextEditor, range.startOffset)
34
+ let end = start
35
+ if (range.startContainer !== range.endContainer) {
36
+ end = getNodePosition(range.endContainer, domTextEditor, range.endOffset)
37
+ } else if (range.endOffset !== range.startOffset)
38
+ end = start + (range.endOffset - range.startOffset)
39
+
55
40
  let startContainer = range.startContainer;
56
41
  if (startContainer.nodeType == 3)
57
42
  startContainer = range.startContainer.parentElement;
@@ -60,21 +45,55 @@ export function getSelection(element) {
60
45
  if (endContainer.nodeType == 3)
61
46
  endContainer = range.endContainer.parentElement;
62
47
 
48
+ let textStart = 0, node = range.startContainer
49
+ while (node) {
50
+ textStart += node.textContent.length;
51
+ node = node.previousSibling;
52
+ }
53
+ let textEnd = textStart + (range.endOffset - range.startOffset)
54
+
63
55
  let rangeObj = {
64
- element: contenteditable,
65
- // domTextEditor,
56
+ element,
57
+ domTextEditor,
66
58
  startOffset: range.startOffset,
67
59
  endOffset: range.endOffset,
68
60
  startContainer,
69
61
  endContainer,
70
- elementStart,
71
- elementEnd
62
+ elementStart: start,
63
+ elementEnd: end,
64
+ nodeStartContainer: range.startContainer,
65
+ nodeEndContainer: range.endContainer,
66
+ textStart,
67
+ textEnd
72
68
  };
73
- return { start, end, range: rangeObj };
69
+
70
+ return { element: contenteditable, value: selection.toString(), start, end, range: rangeObj };
74
71
  }
75
72
 
76
73
  }
77
74
 
75
+
76
+ function getNodePosition(container, domTextEditor, position) {
77
+ let string = domTextEditor.htmlString
78
+ let node = container.previousSibling
79
+ while (node && node.nodeType === 3) {
80
+ position += node.textContent.length;
81
+ node = node.previousSibling;
82
+ }
83
+
84
+ let nodePosition
85
+ if (node && node.nodeType === 1) {
86
+ nodePosition = getStringPosition({ string, target: node, position: 'afterend' });
87
+ position += nodePosition.end
88
+ } else if (container.parentElement !== domTextEditor && container !== domTextEditor) {
89
+ let parentElement = container.parentElement
90
+ nodePosition = getStringPosition({ string, target: parentElement, position: 'afterbegin' });
91
+ position += nodePosition.start
92
+ }
93
+
94
+ return position
95
+ }
96
+
78
97
  export function processSelection(element, value = "", prev_start, prev_end, start, end, range) {
79
98
  let prevStart = prev_start;
80
99
  let prevEnd = prev_end;
@@ -83,8 +102,7 @@ export function processSelection(element, value = "", prev_start, prev_end, star
83
102
  prev_start -= end - start;
84
103
  prev_end -= end - start;
85
104
  prev_start = prev_start < start ? start : prev_start;
86
- }
87
- else {
105
+ } else {
88
106
  prev_start += value.length;
89
107
  prev_end += value.length;
90
108
  }
@@ -98,8 +116,7 @@ export function processSelection(element, value = "", prev_start, prev_end, star
98
116
  let length = prevStart - prev_start;
99
117
  if (Math.sign(length) === 1 && range.startOffset >= length)
100
118
  range.startOffset -= length;
101
- }
102
- else if (prevStart < prev_start) {
119
+ } else if (prevStart < prev_start) {
103
120
  let length = prev_start - prevStart;
104
121
  if (Math.sign(length) === 1)
105
122
  if (range.startOffset == 0 || range.startOffset >= length)
@@ -109,8 +126,7 @@ export function processSelection(element, value = "", prev_start, prev_end, star
109
126
  let length = prevEnd - prev_end;
110
127
  if (Math.sign(length) === 1 && range.endOffset >= length)
111
128
  range.endOffset -= length;
112
- }
113
- else if (prevEnd < prev_end) {
129
+ } else if (prevEnd < prev_end) {
114
130
  let length = prev_end - prevEnd;
115
131
  if (Math.sign(length) === 1)
116
132
  if (range.endOffset == 0 || range.endOffset >= length)
@@ -126,13 +142,25 @@ export function setSelection(element, start, end, range) {
126
142
  if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
127
143
  element.selectionStart = start;
128
144
  element.selectionEnd = end;
129
- }
130
- else {
145
+ } else {
131
146
  if (!range) return;
132
147
  let Document = element.ownerDocument;
133
148
 
134
- let startContainer = getContainer(range.startContainer, range.startOffset);
135
- let endContainer = getContainer(range.endContainer, range.endOffset);
149
+ let startContainer, endContainer
150
+ // if (range.startContainer.htmlString)
151
+ startContainer = getContainer(range.startContainer, range.textStart - range.startOffset);
152
+ // else
153
+ // startContainer = getContainer(range.startContainer, range.startOffset);
154
+
155
+ // if (range.endContainer.htmlString)
156
+ endContainer = getContainer(range.endContainer, range.textEnd - range.endOffset);
157
+ // else
158
+ // endContainer = getContainer(range.endContainer, range.endOffset);
159
+
160
+ // let startContainer = getContainer(range.startContainer, range.elementStart);
161
+ // let endContainer = getContainer(range.endContainer, range.elementEnd);
162
+ // let startContainer = getContainer(range.startContainer, range.startOffset);
163
+ // let endContainer = getContainer(range.endContainer, range.endOffset);
136
164
 
137
165
  if (!startContainer || !endContainer)
138
166
  return;
@@ -141,6 +169,7 @@ export function setSelection(element, start, end, range) {
141
169
  selection.removeAllRanges();
142
170
 
143
171
  const newRange = Document.createRange();
172
+
144
173
  newRange.setStart(startContainer, range.startOffset);
145
174
  newRange.setEnd(endContainer, range.endOffset);
146
175
 
@@ -150,14 +179,11 @@ export function setSelection(element, start, end, range) {
150
179
 
151
180
  function getContainer(element, offset) {
152
181
  let nodeLengths = 0;
153
- for (let node of element.childNodes) {
154
- if (node.nodeType == 3) {
155
- let length = node.length + nodeLengths;
156
- if (length >= offset)
157
- return node;
158
- else
159
- nodeLengths += length;
160
- }
182
+ let nodes = element.childNodes
183
+ for (let i = 0; i < nodes.length; i++) {
184
+ nodeLengths += nodes[i].textContent.length
185
+ if (nodeLengths >= offset)
186
+ return nodes[i];
161
187
  }
162
188
  }
163
189
 
@@ -175,7 +201,7 @@ export function getElementPosition(str, start, end) {
175
201
  let angleStart = startString.lastIndexOf("<");
176
202
  let angleEnd = startString.lastIndexOf(">");
177
203
  let endStringAngleEnd = endString.indexOf(">");
178
- let element, position, nodeStart, nodeEnd, startNode, type;
204
+ let element, path, position, nodeStart, nodeEnd, startNode, type;
179
205
  if (angleEnd > angleStart) {
180
206
  let length = 0;
181
207
  if (start != end)
@@ -192,16 +218,22 @@ export function getElementPosition(str, start, end) {
192
218
  type = 'textNode';
193
219
  if (position == 'beforeend' && findEl.previousSibling && findEl.previousSibling.nodeType == 3)
194
220
  type = 'textNode';
195
- if (type == 'textNode' || position == 'afterbegin')
221
+ if (position == 'afterbegin')
196
222
  nodeStart = start - angleEnd - 1;
223
+ if (type == 'textNode') {
224
+ if (element.tagName === 'DOM-PARSER') {
225
+ element = null
226
+ nodeStart = start
227
+ nodeEnd = end
228
+ } else
229
+ nodeStart = start - angleEnd - 1;
230
+ }
197
231
 
198
232
  findEl.remove();
199
233
  }
200
- }
201
- else if (angleStart == -1) {
234
+ } else if (angleStart == -1) {
202
235
  type = 'textNode';
203
- }
204
- else {
236
+ } else {
205
237
  let node = str.slice(angleStart, startString.length + endStringAngleEnd + 1);
206
238
  if (node.startsWith("</")) {
207
239
  startNode = node.slice(0, 1) + node.slice(2);
@@ -211,13 +243,13 @@ export function getElementPosition(str, start, end) {
211
243
  let end = endString1.indexOf(">");
212
244
  nodeEnd = nodeStart + end + 1;
213
245
  type = 'isEndTag';
214
- }
215
- else {
246
+ } else {
216
247
  nodeEnd = startString.length + endStringAngleEnd + 1;
217
248
  startNode = node;
218
249
  nodeStart = angleStart;
219
250
  type = 'isStartTag';
220
251
  }
252
+
221
253
  if (nodeEnd > 0) {
222
254
  let string = str.customSplice(nodeEnd - 1, 0, ' findelement');
223
255
  let newDom = domParser(string);
@@ -227,8 +259,7 @@ export function getElementPosition(str, start, end) {
227
259
  else if (type == "isEndTag")
228
260
  element = element.parentElement;
229
261
  element.removeAttribute('findelement');
230
- }
231
- else {
262
+ } else {
232
263
  let string = str.customSplice(angleStart, 0, '<findelement></findelement>');
233
264
  let newDom = domParser(string);
234
265
  element = newDom.querySelector('findelement');
@@ -246,14 +277,13 @@ export function getElementPosition(str, start, end) {
246
277
  }
247
278
  }
248
279
 
249
- if (element) {
250
- response.element = element;
280
+ response.element = element;
281
+ if (element)
251
282
  response.path = cssPath(element);
252
- response.position = position;
253
- response.start = nodeStart;
254
- response.end = nodeEnd;
255
- response.type = type;
256
- }
283
+ response.position = position;
284
+ response.start = nodeStart;
285
+ response.end = nodeEnd;
286
+ response.type = type;
257
287
 
258
288
  return response;
259
289
  }
@@ -266,24 +296,19 @@ function getInsertPosition(element) {
266
296
  if (!previousSibling) {
267
297
  target = element.parentElement;
268
298
  position = 'afterbegin';
269
- }
270
- else if (!nextSibling) {
299
+ } else if (!nextSibling) {
271
300
  target = element.parentElement;
272
301
  position = 'beforeend';
273
- }
274
- else if (previousSibling && previousSibling.nodeType == 1) {
302
+ } else if (previousSibling && previousSibling.nodeType == 1) {
275
303
  target = previousSibling;
276
304
  position = 'afterend';
277
- }
278
- else if (nextSibling && nextSibling.nodeType == 1) {
305
+ } else if (nextSibling && nextSibling.nodeType == 1) {
279
306
  target = element.parentElement;
280
307
  position = 'afterbegin';
281
- }
282
- else {
308
+ } else {
283
309
  target = element.parentElement;
284
310
  }
285
- }
286
- else {
311
+ } else {
287
312
  target = element.parentElement;
288
313
  position = 'afterbegin';
289
314
  }
@@ -315,13 +340,11 @@ export function getStringPosition({ string, target, position, attribute, propert
315
340
  else
316
341
  start = getElFromString(dom, string, element, position);
317
342
  end = start;
318
- }
319
- else if (attribute) {
343
+ } else if (attribute) {
320
344
  if (!element.hasAttribute(attribute)) {
321
345
  start = getElFromString(dom, string, element, 'afterbegin', true) - 1;
322
346
  end = start;
323
- }
324
- else {
347
+ } else {
325
348
  start = getElFromString(dom, string, element, 'beforebegin');
326
349
  let elString = string.substring(start);
327
350
  let attrValue = element.getAttribute(attribute);
@@ -333,8 +356,7 @@ export function getStringPosition({ string, target, position, attribute, propert
333
356
  else
334
357
  element.style[property] = value;
335
358
  value = element.getAttribute(attribute);
336
- }
337
- else if (attribute == 'class') {
359
+ } else if (attribute == 'class') {
338
360
  let [prop, val] = value.split(':');
339
361
  if (prop && val) {
340
362
  if (attrValue.includes(`${prop}:`)) {
@@ -349,20 +371,17 @@ export function getStringPosition({ string, target, position, attribute, propert
349
371
  if (!remove)
350
372
  element.classList.add(value);
351
373
  value = element.getAttribute(attribute);
352
- }
353
- else {
374
+ } else {
354
375
  element.setAttribute(attribute, value);
355
376
  value = element.getAttribute(attribute);
356
377
  }
357
378
  end = start + attribute.length + attrValue.length + 4;
358
379
  }
359
- }
360
- else if (value) {
380
+ } else if (value) {
361
381
  start = getElFromString(dom, string, element, 'afterbegin');
362
382
  let length = element.innerHTML.length;
363
383
  end = start + length;
364
- }
365
- else {
384
+ } else {
366
385
  start = getElFromString(dom, string, element, 'beforebegin');
367
386
  end = getElFromString(dom, string, element, 'afterend', true);
368
387
  }
@@ -380,19 +399,17 @@ function getElFromString(dom, string, element, position, isAttribute) {
380
399
  if (position == 'afterbegin') {
381
400
  element.insertAdjacentElement('afterbegin', findEl);
382
401
  angle = '>';
383
- }
384
- else if (position == 'afterend') {
402
+ } else if (position == 'afterend') {
385
403
  element.insertAdjacentElement('afterend', findEl);
386
404
  angle = '>';
387
- }
388
- else if (position == 'beforebegin') {
405
+ } else if (position == 'beforebegin') {
389
406
  element.insertAdjacentElement('afterbegin', findEl);
390
407
  angle = '<';
391
- }
392
- else if (position == 'beforeend') {
408
+ } else if (position == 'beforeend') {
393
409
  element.insertAdjacentElement('afterend', findEl);
394
410
  angle = '<';
395
411
  }
412
+
396
413
  if (dom.tagName == 'HTML')
397
414
  start = dom.outerHTML.indexOf("<findelement></findelement>");
398
415
  else
@@ -409,15 +426,19 @@ function getElFromString(dom, string, element, position, isAttribute) {
409
426
 
410
427
  findEl.remove();
411
428
 
412
- let domString = dom.outerHTML.substring(0, start);
429
+ let domString = dom.innerHTML.substring(0, start);
430
+ // let domString = dom.outerHTML.substring(0, start);
413
431
 
414
432
  if (dom.tagName == "HTML") {
433
+ domString = dom.outerHTML.substring(0, start);
415
434
  let htmlIndex = string.indexOf('<html');
416
435
  let documentType = string.substring(0, htmlIndex);
417
436
  documentTypeAngles = documentType.split(angle).length - 1;
418
437
  }
419
438
  let angles = domString.split(angle);
420
439
  let angleLength = angles.length - 1;
440
+ // if (position == 'afterend')
441
+ // angleLength += 1;
421
442
  if (documentTypeAngles)
422
443
  angleLength += documentTypeAngles;
423
444
  let elStart = getPosition(string, angle, angleLength);