@sikka/hawa 0.0.237 → 0.0.238
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/dist/styles.css +0 -6
- package/docs/documentation/iframe.html +1 -1
- package/docs/documentation/{main.53a90744.iframe.bundle.js → main.0607e052.iframe.bundle.js} +1 -1
- package/docs/documentation/project.json +1 -1
- package/es/index.es.js +1 -1
- package/lib/index.js +1 -1
- package/package.json +1 -1
- package/src/elements/FloatingComment.tsx +234 -698
- package/src/styles.css +0 -6
|
@@ -47,9 +47,11 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
47
47
|
content: "",
|
|
48
48
|
stylings: [], // A styling is an object with 2 indices specifying a substring of text, and the applied effect
|
|
49
49
|
revert: [0, 0],
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
clipboard: [],
|
|
51
|
+
events: {
|
|
52
|
+
paste: { is: false, length: null },
|
|
53
|
+
drop: { is: false, text: null, drag: null },
|
|
54
|
+
},
|
|
53
55
|
})
|
|
54
56
|
|
|
55
57
|
const field = useRef(null)
|
|
@@ -112,53 +114,10 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
112
114
|
if (document.activeElement != field.current) return [0, 0]
|
|
113
115
|
|
|
114
116
|
let selection = window.getSelection()
|
|
115
|
-
// let nodes = Array.from(field.current.childNodes)
|
|
116
|
-
|
|
117
|
-
// console.log(nodes)
|
|
118
|
-
|
|
119
|
-
// nodes = nodes.filter(
|
|
120
|
-
// (item: any) => !["#text", "BR"].includes(item.nodeName)
|
|
121
|
-
// )
|
|
122
|
-
|
|
123
|
-
// console.log(selection.anchorNode)
|
|
124
|
-
// console.log(selection.focusNode)
|
|
125
|
-
// console.log(selection.anchorNode.parentNode)
|
|
126
|
-
// console.log(selection.focusNode.parentNode)
|
|
127
|
-
// console.log(selection.anchorNode.parentNode.parentNode)
|
|
128
|
-
// console.log(selection.focusNode.parentNode.parentNode)
|
|
129
|
-
// console.log(selection.anchorOffset)
|
|
130
|
-
// console.log(selection.focusOffset)
|
|
131
|
-
|
|
132
|
-
// let startParent: any = selection.anchorNode.parentNode
|
|
133
|
-
|
|
134
|
-
// let startNodeIndex =
|
|
135
|
-
// startParent == field.current
|
|
136
|
-
// ? nodes.length
|
|
137
|
-
// : // : parseInt(startParent.dataset.childIndex)
|
|
138
|
-
// getChildIndex(startParent)
|
|
139
|
-
|
|
140
|
-
// let startPrecedingSum = nodes
|
|
141
|
-
// .slice(0, startNodeIndex)
|
|
142
|
-
// .map((span: any) => span.textContent.length)
|
|
143
|
-
// .reduce((a, b) => a + b, 0)
|
|
144
117
|
|
|
145
118
|
let startPrecedingSum = getSelectionPrecedingSum("anchorNode")
|
|
146
|
-
|
|
147
|
-
// let endParent: any = selection.focusNode.parentNode
|
|
148
|
-
// let endNodeIndex =
|
|
149
|
-
// endParent == field.current
|
|
150
|
-
// ? nodes.length
|
|
151
|
-
// : // : parseInt(endParent.dataset.childIndex)
|
|
152
|
-
// getChildIndex(endParent)
|
|
153
|
-
|
|
154
|
-
// let endPrecedingSum = nodes
|
|
155
|
-
// .slice(0, endNodeIndex)
|
|
156
|
-
// .map((span: any) => span.textContent.length)
|
|
157
|
-
// .reduce((a, b) => a + b, 0)
|
|
158
|
-
|
|
159
119
|
let endPrecedingSum = getSelectionPrecedingSum("focusNode")
|
|
160
120
|
|
|
161
|
-
console.log([startPrecedingSum, endPrecedingSum])
|
|
162
121
|
let result = [
|
|
163
122
|
startPrecedingSum + selection.anchorOffset,
|
|
164
123
|
endPrecedingSum + selection.focusOffset,
|
|
@@ -369,36 +328,6 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
369
328
|
})
|
|
370
329
|
}
|
|
371
330
|
|
|
372
|
-
const getRangeIntersectStylings = (start, end, startOffset, finishOffset) => {
|
|
373
|
-
// Get all stylings intersecting
|
|
374
|
-
let stylings = []
|
|
375
|
-
for (let i = start; i < end; i++) {
|
|
376
|
-
stylings.push(getIntersectStylings(i, startOffset, finishOffset))
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// Remove duplicates
|
|
380
|
-
stylings = stylings.flat().filter((item) => item)
|
|
381
|
-
stylings = stylings.filter(
|
|
382
|
-
(item, index) =>
|
|
383
|
-
stylings.findIndex(
|
|
384
|
-
(_item) =>
|
|
385
|
-
_item.start == item.start &&
|
|
386
|
-
_item.finish == item.finish &&
|
|
387
|
-
_item.type == item.type
|
|
388
|
-
) == index
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
return stylings
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const compareStylings = (styling1, styling2) => {
|
|
395
|
-
return (
|
|
396
|
-
styling1.type == styling2.type &&
|
|
397
|
-
styling1.start == styling2.start &&
|
|
398
|
-
styling1.finish == styling2.finish
|
|
399
|
-
)
|
|
400
|
-
}
|
|
401
|
-
|
|
402
331
|
// Get stylings encompassing an index within it's range
|
|
403
332
|
const getIntersectStylings = (index, startOffset = 0, finishOffset = 0) => {
|
|
404
333
|
// Find all stylings with encompassing range
|
|
@@ -410,647 +339,306 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
410
339
|
return matches
|
|
411
340
|
}
|
|
412
341
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
const getStylingIndex = (styling) => {
|
|
422
|
-
return text.stylings.findIndex(
|
|
423
|
-
(item) =>
|
|
424
|
-
item.start == styling.start &&
|
|
425
|
-
item.finish == styling.finish &&
|
|
426
|
-
item.type == styling.type
|
|
427
|
-
)
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const handleScenario = (stylings, predicate) => {
|
|
431
|
-
let matches = stylings.filter(({ start: _start, finish: _finish }) =>
|
|
432
|
-
predicate(_start, _finish)
|
|
433
|
-
)
|
|
434
|
-
|
|
435
|
-
let indices = []
|
|
436
|
-
|
|
437
|
-
stylings.map((styling, index) => {
|
|
438
|
-
let result = matches.find((item) => compareStylings(styling, item))
|
|
439
|
-
if (!result) return
|
|
440
|
-
indices.push({
|
|
441
|
-
index: index,
|
|
442
|
-
type: styling.type,
|
|
443
|
-
start: styling.start,
|
|
444
|
-
finish: styling.finish,
|
|
445
|
-
})
|
|
446
|
-
})
|
|
447
|
-
|
|
448
|
-
return indices
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
const handleDeletion = (length, start, end) => {
|
|
452
|
-
let stylings = _text.current.stylings.slice()
|
|
453
|
-
let changes = []
|
|
454
|
-
|
|
455
|
-
// TODO: Refactor
|
|
456
|
-
|
|
457
|
-
// Offset all succeeding stylings by length
|
|
458
|
-
// changes.push(
|
|
459
|
-
// handleScenario(
|
|
460
|
-
// stylings,
|
|
461
|
-
// (_start, _finish) => start < _start && end <= start
|
|
462
|
-
// ).map((styling) => {
|
|
463
|
-
// return {
|
|
464
|
-
// ...styling,
|
|
465
|
-
// start: styling.start - length,
|
|
466
|
-
// finish: styling.finish - length,
|
|
467
|
-
// }
|
|
468
|
-
// })
|
|
469
|
-
// )
|
|
470
|
-
|
|
471
|
-
let succeeding = stylings.filter(
|
|
472
|
-
({ start: _start }) => start < _start && end <= _start
|
|
473
|
-
)
|
|
474
|
-
stylings.map((styling, index) => {
|
|
475
|
-
let result = succeeding.find((item) => compareStylings(styling, item))
|
|
476
|
-
if (!result) return
|
|
477
|
-
|
|
478
|
-
changes.push({
|
|
479
|
-
index: index,
|
|
480
|
-
start: styling.start - length,
|
|
481
|
-
finish: styling.finish - length,
|
|
482
|
-
})
|
|
483
|
-
})
|
|
484
|
-
|
|
485
|
-
// Handle complete encapsulation over styling
|
|
486
|
-
let encapsulating = stylings.filter(
|
|
487
|
-
({ start: _start, finish: _finish }) => start <= _start && end >= _finish
|
|
488
|
-
)
|
|
489
|
-
stylings.map((styling, index) => {
|
|
490
|
-
let result = encapsulating.find((item) => compareStylings(styling, item))
|
|
491
|
-
if (!result) return
|
|
492
|
-
|
|
493
|
-
// This will effectively remove the styling, since collapsed ranges are automatically removed
|
|
494
|
-
changes.push({
|
|
495
|
-
index: index,
|
|
496
|
-
start: styling.start,
|
|
497
|
-
finish: styling.start,
|
|
498
|
-
})
|
|
499
|
-
})
|
|
500
|
-
|
|
501
|
-
// Handle deletion being encapsulated by styling
|
|
502
|
-
let encapsulated = stylings.filter(
|
|
503
|
-
({ start: _start, finish: _finish }) =>
|
|
504
|
-
(start > _start && end <= _finish) || (start >= _start && end < _finish)
|
|
505
|
-
)
|
|
506
|
-
stylings.map((styling, index) => {
|
|
507
|
-
let result = encapsulated.find((item) => compareStylings(styling, item))
|
|
508
|
-
if (!result) return
|
|
509
|
-
|
|
510
|
-
changes.push({
|
|
511
|
-
index: index,
|
|
512
|
-
start: styling.start,
|
|
513
|
-
finish: styling.finish - length,
|
|
514
|
-
})
|
|
515
|
-
})
|
|
516
|
-
|
|
517
|
-
// Handle deletion being encapsulated by styling with left resumption
|
|
518
|
-
let leftResumption = stylings.filter(
|
|
519
|
-
({ start: _start, finish: _finish }) =>
|
|
520
|
-
end < _finish && end > _start && start < _start
|
|
521
|
-
)
|
|
522
|
-
stylings.map((styling, index) => {
|
|
523
|
-
let result = leftResumption.find((item) => compareStylings(styling, item))
|
|
524
|
-
if (!result) return
|
|
525
|
-
|
|
526
|
-
changes.push({
|
|
527
|
-
index: index,
|
|
528
|
-
start: getMaximum([end, styling.start]) - length,
|
|
529
|
-
finish: styling.finish - length,
|
|
530
|
-
})
|
|
531
|
-
})
|
|
532
|
-
|
|
533
|
-
let rightResumption = stylings.filter(
|
|
534
|
-
({ start: _start, finish: _finish }) =>
|
|
535
|
-
start > _start && start < _finish && end > _finish
|
|
342
|
+
const getStylingsInRange = (stylings, startIndex, endIndex) => {
|
|
343
|
+
// Get all intersecting stylings within range
|
|
344
|
+
let result = stylings.filter(
|
|
345
|
+
({ start, finish }) =>
|
|
346
|
+
(finish > startIndex && start < endIndex) ||
|
|
347
|
+
(start < endIndex && finish > startIndex)
|
|
536
348
|
)
|
|
537
|
-
stylings.map((styling, index) => {
|
|
538
|
-
let result = rightResumption.find((item) =>
|
|
539
|
-
compareStylings(styling, item)
|
|
540
|
-
)
|
|
541
|
-
if (!result) return
|
|
542
349
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
// Apply changes
|
|
551
|
-
changes.map(({ index, start, finish }) => {
|
|
552
|
-
stylings[index] = {
|
|
553
|
-
...stylings[index],
|
|
554
|
-
start: start,
|
|
555
|
-
finish: finish,
|
|
350
|
+
// Clamp start and end values, and offset by start index to reach the relative minimum
|
|
351
|
+
result = result.map((styling) => {
|
|
352
|
+
return {
|
|
353
|
+
...styling,
|
|
354
|
+
start: getMaximum([styling.start, startIndex]) - startIndex,
|
|
355
|
+
finish: getMinimum([styling.finish, endIndex]) - startIndex,
|
|
556
356
|
}
|
|
557
357
|
})
|
|
558
358
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
// if (start >= styling.start && end <= styling.finish) {
|
|
562
|
-
// console.log("hi")
|
|
563
|
-
// }
|
|
564
|
-
|
|
565
|
-
// return styling
|
|
566
|
-
// })
|
|
567
|
-
|
|
568
|
-
// If deletion is surrounded by styling, decrease finish by length (this might not include first character, but try first)
|
|
569
|
-
// If deletion is intersecting with a styling behind it, get maximum between deletion finish and styling start, and set the start to it, then offset styling by length
|
|
570
|
-
// If deletion is intersecting wit ha styling after it, get minimum between deletion start and styling finish, and set the finish to it
|
|
359
|
+
return result
|
|
360
|
+
}
|
|
571
361
|
|
|
572
|
-
|
|
362
|
+
const splitStyling = (styling, index, offset = 0) => {
|
|
363
|
+
// Get first split
|
|
364
|
+
let first = {
|
|
365
|
+
...styling,
|
|
366
|
+
start: styling.start,
|
|
367
|
+
finish: index,
|
|
368
|
+
}
|
|
573
369
|
|
|
574
|
-
//
|
|
370
|
+
// Get second split
|
|
371
|
+
let second = {
|
|
372
|
+
...styling,
|
|
373
|
+
start: index + offset,
|
|
374
|
+
finish: styling.finish + offset,
|
|
375
|
+
}
|
|
575
376
|
|
|
576
|
-
return
|
|
377
|
+
return [first, second]
|
|
577
378
|
}
|
|
578
379
|
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
end -= length + 1
|
|
380
|
+
const additionTo = (stylings, startIndex, length, defaultBehavior = true) => {
|
|
381
|
+
// console.log(`Adding text of length ${length} at index ${startIndex}`)
|
|
582
382
|
|
|
583
|
-
|
|
383
|
+
// Required operations:
|
|
384
|
+
// Offset succeeding stylings
|
|
385
|
+
// Split intersecting stylings
|
|
386
|
+
// Styling continuation at end (only for normal addition)
|
|
584
387
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
finish: styling.finish + length,
|
|
388
|
+
stylings = stylings.map((styling) => {
|
|
389
|
+
// A succeeding styling
|
|
390
|
+
if (styling.start >= startIndex && styling.finish > startIndex) {
|
|
391
|
+
console.log("succeeding")
|
|
392
|
+
return {
|
|
393
|
+
...styling,
|
|
394
|
+
start: styling.start + length,
|
|
395
|
+
finish: styling.finish + length,
|
|
396
|
+
}
|
|
595
397
|
}
|
|
596
|
-
})
|
|
597
|
-
changes.push(succeeding)
|
|
598
398
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
).map((styling) => {
|
|
612
|
-
return {
|
|
613
|
-
...styling,
|
|
614
|
-
start: styling.start,
|
|
615
|
-
finish: styling.finish + length,
|
|
399
|
+
// An intersecting styling
|
|
400
|
+
if (styling.start < startIndex && styling.finish > startIndex) {
|
|
401
|
+
// Normal addition (non-drop & non-paste), adds to the length of the styling
|
|
402
|
+
if (defaultBehavior) {
|
|
403
|
+
return {
|
|
404
|
+
...styling,
|
|
405
|
+
finish: styling.finish + length,
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
// Special addition (drop & paste), splits the styling and offsets the second half by length of addition
|
|
409
|
+
return splitStyling(styling, startIndex, length)
|
|
410
|
+
}
|
|
616
411
|
}
|
|
617
|
-
})
|
|
618
|
-
changes.push(preceding)
|
|
619
412
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
413
|
+
// A connected styling at the end
|
|
414
|
+
if (styling.finish == startIndex) {
|
|
415
|
+
// Normal addition (non-drop & non-paste), continues the styling by addition length
|
|
416
|
+
if (defaultBehavior) {
|
|
417
|
+
return {
|
|
418
|
+
...styling,
|
|
419
|
+
finish: styling.finish + length,
|
|
420
|
+
}
|
|
421
|
+
}
|
|
627
422
|
}
|
|
423
|
+
|
|
424
|
+
return styling
|
|
628
425
|
})
|
|
629
426
|
|
|
630
|
-
|
|
427
|
+
return stylings.flat()
|
|
428
|
+
}
|
|
631
429
|
|
|
632
|
-
|
|
430
|
+
const deletionOf = (stylings, startIndex, endIndex) => {
|
|
431
|
+
// console.log(`Removing text from ${startIndex} to ${endIndex}`)
|
|
633
432
|
|
|
634
|
-
|
|
433
|
+
let length = Math.abs(endIndex - startIndex)
|
|
635
434
|
|
|
636
|
-
//
|
|
637
|
-
//
|
|
638
|
-
//
|
|
435
|
+
// Required operations:
|
|
436
|
+
// Offset succeeding stylings
|
|
437
|
+
// Remove stylings completely within range
|
|
438
|
+
// Shrink stylings surrounding range
|
|
439
|
+
// Clamp left resumptions and offset
|
|
440
|
+
// Clamp right resumptions
|
|
639
441
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
start
|
|
644
|
-
|
|
442
|
+
stylings = stylings.map((styling) => {
|
|
443
|
+
// A succeeding styling, but not a right resumption
|
|
444
|
+
if (
|
|
445
|
+
styling.start >= startIndex &&
|
|
446
|
+
styling.start >= endIndex &&
|
|
447
|
+
styling.finish >= startIndex &&
|
|
448
|
+
styling.finish >= endIndex
|
|
449
|
+
) {
|
|
450
|
+
return {
|
|
451
|
+
...styling,
|
|
452
|
+
start: styling.start - length,
|
|
453
|
+
finish: styling.finish - length,
|
|
454
|
+
}
|
|
645
455
|
}
|
|
646
|
-
})
|
|
647
|
-
|
|
648
|
-
return stylings
|
|
649
|
-
}
|
|
650
456
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
// console.log(stylings)
|
|
655
|
-
let changes = []
|
|
656
|
-
|
|
657
|
-
// Get stylings being encapsulated by pasting range
|
|
658
|
-
let encapsulating = handleScenario(
|
|
659
|
-
stylings,
|
|
660
|
-
(_start, _end) => start <= _start && end >= _end // This is needed because of conflict with addition/deletion
|
|
661
|
-
).map((styling) => {
|
|
662
|
-
// Effective removal
|
|
663
|
-
return {
|
|
664
|
-
...styling,
|
|
665
|
-
start: styling.start,
|
|
666
|
-
finish: styling.start,
|
|
457
|
+
// A styling completely within deletion range
|
|
458
|
+
if (styling.start >= startIndex && styling.finish <= endIndex) {
|
|
459
|
+
return null
|
|
667
460
|
}
|
|
668
|
-
})
|
|
669
|
-
changes.push(encapsulating)
|
|
670
|
-
|
|
671
|
-
// Get encapsulated stylings
|
|
672
|
-
let encapsulated = handleScenario(
|
|
673
|
-
stylings,
|
|
674
|
-
(_start, _end) => _start < start && _end > end
|
|
675
|
-
).map((styling) => {
|
|
676
|
-
// Right splice
|
|
677
|
-
changes.push({
|
|
678
|
-
...styling,
|
|
679
|
-
index: -1,
|
|
680
|
-
start: end,
|
|
681
|
-
finish: styling.finish,
|
|
682
|
-
})
|
|
683
461
|
|
|
684
|
-
//
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
})
|
|
691
|
-
|
|
692
|
-
// Effective removal
|
|
693
|
-
return {
|
|
694
|
-
...styling,
|
|
695
|
-
start: styling.start,
|
|
696
|
-
finish: styling.start,
|
|
697
|
-
}
|
|
698
|
-
})
|
|
699
|
-
changes.push(encapsulated)
|
|
700
|
-
|
|
701
|
-
// Get intersecting stylings from the left
|
|
702
|
-
let left = handleScenario(
|
|
703
|
-
stylings,
|
|
704
|
-
(_start, _end) =>
|
|
705
|
-
_end > start && _end <= end - difference + 1 && _start < start
|
|
706
|
-
).map((styling) => {
|
|
707
|
-
return {
|
|
708
|
-
...styling,
|
|
709
|
-
finish: start,
|
|
462
|
+
// A styling surrounding deletion range
|
|
463
|
+
if (styling.start <= startIndex && styling.finish >= endIndex) {
|
|
464
|
+
return {
|
|
465
|
+
...styling,
|
|
466
|
+
finish: styling.finish - length,
|
|
467
|
+
}
|
|
710
468
|
}
|
|
711
|
-
})
|
|
712
|
-
|
|
713
|
-
changes.push(left)
|
|
714
469
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
...styling,
|
|
723
|
-
start: end,
|
|
470
|
+
// A styling not fully within deletion range, while the range exceeds to the left
|
|
471
|
+
if (styling.start > startIndex && styling.start < endIndex) {
|
|
472
|
+
return {
|
|
473
|
+
...styling,
|
|
474
|
+
start: getMaximum([styling.start, endIndex]) - length,
|
|
475
|
+
finish: styling.finish - length,
|
|
476
|
+
}
|
|
724
477
|
}
|
|
725
|
-
})
|
|
726
478
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
changes = changes.flat()
|
|
735
|
-
changes.map((styling) => {
|
|
736
|
-
let { index, start, finish } = styling
|
|
737
|
-
if (index == -1) {
|
|
738
|
-
stylings.push({
|
|
739
|
-
type: styling.type,
|
|
740
|
-
start: start,
|
|
741
|
-
finish: finish,
|
|
742
|
-
})
|
|
743
|
-
return
|
|
479
|
+
// A styling not full within deletion range, while the range exceeds to the right
|
|
480
|
+
if (styling.finish > startIndex && styling.finish < endIndex) {
|
|
481
|
+
return {
|
|
482
|
+
...styling,
|
|
483
|
+
finish: getMinimum([styling.finish, startIndex]),
|
|
484
|
+
}
|
|
744
485
|
}
|
|
745
486
|
|
|
746
|
-
|
|
747
|
-
...stylings[index],
|
|
748
|
-
start: start,
|
|
749
|
-
finish: finish,
|
|
750
|
-
}
|
|
487
|
+
return styling
|
|
751
488
|
})
|
|
752
489
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
return stylings
|
|
490
|
+
return stylings.flat().filter((styling) => styling)
|
|
756
491
|
}
|
|
757
492
|
|
|
758
|
-
const
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
// Possible refactorization:
|
|
776
|
-
// Since the drop invokes the onInput event twice, the first is the removal of dragged text, and the second is the addition of dropped text
|
|
777
|
-
// If the handling occurs at the second occurence of onInput, the first could be handled naturally by the handleDeletion function
|
|
493
|
+
const processNormal = (
|
|
494
|
+
stylings,
|
|
495
|
+
difference,
|
|
496
|
+
selectionStart,
|
|
497
|
+
selectionEnd
|
|
498
|
+
) => {
|
|
499
|
+
if (difference == 0) return stylings
|
|
500
|
+
|
|
501
|
+
if (difference > 0) {
|
|
502
|
+
stylings = additionTo(stylings, selectionStart - difference, difference)
|
|
503
|
+
} else {
|
|
504
|
+
stylings = deletionOf(
|
|
505
|
+
stylings,
|
|
506
|
+
selectionStart,
|
|
507
|
+
selectionEnd + Math.abs(difference)
|
|
508
|
+
)
|
|
509
|
+
}
|
|
778
510
|
|
|
779
|
-
|
|
511
|
+
return stylings
|
|
512
|
+
}
|
|
780
513
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
// (_end <= dp.start && _start < dp.start)
|
|
514
|
+
const processPaste = (stylings, difference, selectionStart, selectionEnd) => {
|
|
515
|
+
let pasteLength = _text.current.events.paste.length
|
|
784
516
|
|
|
785
|
-
//
|
|
786
|
-
|
|
787
|
-
// (_start >= dp.end && _end > dp.end)
|
|
517
|
+
// Get addition start index
|
|
518
|
+
let additionStart = selectionStart - pasteLength
|
|
788
519
|
|
|
789
|
-
// Get
|
|
790
|
-
let
|
|
791
|
-
|
|
792
|
-
!(
|
|
793
|
-
(start < dragStart && finish <= dragStart) ||
|
|
794
|
-
(start >= dragEnd && finish > dragEnd)
|
|
795
|
-
)
|
|
796
|
-
)
|
|
520
|
+
// Get removal range
|
|
521
|
+
let removalStart = additionStart
|
|
522
|
+
let removalEnd = additionStart + pasteLength - difference
|
|
797
523
|
|
|
798
|
-
//
|
|
799
|
-
stylings
|
|
800
|
-
.filter(({ start, finish }) => start >= dragEnd && finish > dragEnd)
|
|
801
|
-
.map((styling) => {
|
|
802
|
-
changes.push({
|
|
803
|
-
original: styling,
|
|
804
|
-
changed: {
|
|
805
|
-
...styling,
|
|
806
|
-
start: styling.start - dropped.length,
|
|
807
|
-
finish: styling.finish - dropped.length,
|
|
808
|
-
},
|
|
809
|
-
})
|
|
810
|
-
})
|
|
524
|
+
// Compute deletion
|
|
525
|
+
stylings = deletionOf(stylings, removalStart, removalEnd)
|
|
811
526
|
|
|
812
|
-
//
|
|
813
|
-
stylings
|
|
814
|
-
.filter(({ start, finish }) => dragStart <= start && dragEnd >= finish)
|
|
815
|
-
.map((styling) => {
|
|
816
|
-
changes.push({
|
|
817
|
-
original: styling,
|
|
818
|
-
changed: { ...styling, start: styling.start, finish: styling.start },
|
|
819
|
-
})
|
|
820
|
-
})
|
|
527
|
+
// Compute addition
|
|
528
|
+
stylings = additionTo(stylings, additionStart, pasteLength, false)
|
|
821
529
|
|
|
822
|
-
//
|
|
823
|
-
stylings
|
|
824
|
-
.
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
changes.push({
|
|
831
|
-
original: styling,
|
|
832
|
-
changed: {
|
|
833
|
-
...styling,
|
|
834
|
-
start: styling.start,
|
|
835
|
-
finish: styling.finish - dropped.length,
|
|
836
|
-
},
|
|
837
|
-
})
|
|
530
|
+
// Add rich copied stylings offset by paste start index
|
|
531
|
+
stylings = stylings.concat(
|
|
532
|
+
_text.current.clipboard.map((styling) => {
|
|
533
|
+
return {
|
|
534
|
+
...styling,
|
|
535
|
+
start: styling.start + additionStart,
|
|
536
|
+
finish: styling.finish + additionStart,
|
|
537
|
+
}
|
|
838
538
|
})
|
|
839
|
-
|
|
840
|
-
// Handle resumptions
|
|
841
|
-
let resumptions = stylings.filter(
|
|
842
|
-
({ start, finish }) =>
|
|
843
|
-
(finish > dragStart &&
|
|
844
|
-
start > dragStart &&
|
|
845
|
-
start < dragEnd &&
|
|
846
|
-
finish > dragEnd) ||
|
|
847
|
-
(start < dragEnd &&
|
|
848
|
-
finish < dragEnd &&
|
|
849
|
-
finish > dragStart &&
|
|
850
|
-
start < dragStart)
|
|
851
539
|
)
|
|
852
540
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
styling.start < dragEnd &&
|
|
856
|
-
styling.finish < dragEnd &&
|
|
857
|
-
styling.finish > dragStart &&
|
|
858
|
-
styling.start < dragStart
|
|
541
|
+
return stylings
|
|
542
|
+
}
|
|
859
543
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
changed: {
|
|
863
|
-
...styling,
|
|
864
|
-
start: !right
|
|
865
|
-
? getMaximum([dragEnd, styling.start]) - dropped.length // Only decrease if the drag
|
|
866
|
-
: styling.start,
|
|
867
|
-
finish: right
|
|
868
|
-
? getMinimum([dragStart, styling.finish])
|
|
869
|
-
: styling.finish - dropped.length,
|
|
870
|
-
},
|
|
871
|
-
})
|
|
872
|
-
})
|
|
544
|
+
const processDrop = (stylings, difference, dropStart, dropEnd) => {
|
|
545
|
+
let dropLength = _text.current.events.drop.text.length
|
|
873
546
|
|
|
874
|
-
|
|
875
|
-
changes.map(({ original, changed }) => {
|
|
876
|
-
let index = stylings.findIndex((styling) =>
|
|
877
|
-
compareStylings(original, styling)
|
|
878
|
-
)
|
|
547
|
+
let [dragStart, dragEnd] = _text.current.events.drop.drag
|
|
879
548
|
|
|
880
|
-
|
|
881
|
-
})
|
|
549
|
+
let dropDifference = dropStart - dragStart
|
|
882
550
|
|
|
883
|
-
|
|
551
|
+
// Get stylings at drag range
|
|
552
|
+
let dragStylings = getStylingsInRange(stylings, dragStart, dragEnd)
|
|
884
553
|
|
|
885
|
-
//
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
.map((styling) => {
|
|
889
|
-
changes.push({
|
|
890
|
-
original: styling,
|
|
891
|
-
changed: {
|
|
892
|
-
...styling,
|
|
893
|
-
start: styling.start + dropped.length,
|
|
894
|
-
finish: styling.finish + dropped.length,
|
|
895
|
-
},
|
|
896
|
-
})
|
|
897
|
-
})
|
|
554
|
+
// Removal range
|
|
555
|
+
let removalStart = dragStart
|
|
556
|
+
let removalEnd = dragEnd
|
|
898
557
|
|
|
899
|
-
//
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
changes.push({
|
|
904
|
-
original: styling,
|
|
905
|
-
changed: {
|
|
906
|
-
...styling,
|
|
907
|
-
start: styling.start,
|
|
908
|
-
finish: dropStart,
|
|
909
|
-
},
|
|
910
|
-
})
|
|
911
|
-
|
|
912
|
-
changes.push({
|
|
913
|
-
original: null,
|
|
914
|
-
changed: {
|
|
915
|
-
...styling,
|
|
916
|
-
start: dropEnd,
|
|
917
|
-
finish: styling.finish + dropped.length,
|
|
918
|
-
},
|
|
919
|
-
})
|
|
920
|
-
})
|
|
558
|
+
// If the drag precedes the drop (positive difference)
|
|
559
|
+
if (dropDifference > 0) {
|
|
560
|
+
// Addition start index
|
|
561
|
+
let additionStart = dropEnd
|
|
921
562
|
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
if (original == null) {
|
|
925
|
-
stylings.push(changed)
|
|
926
|
-
return
|
|
927
|
-
}
|
|
563
|
+
// Compute addition first
|
|
564
|
+
stylings = additionTo(stylings, additionStart, dropLength, false)
|
|
928
565
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
566
|
+
// Compute removal second
|
|
567
|
+
stylings = deletionOf(stylings, removalStart, removalEnd)
|
|
568
|
+
}
|
|
932
569
|
|
|
933
|
-
|
|
934
|
-
|
|
570
|
+
// If the drop precedes the drag (negative difference)
|
|
571
|
+
if (dropDifference < 0) {
|
|
572
|
+
// Addition start index
|
|
573
|
+
let additionStart = dropStart
|
|
935
574
|
|
|
936
|
-
|
|
937
|
-
|
|
575
|
+
// Compute removal first
|
|
576
|
+
stylings = deletionOf(stylings, removalStart, removalEnd)
|
|
938
577
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
...styling,
|
|
943
|
-
start: getMaximum([styling.start, dragStart]) - dragStart + dropStart,
|
|
944
|
-
finish: getMinimum([styling.finish, dragEnd]) - dragStart + dropStart,
|
|
945
|
-
}
|
|
946
|
-
})
|
|
578
|
+
// Compute addition second
|
|
579
|
+
stylings = additionTo(stylings, additionStart, dropLength, false)
|
|
580
|
+
}
|
|
947
581
|
|
|
948
|
-
//
|
|
949
|
-
stylings = stylings.concat(
|
|
582
|
+
// Add rich dragged stylings offset
|
|
583
|
+
stylings = stylings.concat(
|
|
584
|
+
dragStylings.map((styling) => {
|
|
585
|
+
return {
|
|
586
|
+
...styling,
|
|
587
|
+
start: styling.start + dropStart,
|
|
588
|
+
finish: styling.finish + dropStart,
|
|
589
|
+
}
|
|
590
|
+
})
|
|
591
|
+
)
|
|
950
592
|
|
|
951
|
-
|
|
952
|
-
..._text.current,
|
|
953
|
-
content: value,
|
|
954
|
-
stylings: stylings,
|
|
955
|
-
revert: [dropStart, dropEnd],
|
|
956
|
-
pasted: { status: false, length: 0 },
|
|
957
|
-
dropped: { status: false, text: "", previous: [0, 0] },
|
|
958
|
-
})
|
|
593
|
+
return stylings
|
|
959
594
|
}
|
|
960
595
|
|
|
961
596
|
const onChange = (value) => {
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
return
|
|
969
|
-
}
|
|
597
|
+
// Since drop events cause onChange to invoke twice, ignore the first incomplete event
|
|
598
|
+
if (
|
|
599
|
+
_text.current.events.drop.is &&
|
|
600
|
+
value.length != _text.current.content.length
|
|
601
|
+
)
|
|
602
|
+
return
|
|
970
603
|
|
|
604
|
+
setTimeout(function () {
|
|
971
605
|
let [selectionStart, selectionEnd] = getFieldSelection()
|
|
972
606
|
let difference = value.length - _text.current.content.length
|
|
607
|
+
let stylings = _text.current.stylings
|
|
973
608
|
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
let succeeding = getSucceedStylings(start)
|
|
980
|
-
let changes = []
|
|
981
|
-
|
|
982
|
-
for (let succeed of succeeding) {
|
|
983
|
-
let index = getStylingIndex(succeed)
|
|
984
|
-
let styling = stylings[index]
|
|
985
|
-
|
|
986
|
-
changes.push([
|
|
987
|
-
index,
|
|
988
|
-
styling.start + difference,
|
|
989
|
-
styling.finish + difference,
|
|
990
|
-
])
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
if (difference < 0) {
|
|
994
|
-
stylings = handleDeletion(
|
|
995
|
-
Math.abs(difference),
|
|
609
|
+
// Paste event
|
|
610
|
+
if (_text.current.events.paste.is) {
|
|
611
|
+
stylings = processPaste(
|
|
612
|
+
stylings,
|
|
613
|
+
difference,
|
|
996
614
|
selectionStart,
|
|
997
|
-
selectionEnd
|
|
615
|
+
selectionEnd
|
|
998
616
|
)
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
Math.abs(difference),
|
|
617
|
+
} else if (_text.current.events.drop.is) {
|
|
618
|
+
stylings = processDrop(
|
|
619
|
+
stylings,
|
|
620
|
+
difference,
|
|
1004
621
|
selectionStart,
|
|
1005
622
|
selectionEnd
|
|
1006
623
|
)
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
// Remove empty stylings and invisible stylings
|
|
1010
|
-
stylings = stylings.filter(
|
|
1011
|
-
(styling) =>
|
|
1012
|
-
!(
|
|
1013
|
-
styling.start == styling.finish ||
|
|
1014
|
-
(styling.start >= value.length && styling.finish >= value.length)
|
|
1015
|
-
)
|
|
1016
|
-
)
|
|
1017
|
-
|
|
1018
|
-
if (_text.current.pasted.status) {
|
|
1019
|
-
stylings = handlePaste(
|
|
624
|
+
} else {
|
|
625
|
+
stylings = processNormal(
|
|
1020
626
|
stylings,
|
|
1021
627
|
difference,
|
|
1022
|
-
selectionStart
|
|
1023
|
-
|
|
628
|
+
selectionStart,
|
|
629
|
+
selectionEnd
|
|
1024
630
|
)
|
|
1025
|
-
|
|
1026
|
-
for (let styling of _text.current.lastCopy) {
|
|
1027
|
-
styling = {
|
|
1028
|
-
...styling,
|
|
1029
|
-
start: styling.start + selectionStart - _text.current.pasted.length,
|
|
1030
|
-
finish:
|
|
1031
|
-
styling.finish + selectionStart - _text.current.pasted.length,
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
stylings.push(styling)
|
|
1035
|
-
}
|
|
1036
631
|
}
|
|
1037
632
|
|
|
1038
|
-
// Remove empty stylings and invisible stylings
|
|
1039
|
-
stylings = stylings.filter(
|
|
1040
|
-
(styling) =>
|
|
1041
|
-
!(
|
|
1042
|
-
styling.start == styling.finish ||
|
|
1043
|
-
(styling.start >= value.length && styling.finish >= value.length)
|
|
1044
|
-
)
|
|
1045
|
-
)
|
|
1046
|
-
|
|
1047
633
|
setText({
|
|
1048
634
|
..._text.current,
|
|
1049
635
|
content: value,
|
|
1050
636
|
stylings: stylings,
|
|
1051
637
|
revert: [selectionStart, selectionEnd],
|
|
1052
|
-
|
|
1053
|
-
|
|
638
|
+
events: {
|
|
639
|
+
paste: { is: false, length: null },
|
|
640
|
+
drop: { is: false, text: null, drag: null },
|
|
641
|
+
},
|
|
1054
642
|
})
|
|
1055
643
|
}, 0)
|
|
1056
644
|
}
|
|
@@ -1087,37 +675,6 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
1087
675
|
return result
|
|
1088
676
|
}
|
|
1089
677
|
|
|
1090
|
-
const serializeStyleInRange = (start, end) => {
|
|
1091
|
-
// Get all stylings intersecting
|
|
1092
|
-
let stylings = []
|
|
1093
|
-
for (let i = start; i < end; i++) {
|
|
1094
|
-
stylings.push(getIntersectStylings(i))
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// Remove duplicates
|
|
1098
|
-
stylings = stylings.flat().filter((item) => item)
|
|
1099
|
-
stylings = stylings.filter(
|
|
1100
|
-
(item, index) =>
|
|
1101
|
-
stylings.findIndex(
|
|
1102
|
-
(_item) =>
|
|
1103
|
-
_item.start == item.start &&
|
|
1104
|
-
_item.finish == item.finish &&
|
|
1105
|
-
_item.type == item.type
|
|
1106
|
-
) == index
|
|
1107
|
-
)
|
|
1108
|
-
|
|
1109
|
-
// Clamp start and finish values and offset by start index
|
|
1110
|
-
stylings = stylings.map((styling) => {
|
|
1111
|
-
return {
|
|
1112
|
-
...styling,
|
|
1113
|
-
start: getMaximum([styling.start, start]) - start,
|
|
1114
|
-
finish: getMinimum([styling.finish, end]) - start,
|
|
1115
|
-
}
|
|
1116
|
-
})
|
|
1117
|
-
|
|
1118
|
-
return stylings
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
678
|
// dangerouslySetInnerHTML incorrectly renders when the entire text is highlighted, copied, and then pasted in succession
|
|
1122
679
|
useEffect(() => {
|
|
1123
680
|
let html = getContent()
|
|
@@ -1126,8 +683,6 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
1126
683
|
|
|
1127
684
|
// Get stylings encompassing an index within it's range
|
|
1128
685
|
let stylings = getIntersectStylings(start)
|
|
1129
|
-
// console.log(data)
|
|
1130
|
-
// console.log(stylings)
|
|
1131
686
|
return `<span class="${stylings
|
|
1132
687
|
.map((styling) => stylers[styling.type].css)
|
|
1133
688
|
.join(" ")}" data-child-index="${index}">${data}</span>`
|
|
@@ -1150,22 +705,6 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
1150
705
|
}
|
|
1151
706
|
}
|
|
1152
707
|
|
|
1153
|
-
const calculateTextWidth = (
|
|
1154
|
-
text: string,
|
|
1155
|
-
font: { size: number; family: string }
|
|
1156
|
-
) => {
|
|
1157
|
-
let element = document.createElement("div")
|
|
1158
|
-
let { size, family } = font
|
|
1159
|
-
|
|
1160
|
-
element.className = `text-[${size}px] font-['${family}'] absolute float-left whitespace-nowrap invisible`
|
|
1161
|
-
element.innerHTML = text
|
|
1162
|
-
|
|
1163
|
-
document.body.appendChild(element)
|
|
1164
|
-
|
|
1165
|
-
let rect = element.getBoundingClientRect()
|
|
1166
|
-
return rect.width
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
708
|
return (
|
|
1170
709
|
<div className="align-center box-border flex h-min w-[400px] flex-col items-center justify-center rounded shadow-md">
|
|
1171
710
|
<div className={clsx("flex w-full flex-row justify-start p-2")}>
|
|
@@ -1197,24 +736,26 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
1197
736
|
const data = event.clipboardData.getData("text/plain")
|
|
1198
737
|
document.execCommand("insertHTML", false, data)
|
|
1199
738
|
|
|
1200
|
-
console.log(data)
|
|
1201
|
-
|
|
1202
739
|
setText({
|
|
1203
740
|
..._text.current,
|
|
1204
|
-
|
|
741
|
+
events: {
|
|
742
|
+
..._text.current.events,
|
|
743
|
+
paste: { is: true, length: data.length },
|
|
744
|
+
},
|
|
1205
745
|
})
|
|
1206
746
|
}}
|
|
1207
747
|
onInput={(event: any) => {
|
|
1208
748
|
onChange(event.target.textContent)
|
|
1209
749
|
}}
|
|
1210
|
-
onCopy={(
|
|
750
|
+
onCopy={() => {
|
|
1211
751
|
let [start, end] = getFieldSelection()
|
|
1212
752
|
|
|
1213
|
-
let
|
|
753
|
+
let stylings = _text.current.stylings.slice()
|
|
754
|
+
stylings = getStylingsInRange(stylings, start, end)
|
|
1214
755
|
|
|
1215
756
|
setText({
|
|
1216
757
|
...text,
|
|
1217
|
-
|
|
758
|
+
clipboard: stylings,
|
|
1218
759
|
})
|
|
1219
760
|
}}
|
|
1220
761
|
onDrop={(event) => {
|
|
@@ -1222,16 +763,11 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
1222
763
|
|
|
1223
764
|
if (text.trim() == "") return
|
|
1224
765
|
|
|
1225
|
-
// console.log(getSelectionPrecedingSum("anchorNode"))
|
|
1226
|
-
// console.log(getSelectionPrecedingSum("focusNode"))
|
|
1227
|
-
// console.log(window.getSelection())
|
|
1228
|
-
|
|
1229
766
|
setText({
|
|
1230
767
|
..._text.current,
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
text: text,
|
|
1234
|
-
previous: getFieldSelection(),
|
|
768
|
+
events: {
|
|
769
|
+
..._text.current.events,
|
|
770
|
+
drop: { is: true, text: text, drag: getFieldSelection() },
|
|
1235
771
|
},
|
|
1236
772
|
})
|
|
1237
773
|
}}
|