@cocreate/selection 1.6.10 → 1.6.12

Sign up to get free protection for your applications and to get access to all the features.
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};