@cocreate/selection 1.6.10 → 1.6.12

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/src/index.js CHANGED
@@ -1,449 +1,449 @@
1
- import {cssPath, domParser} from '@cocreate/utils';
2
-
3
- String.prototype.customSplice = function(index, absIndex, string) {
4
- return this.slice(0, index) + string + this.slice(index + Math.abs(absIndex));
5
- };
6
-
7
- export function getSelection(element) {
8
- if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
9
- return {
10
- start: element.selectionStart,
11
- end: element.selectionEnd
12
- };
13
- }
14
- else {
15
- let Document = element.ownerDocument;
16
- let selection = Document.getSelection();
17
- if (!selection.rangeCount) return { start: 0, end: 0 };
18
-
19
- 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
-
33
- if (range.startContainer != range.endContainer) {
34
- // TODO: replace common ancestor value
35
- }
36
- let contenteditable = range.startContainer.parentElement.closest('[contenteditable][collection][document_id][name]');
37
- if (contenteditable){
38
- element = contenteditable;
39
- }
40
- let domTextEditor = element;
41
- 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
- }
53
- }
54
-
55
- let startContainer = range.startContainer;
56
- if (startContainer.nodeType == 3)
57
- startContainer = range.startContainer.parentElement;
58
-
59
- let endContainer = range.endContainer;
60
- if (endContainer.nodeType == 3)
61
- endContainer = range.endContainer.parentElement;
62
-
63
- let rangeObj = {
64
- element: contenteditable,
65
- // domTextEditor,
66
- startOffset: range.startOffset,
67
- endOffset: range.endOffset,
68
- startContainer,
69
- endContainer,
70
- elementStart,
71
- elementEnd
72
- };
73
- return { start, end, range: rangeObj};
74
- }
75
-
76
- }
77
-
78
- export function processSelection(element, value = "", prev_start, prev_end, start, end, range) {
79
- let prevStart = prev_start;
80
- let prevEnd = prev_end;
81
- if (prev_start >= start) {
82
- if (value == "") {
83
- prev_start -= end - start;
84
- prev_end -= end - start;
85
- prev_start = prev_start < start ? start : prev_start;
86
- }
87
- else {
88
- prev_start += value.length;
89
- prev_end += value.length;
90
- }
91
- } {
92
- if (value == "" && prev_end >= start) {
93
- prev_end = (prev_end >= end) ? prev_end - (end - start) : start;
94
- }
95
- }
96
- if (range) {
97
- if (prevStart > prev_start){
98
- let length = prevStart - prev_start;
99
- if (Math.sign(length) === 1 && range.startOffset >= length)
100
- range.startOffset -= length;
101
- }
102
- else if (prevStart < prev_start){
103
- let length = prev_start - prevStart;
104
- if (Math.sign(length) === 1)
105
- if (range.startOffset == 0 || range.startOffset >= length)
106
- range.startOffset += length;
107
- }
108
- if (prevEnd > prev_end){
109
- let length = prevEnd - prev_end;
110
- if (Math.sign(length) === 1 && range.endOffset >= length)
111
- range.endOffset -= length;
112
- }
113
- else if (prevEnd < prev_end){
114
- let length = prev_end - prevEnd;
115
- if (Math.sign(length) === 1)
116
- if (range.endOffset == 0 || range.endOffset >= length)
117
- range.endOffset += length;
118
- }
119
- }
120
-
121
- setSelection(element, prev_start, prev_end, range);
122
- return {element, value, start, end, prev_start, prev_end};
123
- }
124
-
125
- export function setSelection(element, start, end, range) {
126
- if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
127
- element.selectionStart = start;
128
- element.selectionEnd = end;
129
- }
130
- else {
131
- if (!range) return;
132
- let Document = element.ownerDocument;
133
-
134
- let startContainer = getContainer(range.startContainer, range.startOffset);
135
- let endContainer = getContainer(range.endContainer, range.endOffset);
136
-
137
- if (!startContainer || !endContainer)
138
- return;
139
-
140
- let selection = Document.getSelection();
141
- selection.removeAllRanges();
142
-
143
- const newRange = Document.createRange();
144
- newRange.setStart(startContainer, range.startOffset);
145
- newRange.setEnd(endContainer, range.endOffset);
146
-
147
- selection.addRange(newRange);
148
- }
149
- }
150
-
151
- function getContainer(element, offset){
152
- 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
- }
161
- }
162
- }
163
-
164
- export function hasSelection(el) {
165
- let { start, end } = getSelection(el);
166
- if (start != end) {
167
- return true;
168
- }
169
- }
170
-
171
- export function getElementPosition(str, start, end) {
172
- let response = {};
173
- let startString = str.substring(0, start);
174
- let endString = str.substring(start);
175
- let angleStart = startString.lastIndexOf("<");
176
- let angleEnd = startString.lastIndexOf(">");
177
- let endStringAngleEnd = endString.indexOf(">");
178
- let element, position, nodeStart, nodeEnd, startNode, type;
179
- if (angleEnd > angleStart) {
180
- let length = 0;
181
- if (start != end)
182
- length = end - start;
183
- let string = str.customSplice(start, length, '<findelement></findelement>');
184
- let newDom = domParser(string);
185
- let findEl = newDom.querySelector('findelement');
186
- if (findEl) {
187
- let insert = getInsertPosition(findEl);
188
- element = insert.target;
189
- position = insert.position;
190
- type = 'insertAdjacent';
191
- if (!position)
192
- type = 'textNode';
193
- if (position == 'beforeend' && findEl.previousSibling && findEl.previousSibling.nodeType == 3 )
194
- type = 'textNode';
195
- if (type == 'textNode' || position == 'afterbegin')
196
- nodeStart = start - angleEnd - 1;
197
-
198
- findEl.remove();
199
- }
200
- }
201
- else if (angleStart == -1) {
202
- type = 'textNode';
203
- }
204
- else {
205
- let node = str.slice(angleStart, startString.length + endStringAngleEnd + 1);
206
- if (node.startsWith("</")) {
207
- startNode = node.slice(0, 1) + node.slice(2);
208
- startNode = startNode.substring(0, startNode.length - 1);
209
- nodeStart = startString.lastIndexOf(startNode);
210
- let endString1 = str.substring(nodeStart);
211
- let end = endString1.indexOf(">");
212
- nodeEnd = nodeStart + end + 1;
213
- type = 'isEndTag';
214
- }
215
- else {
216
- nodeEnd = startString.length + endStringAngleEnd + 1;
217
- startNode = node;
218
- nodeStart = angleStart;
219
- type = 'isStartTag';
220
- }
221
- if (nodeEnd > 0) {
222
- let string = str.customSplice(nodeEnd - 1, 0, ' findelement');
223
- let newDom = domParser(string);
224
- element = newDom.querySelector('[findelement]');
225
- if (!element && newDom.tagName == 'HTML')
226
- element = newDom;
227
- else if (type == "isEndTag")
228
- element = element.parentElement;
229
- element.removeAttribute('findelement');
230
- }
231
- else {
232
- let string = str.customSplice(angleStart, 0, '<findelement></findelement>');
233
- let newDom = domParser(string);
234
- element = newDom.querySelector('findelement');
235
- if (element) {
236
- let insert = getInsertPosition(element);
237
- element = insert.target.parentElement;
238
- position = insert.position;
239
- if (position == 'afterend')
240
- element = element.parentElement;
241
- type = 'innerHTML';
242
- }
243
- if (!element) {
244
- console.log('Could not find element');
245
- }
246
- }
247
- }
248
-
249
- if (element) {
250
- response.element = element;
251
- response.path = cssPath(element);
252
- response.position = position;
253
- response.start = nodeStart;
254
- response.end = nodeEnd;
255
- response.type = type;
256
- }
257
-
258
- return response;
259
- }
260
-
261
- function getInsertPosition(element){
262
- let target, position;
263
- let previousSibling = element.previousSibling;
264
- let nextSibling = element.nextSibling;
265
- if (previousSibling || nextSibling) {
266
- if (!previousSibling) {
267
- target = element.parentElement;
268
- position = 'afterbegin';
269
- }
270
- else if (!nextSibling) {
271
- target = element.parentElement;
272
- position = 'beforeend';
273
- }
274
- else if (previousSibling && previousSibling.nodeType == 1) {
275
- target = previousSibling;
276
- position = 'afterend';
277
- }
278
- else if (nextSibling && nextSibling.nodeType == 1) {
279
- target = element.parentElement;
280
- position = 'afterbegin';
281
- }
282
- else {
283
- target = element.parentElement;
284
- }
285
- }
286
- else {
287
- target = element.parentElement;
288
- position = 'afterbegin';
289
- }
290
- return {target, position};
291
- }
292
-
293
- export function getStringPosition({string, target, position, attribute, property, value, remove}) {
294
- try {
295
- let element;
296
- let selector = cssPath(target, '[contenteditable]');
297
- let dom = domParser(string);
298
- if (!selector.includes('[eid=') && dom.tagName == "DOM-PARSER"){
299
- let containerEl = document.createElement('div');
300
- containerEl.appendChild(dom)
301
- selector = `dom-parser > ${selector}`
302
- element = containerEl.querySelector(selector);
303
- }
304
- else
305
- element = dom.querySelector(selector);
306
- if (!element){
307
- // console.log('element could not be found using selector:', selector);
308
- return;
309
- }
310
- let start = 0, end = 0;
311
-
312
- if (position) {
313
- if (position == 'beforebegin')
314
- start = getElFromString(dom, string, element, position, true);
315
- else
316
- start = getElFromString(dom, string, element, position);
317
- end = start;
318
- }
319
- else if (attribute) {
320
- if (!element.hasAttribute(attribute)){
321
- start = getElFromString(dom, string, element, 'afterbegin', true) - 1;
322
- end = start;
323
- }
324
- else {
325
- start = getElFromString(dom, string, element, 'beforebegin');
326
- let elString = string.substring(start);
327
- let attrValue = element.getAttribute(attribute);
328
- let attrStart = elString.indexOf(` ${attribute}=`);
329
- start = start + attrStart;
330
- if (attribute == 'style') {
331
- if (remove)
332
- element.style.removeProperty(property);
333
- else
334
- element.style[property] = value;
335
- value = element.getAttribute(attribute);
336
- }
337
- else if (attribute == 'class') {
338
- let [prop, val] = value.split(':');
339
- if (prop && val){
340
- if (attrValue.includes(`${prop}:`)){
341
- let propStart = attrValue.indexOf(`${prop}:`);
342
- let propString = attrValue.substring(propStart);
343
- let propEnd = propString.indexOf(" ");
344
- if (propEnd > 0)
345
- propString = propString.slice(0, propEnd);
346
- element.classList.remove(propString);
347
- }
348
- }
349
- if (!remove)
350
- element.classList.add(value);
351
- value = element.getAttribute(attribute);
352
- }
353
- else {
354
- element.setAttribute(attribute, value);
355
- value = element.getAttribute(attribute);
356
- }
357
- end = start + attribute.length + attrValue.length + 4;
358
- }
359
- }
360
- else if (value) {
361
- start = getElFromString(dom, string, element, 'afterbegin');
362
- let length = element.innerHTML.length;
363
- end = start + length;
364
- }
365
- else {
366
- start = getElFromString(dom, string, element, 'beforebegin');
367
- end = getElFromString(dom, string, element, 'afterend', true);
368
- }
369
-
370
- return {start, end, newValue: value};
371
- }
372
- catch (e){
373
- console.log(e);
374
- }
375
- }
376
-
377
- function getElFromString(dom, string, element, position, isAttribute) {
378
- let findEl = document.createElement('findelement');
379
- let start, angle, documentTypeAngles;
380
- if (position == 'afterbegin') {
381
- element.insertAdjacentElement('afterbegin', findEl);
382
- angle = '>';
383
- }
384
- else if (position == 'afterend') {
385
- element.insertAdjacentElement('afterend', findEl);
386
- angle = '>';
387
- }
388
- else if (position == 'beforebegin'){
389
- element.insertAdjacentElement('afterbegin', findEl);
390
- angle = '<';
391
- }
392
- else if (position == 'beforeend'){
393
- element.insertAdjacentElement('afterend', findEl);
394
- angle = '<';
395
- }
396
- if (dom.tagName == 'HTML')
397
- start = dom.outerHTML.indexOf("<findelement></findelement>");
398
- else
399
- start = dom.innerHTML.indexOf("<findelement></findelement>");
400
-
401
- if (start == -1){
402
- position = 'singleton';
403
- element.insertAdjacentElement('afterend', findEl);
404
- if (dom.tagName == 'HTML')
405
- start = dom.outerHTML.indexOf("<findelement></findelement>");
406
- else
407
- start = dom.innerHTML.indexOf("<findelement></findelement>");
408
- }
409
-
410
- findEl.remove();
411
-
412
- let domString = dom.outerHTML.substring(0, start);
413
-
414
- if (dom.tagName == "HTML") {
415
- let htmlIndex = string.indexOf('<html');
416
- let documentType = string.substring(0, htmlIndex);
417
- documentTypeAngles = documentType.split(angle).length -1;
418
- }
419
- let angles = domString.split(angle);
420
- let angleLength = angles.length - 1;
421
- if (documentTypeAngles)
422
- angleLength += documentTypeAngles;
423
- let elStart = getPosition(string, angle, angleLength);
424
-
425
- if (position == 'afterbegin')
426
- elStart += 1;
427
- else if (position == 'beforeend')
428
- elStart += 1;
429
- else if (position == 'afterend')
430
- elStart += 1;
431
- else if (position == 'singleton'){
432
- let newString = string.substring(0, elStart);
433
- if (newString.lastIndexOf('/') == newString.length - 1 && isAttribute)
434
- elStart;
435
- else
436
- elStart += 1;
437
- }
438
- return elStart;
439
- }
440
-
441
- function getPosition(string, subString, index) {
442
- let angleArray = string.split(subString, index);
443
- let startstring = angleArray.join(subString);
444
- let start = startstring.length;
445
- return start;
446
- // return string.split(subString, index).join(subString).length;
447
- }
448
-
1
+ import {cssPath, domParser} from '@cocreate/utils';
2
+
3
+ String.prototype.customSplice = function(index, absIndex, string) {
4
+ return this.slice(0, index) + string + this.slice(index + Math.abs(absIndex));
5
+ };
6
+
7
+ export function getSelection(element) {
8
+ if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
9
+ return {
10
+ start: element.selectionStart,
11
+ end: element.selectionEnd
12
+ };
13
+ }
14
+ else {
15
+ let Document = element.ownerDocument;
16
+ let selection = Document.getSelection();
17
+ if (!selection.rangeCount) return { start: 0, end: 0 };
18
+
19
+ 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
+
33
+ if (range.startContainer != range.endContainer) {
34
+ // TODO: replace common ancestor value
35
+ }
36
+ let contenteditable = range.startContainer.parentElement.closest('[contenteditable][collection][document_id][name]');
37
+ if (contenteditable){
38
+ element = contenteditable;
39
+ }
40
+ let domTextEditor = element;
41
+ 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
+ }
53
+ }
54
+
55
+ let startContainer = range.startContainer;
56
+ if (startContainer.nodeType == 3)
57
+ startContainer = range.startContainer.parentElement;
58
+
59
+ let endContainer = range.endContainer;
60
+ if (endContainer.nodeType == 3)
61
+ endContainer = range.endContainer.parentElement;
62
+
63
+ let rangeObj = {
64
+ element: contenteditable,
65
+ // domTextEditor,
66
+ startOffset: range.startOffset,
67
+ endOffset: range.endOffset,
68
+ startContainer,
69
+ endContainer,
70
+ elementStart,
71
+ elementEnd
72
+ };
73
+ return { start, end, range: rangeObj};
74
+ }
75
+
76
+ }
77
+
78
+ export function processSelection(element, value = "", prev_start, prev_end, start, end, range) {
79
+ let prevStart = prev_start;
80
+ let prevEnd = prev_end;
81
+ if (prev_start >= start) {
82
+ if (value == "") {
83
+ prev_start -= end - start;
84
+ prev_end -= end - start;
85
+ prev_start = prev_start < start ? start : prev_start;
86
+ }
87
+ else {
88
+ prev_start += value.length;
89
+ prev_end += value.length;
90
+ }
91
+ } {
92
+ if (value == "" && prev_end >= start) {
93
+ prev_end = (prev_end >= end) ? prev_end - (end - start) : start;
94
+ }
95
+ }
96
+ if (range) {
97
+ if (prevStart > prev_start){
98
+ let length = prevStart - prev_start;
99
+ if (Math.sign(length) === 1 && range.startOffset >= length)
100
+ range.startOffset -= length;
101
+ }
102
+ else if (prevStart < prev_start){
103
+ let length = prev_start - prevStart;
104
+ if (Math.sign(length) === 1)
105
+ if (range.startOffset == 0 || range.startOffset >= length)
106
+ range.startOffset += length;
107
+ }
108
+ if (prevEnd > prev_end){
109
+ let length = prevEnd - prev_end;
110
+ if (Math.sign(length) === 1 && range.endOffset >= length)
111
+ range.endOffset -= length;
112
+ }
113
+ else if (prevEnd < prev_end){
114
+ let length = prev_end - prevEnd;
115
+ if (Math.sign(length) === 1)
116
+ if (range.endOffset == 0 || range.endOffset >= length)
117
+ range.endOffset += length;
118
+ }
119
+ }
120
+
121
+ setSelection(element, prev_start, prev_end, range);
122
+ return {element, value, start, end, prev_start, prev_end};
123
+ }
124
+
125
+ export function setSelection(element, start, end, range) {
126
+ if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
127
+ element.selectionStart = start;
128
+ element.selectionEnd = end;
129
+ }
130
+ else {
131
+ if (!range) return;
132
+ let Document = element.ownerDocument;
133
+
134
+ let startContainer = getContainer(range.startContainer, range.startOffset);
135
+ let endContainer = getContainer(range.endContainer, range.endOffset);
136
+
137
+ if (!startContainer || !endContainer)
138
+ return;
139
+
140
+ let selection = Document.getSelection();
141
+ selection.removeAllRanges();
142
+
143
+ const newRange = Document.createRange();
144
+ newRange.setStart(startContainer, range.startOffset);
145
+ newRange.setEnd(endContainer, range.endOffset);
146
+
147
+ selection.addRange(newRange);
148
+ }
149
+ }
150
+
151
+ function getContainer(element, offset){
152
+ 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
+ }
161
+ }
162
+ }
163
+
164
+ export function hasSelection(el) {
165
+ let { start, end } = getSelection(el);
166
+ if (start != end) {
167
+ return true;
168
+ }
169
+ }
170
+
171
+ export function getElementPosition(str, start, end) {
172
+ let response = {};
173
+ let startString = str.substring(0, start);
174
+ let endString = str.substring(start);
175
+ let angleStart = startString.lastIndexOf("<");
176
+ let angleEnd = startString.lastIndexOf(">");
177
+ let endStringAngleEnd = endString.indexOf(">");
178
+ let element, position, nodeStart, nodeEnd, startNode, type;
179
+ if (angleEnd > angleStart) {
180
+ let length = 0;
181
+ if (start != end)
182
+ length = end - start;
183
+ let string = str.customSplice(start, length, '<findelement></findelement>');
184
+ let newDom = domParser(string);
185
+ let findEl = newDom.querySelector('findelement');
186
+ if (findEl) {
187
+ let insert = getInsertPosition(findEl);
188
+ element = insert.target;
189
+ position = insert.position;
190
+ type = 'insertAdjacent';
191
+ if (!position)
192
+ type = 'textNode';
193
+ if (position == 'beforeend' && findEl.previousSibling && findEl.previousSibling.nodeType == 3 )
194
+ type = 'textNode';
195
+ if (type == 'textNode' || position == 'afterbegin')
196
+ nodeStart = start - angleEnd - 1;
197
+
198
+ findEl.remove();
199
+ }
200
+ }
201
+ else if (angleStart == -1) {
202
+ type = 'textNode';
203
+ }
204
+ else {
205
+ let node = str.slice(angleStart, startString.length + endStringAngleEnd + 1);
206
+ if (node.startsWith("</")) {
207
+ startNode = node.slice(0, 1) + node.slice(2);
208
+ startNode = startNode.substring(0, startNode.length - 1);
209
+ nodeStart = startString.lastIndexOf(startNode);
210
+ let endString1 = str.substring(nodeStart);
211
+ let end = endString1.indexOf(">");
212
+ nodeEnd = nodeStart + end + 1;
213
+ type = 'isEndTag';
214
+ }
215
+ else {
216
+ nodeEnd = startString.length + endStringAngleEnd + 1;
217
+ startNode = node;
218
+ nodeStart = angleStart;
219
+ type = 'isStartTag';
220
+ }
221
+ if (nodeEnd > 0) {
222
+ let string = str.customSplice(nodeEnd - 1, 0, ' findelement');
223
+ let newDom = domParser(string);
224
+ element = newDom.querySelector('[findelement]');
225
+ if (!element && newDom.tagName == 'HTML')
226
+ element = newDom;
227
+ else if (type == "isEndTag")
228
+ element = element.parentElement;
229
+ element.removeAttribute('findelement');
230
+ }
231
+ else {
232
+ let string = str.customSplice(angleStart, 0, '<findelement></findelement>');
233
+ let newDom = domParser(string);
234
+ element = newDom.querySelector('findelement');
235
+ if (element) {
236
+ let insert = getInsertPosition(element);
237
+ element = insert.target.parentElement;
238
+ position = insert.position;
239
+ if (position == 'afterend')
240
+ element = element.parentElement;
241
+ type = 'innerHTML';
242
+ }
243
+ if (!element) {
244
+ console.log('Could not find element');
245
+ }
246
+ }
247
+ }
248
+
249
+ if (element) {
250
+ response.element = element;
251
+ response.path = cssPath(element);
252
+ response.position = position;
253
+ response.start = nodeStart;
254
+ response.end = nodeEnd;
255
+ response.type = type;
256
+ }
257
+
258
+ return response;
259
+ }
260
+
261
+ function getInsertPosition(element){
262
+ let target, position;
263
+ let previousSibling = element.previousSibling;
264
+ let nextSibling = element.nextSibling;
265
+ if (previousSibling || nextSibling) {
266
+ if (!previousSibling) {
267
+ target = element.parentElement;
268
+ position = 'afterbegin';
269
+ }
270
+ else if (!nextSibling) {
271
+ target = element.parentElement;
272
+ position = 'beforeend';
273
+ }
274
+ else if (previousSibling && previousSibling.nodeType == 1) {
275
+ target = previousSibling;
276
+ position = 'afterend';
277
+ }
278
+ else if (nextSibling && nextSibling.nodeType == 1) {
279
+ target = element.parentElement;
280
+ position = 'afterbegin';
281
+ }
282
+ else {
283
+ target = element.parentElement;
284
+ }
285
+ }
286
+ else {
287
+ target = element.parentElement;
288
+ position = 'afterbegin';
289
+ }
290
+ return {target, position};
291
+ }
292
+
293
+ export function getStringPosition({string, target, position, attribute, property, value, remove}) {
294
+ try {
295
+ let element;
296
+ let selector = cssPath(target, '[contenteditable]');
297
+ let dom = domParser(string);
298
+ if (!selector.includes('[eid=') && dom.tagName == "DOM-PARSER"){
299
+ let containerEl = document.createElement('div');
300
+ containerEl.appendChild(dom)
301
+ selector = `dom-parser > ${selector}`
302
+ element = containerEl.querySelector(selector);
303
+ }
304
+ else
305
+ element = dom.querySelector(selector);
306
+ if (!element){
307
+ // console.log('element could not be found using selector:', selector);
308
+ return;
309
+ }
310
+ let start = 0, end = 0;
311
+
312
+ if (position) {
313
+ if (position == 'beforebegin')
314
+ start = getElFromString(dom, string, element, position, true);
315
+ else
316
+ start = getElFromString(dom, string, element, position);
317
+ end = start;
318
+ }
319
+ else if (attribute) {
320
+ if (!element.hasAttribute(attribute)){
321
+ start = getElFromString(dom, string, element, 'afterbegin', true) - 1;
322
+ end = start;
323
+ }
324
+ else {
325
+ start = getElFromString(dom, string, element, 'beforebegin');
326
+ let elString = string.substring(start);
327
+ let attrValue = element.getAttribute(attribute);
328
+ let attrStart = elString.indexOf(` ${attribute}=`);
329
+ start = start + attrStart;
330
+ if (attribute == 'style') {
331
+ if (remove)
332
+ element.style.removeProperty(property);
333
+ else
334
+ element.style[property] = value;
335
+ value = element.getAttribute(attribute);
336
+ }
337
+ else if (attribute == 'class') {
338
+ let [prop, val] = value.split(':');
339
+ if (prop && val){
340
+ if (attrValue.includes(`${prop}:`)){
341
+ let propStart = attrValue.indexOf(`${prop}:`);
342
+ let propString = attrValue.substring(propStart);
343
+ let propEnd = propString.indexOf(" ");
344
+ if (propEnd > 0)
345
+ propString = propString.slice(0, propEnd);
346
+ element.classList.remove(propString);
347
+ }
348
+ }
349
+ if (!remove)
350
+ element.classList.add(value);
351
+ value = element.getAttribute(attribute);
352
+ }
353
+ else {
354
+ element.setAttribute(attribute, value);
355
+ value = element.getAttribute(attribute);
356
+ }
357
+ end = start + attribute.length + attrValue.length + 4;
358
+ }
359
+ }
360
+ else if (value) {
361
+ start = getElFromString(dom, string, element, 'afterbegin');
362
+ let length = element.innerHTML.length;
363
+ end = start + length;
364
+ }
365
+ else {
366
+ start = getElFromString(dom, string, element, 'beforebegin');
367
+ end = getElFromString(dom, string, element, 'afterend', true);
368
+ }
369
+
370
+ return {start, end, newValue: value};
371
+ }
372
+ catch (e){
373
+ console.log(e);
374
+ }
375
+ }
376
+
377
+ function getElFromString(dom, string, element, position, isAttribute) {
378
+ let findEl = document.createElement('findelement');
379
+ let start, angle, documentTypeAngles;
380
+ if (position == 'afterbegin') {
381
+ element.insertAdjacentElement('afterbegin', findEl);
382
+ angle = '>';
383
+ }
384
+ else if (position == 'afterend') {
385
+ element.insertAdjacentElement('afterend', findEl);
386
+ angle = '>';
387
+ }
388
+ else if (position == 'beforebegin'){
389
+ element.insertAdjacentElement('afterbegin', findEl);
390
+ angle = '<';
391
+ }
392
+ else if (position == 'beforeend'){
393
+ element.insertAdjacentElement('afterend', findEl);
394
+ angle = '<';
395
+ }
396
+ if (dom.tagName == 'HTML')
397
+ start = dom.outerHTML.indexOf("<findelement></findelement>");
398
+ else
399
+ start = dom.innerHTML.indexOf("<findelement></findelement>");
400
+
401
+ if (start == -1){
402
+ position = 'singleton';
403
+ element.insertAdjacentElement('afterend', findEl);
404
+ if (dom.tagName == 'HTML')
405
+ start = dom.outerHTML.indexOf("<findelement></findelement>");
406
+ else
407
+ start = dom.innerHTML.indexOf("<findelement></findelement>");
408
+ }
409
+
410
+ findEl.remove();
411
+
412
+ let domString = dom.outerHTML.substring(0, start);
413
+
414
+ if (dom.tagName == "HTML") {
415
+ let htmlIndex = string.indexOf('<html');
416
+ let documentType = string.substring(0, htmlIndex);
417
+ documentTypeAngles = documentType.split(angle).length -1;
418
+ }
419
+ let angles = domString.split(angle);
420
+ let angleLength = angles.length - 1;
421
+ if (documentTypeAngles)
422
+ angleLength += documentTypeAngles;
423
+ let elStart = getPosition(string, angle, angleLength);
424
+
425
+ if (position == 'afterbegin')
426
+ elStart += 1;
427
+ else if (position == 'beforeend')
428
+ elStart += 1;
429
+ else if (position == 'afterend')
430
+ elStart += 1;
431
+ else if (position == 'singleton'){
432
+ let newString = string.substring(0, elStart);
433
+ if (newString.lastIndexOf('/') == newString.length - 1 && isAttribute)
434
+ elStart;
435
+ else
436
+ elStart += 1;
437
+ }
438
+ return elStart;
439
+ }
440
+
441
+ function getPosition(string, subString, index) {
442
+ let angleArray = string.split(subString, index);
443
+ let startstring = angleArray.join(subString);
444
+ let start = startstring.length;
445
+ return start;
446
+ // return string.split(subString, index).join(subString).length;
447
+ }
448
+
449
449
  export default {getSelection, setSelection, hasSelection, processSelection, getStringPosition, getElementPosition};