@samuelbradshaw/highlight-helper-js 0.7.5 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/demo.html +12 -0
- package/highlight-helper.js +26 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,6 +101,9 @@ Options can be provided when Highlight Helper is initialized. They can also be s
|
|
|
101
101
|
- **defaultStyle** – Key of the default highlight style. Default: `fill`.
|
|
102
102
|
- **defaultWrapper** – Key of the default highlight wrapper. Default: `none`.
|
|
103
103
|
- **highlightIdFunction** – Identifier of a function that provides unique IDs for new highlights. Default: `hhGetNewHighlightId`.
|
|
104
|
+
- **showCustomSelectionHandlesForActiveHighlights** – Whether custom selection handles should show for active highlights. Default: `true`.
|
|
105
|
+
- **showCustomSelectionHandlesForTextSelection** – Whether custom selection handles should show for text selection. Default: `false`.
|
|
106
|
+
- **showCustomSelectionHandlesOnTouch** – Whether custom selection handles should show on touch devices. Default: `false`.
|
|
104
107
|
|
|
105
108
|
|
|
106
109
|
### <a name="custom-events"></a>Custom events
|
package/demo.html
CHANGED
|
@@ -147,6 +147,12 @@
|
|
|
147
147
|
<label><input type="radio" name="hh-drawing-mode" value="highlight-api"> Custom Highlight API</label><br>
|
|
148
148
|
<label><input type="radio" name="hh-drawing-mode" value="mark-elements"> HTML mark elements</label><br>
|
|
149
149
|
</p>
|
|
150
|
+
<p>
|
|
151
|
+
Show custom selection handles:<br>
|
|
152
|
+
<label><input type="checkbox" id="hh-selection-handles-active-highlights" checked> For active highlights</label><br>
|
|
153
|
+
<label><input type="checkbox" id="hh-selection-handles-text-selection"> For text selection</label><br>
|
|
154
|
+
<label><input type="checkbox" id="hh-selection-handles-touch"> On touch devices</label><br>
|
|
155
|
+
</p>
|
|
150
156
|
<b>Active highlight:</b>
|
|
151
157
|
<div id="snippet-container">
|
|
152
158
|
<div id="snippet">N/A</div>
|
|
@@ -263,6 +269,12 @@
|
|
|
263
269
|
}
|
|
264
270
|
});
|
|
265
271
|
}
|
|
272
|
+
const selectionHandlesActiveHighlightsCheckbox = document.getElementById('hh-selection-handles-active-highlights');
|
|
273
|
+
selectionHandlesActiveHighlightsCheckbox.addEventListener('change', (event) => { highlighter.setOption('showCustomSelectionHandlesForActiveHighlights', event.currentTarget.checked); });
|
|
274
|
+
const selectionHandlesTextSelectionCheckbox = document.getElementById('hh-selection-handles-text-selection');
|
|
275
|
+
selectionHandlesTextSelectionCheckbox.addEventListener('change', (event) => { highlighter.setOption('showCustomSelectionHandlesForTextSelection', event.currentTarget.checked); });
|
|
276
|
+
const selectionHandlesOnTouchCheckbox = document.getElementById('hh-selection-handles-touch');
|
|
277
|
+
selectionHandlesOnTouchCheckbox.addEventListener('change', (event) => { highlighter.setOption('showCustomSelectionHandlesOnTouch', event.currentTarget.checked); });
|
|
266
278
|
|
|
267
279
|
const container = document.querySelector(highlighter.getOptions().containerSelector);
|
|
268
280
|
const snippetDiv = document.getElementById('snippet');
|
package/highlight-helper.js
CHANGED
|
@@ -70,6 +70,9 @@ function Highlighter(options = hhDefaultOptions) {
|
|
|
70
70
|
width: 0px;
|
|
71
71
|
visibility: hidden;
|
|
72
72
|
}
|
|
73
|
+
[data-hh-pointer-down="true"] .hh-selection-handle {
|
|
74
|
+
visibility: hidden !important;
|
|
75
|
+
}
|
|
73
76
|
.hh-selection-handle-content {
|
|
74
77
|
position: absolute;
|
|
75
78
|
height: 100%;
|
|
@@ -642,13 +645,13 @@ function Highlighter(options = hhDefaultOptions) {
|
|
|
642
645
|
this.annotatableContainer.addEventListener('pointerdown', (event) => respondToPointerDown(event), { signal: controller.signal });
|
|
643
646
|
const respondToPointerDown = (event) => {
|
|
644
647
|
const isSecondaryClick = (event.button !== 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey);
|
|
648
|
+
if (!isSecondaryClick) this.annotatableContainer.dataset.hhPointerDown = 'true';
|
|
645
649
|
pointerType = event.pointerType;
|
|
646
650
|
|
|
647
651
|
// Pointer down on a selection handle
|
|
648
652
|
if (event.target?.closest('.hh-selection-handle')) {
|
|
649
653
|
if (!isSecondaryClick) {
|
|
650
654
|
activeSelectionHandle = event.target.parentElement.closest('.hh-selection-handle');
|
|
651
|
-
this.annotatableContainer.dataset.hhDragging = 'true';
|
|
652
655
|
const selectionHandleClientRect = activeSelectionHandle.getBoundingClientRect();
|
|
653
656
|
const lineHeight = selectionHandleClientRect.bottom - selectionHandleClientRect.top;
|
|
654
657
|
activeSelectionHandle.dataset.dragYOffset = Math.max(0, event.clientY - selectionHandleClientRect.bottom + (lineHeight / 6));
|
|
@@ -748,10 +751,10 @@ function Highlighter(options = hhDefaultOptions) {
|
|
|
748
751
|
}
|
|
749
752
|
tapResult = null;
|
|
750
753
|
longPressTimeoutId = clearTimeout(longPressTimeoutId);
|
|
754
|
+
this.annotatableContainer.dataset.hhPointerDown = 'false';
|
|
751
755
|
if (activeSelectionHandle) {
|
|
752
756
|
activeSelectionHandle = null;
|
|
753
757
|
updateSelectionUi('bounds');
|
|
754
|
-
this.annotatableContainer.dataset.hhDragging = 'false';
|
|
755
758
|
this.annotatableContainer.removeEventListener('pointermove', respondToSelectionHandleDrag);
|
|
756
759
|
}
|
|
757
760
|
}
|
|
@@ -898,7 +901,7 @@ function Highlighter(options = hhDefaultOptions) {
|
|
|
898
901
|
const highlightInfo = highlightsById[activeHighlightId] ?? null;
|
|
899
902
|
const color = highlightInfo?.color ?? null;
|
|
900
903
|
const style = highlightInfo?.style ?? null;
|
|
901
|
-
const colorString = options.colors[color] ?? 'AccentColor';
|
|
904
|
+
const colorString = options.colors[color] ?? (CSS.supports('color', 'AccentColor') ? 'AccentColor' : 'dodgerblue');
|
|
902
905
|
|
|
903
906
|
// Draw SVG selection rects (SVG drawing mode only)
|
|
904
907
|
svgActiveOverlay.innerHTML = '';
|
|
@@ -953,7 +956,7 @@ function Highlighter(options = hhDefaultOptions) {
|
|
|
953
956
|
|
|
954
957
|
} else if (changeType === 'bounds') {
|
|
955
958
|
// Update selection handle location and visibility
|
|
956
|
-
if (selection.type === 'Range'
|
|
959
|
+
if (selection.type === 'Range') {
|
|
957
960
|
const selectionRangeRects = selectionRange.getClientRects();
|
|
958
961
|
const startRect = selectionRangeRects[0];
|
|
959
962
|
const endRect = selectionRangeRects[selectionRangeRects.length-1];
|
|
@@ -961,8 +964,14 @@ function Highlighter(options = hhDefaultOptions) {
|
|
|
961
964
|
const startNodeIsRtl = window.getComputedStyle(selectionRange.startContainer.parentElement).direction === 'rtl';
|
|
962
965
|
const endNodeIsRtl = window.getComputedStyle(selectionRange.endContainer.parentElement).direction === 'rtl';
|
|
963
966
|
|
|
967
|
+
if (
|
|
968
|
+
(options.showCustomSelectionHandlesOnTouch || pointerType === 'mouse')
|
|
969
|
+
&& ((options.showCustomSelectionHandlesForActiveHighlights && activeHighlightId)
|
|
970
|
+
|| (options.showCustomSelectionHandlesForTextSelection && !activeHighlightId))
|
|
971
|
+
) {
|
|
972
|
+
setCustomSelectionHandleVisibility(true);
|
|
973
|
+
}
|
|
964
974
|
for (const selectionHandle of selectionHandles) {
|
|
965
|
-
selectionHandle.style.visibility = 'visible';
|
|
966
975
|
let side;
|
|
967
976
|
if (selectionHandle.dataset.position === 'start') {
|
|
968
977
|
side = startNodeIsRtl ? 'right' : 'left';
|
|
@@ -981,12 +990,17 @@ function Highlighter(options = hhDefaultOptions) {
|
|
|
981
990
|
}
|
|
982
991
|
}
|
|
983
992
|
} else {
|
|
984
|
-
|
|
985
|
-
selectionHandles[1].style.visibility = 'hidden';
|
|
993
|
+
setCustomSelectionHandleVisibility(false);
|
|
986
994
|
}
|
|
987
995
|
}
|
|
988
996
|
}
|
|
989
997
|
|
|
998
|
+
const setCustomSelectionHandleVisibility = (visible = selectionHandles[0].style.visibility === 'hidden') => {
|
|
999
|
+
for (const selectionHandle of selectionHandles) {
|
|
1000
|
+
selectionHandle.style.visibility = visible ? 'visible' : 'hidden';
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
990
1004
|
// Update the selection or highlight range to stay within the annotatable container
|
|
991
1005
|
const snapRangeToBoundaries = (range, anchorNode = null) => {
|
|
992
1006
|
let startNode = range.startContainer;
|
|
@@ -1308,8 +1322,8 @@ function Highlighter(options = hhDefaultOptions) {
|
|
|
1308
1322
|
mergedRect.width = rect.width;
|
|
1309
1323
|
}
|
|
1310
1324
|
// Process then remove rects that apply to the current line
|
|
1311
|
-
const minLeft = Math.min(mergedRect.x, rect.x);
|
|
1312
|
-
const maxRight = Math.max(mergedRect.right, rect.right);
|
|
1325
|
+
const minLeft = Math.max(paragraphRect.left, Math.min(mergedRect.x, rect.x));
|
|
1326
|
+
const maxRight = Math.min(paragraphRect.right, Math.max(mergedRect.right, rect.right));
|
|
1313
1327
|
mergedRect.width = maxRight - minLeft;
|
|
1314
1328
|
mergedRect.x = minLeft;
|
|
1315
1329
|
unmergedRects.splice(r, 1); r--;
|
|
@@ -1450,6 +1464,9 @@ let hhDefaultOptions = {
|
|
|
1450
1464
|
defaultStyle: 'fill',
|
|
1451
1465
|
defaultWrapper: 'none',
|
|
1452
1466
|
highlightIdFunction: hhGetNewHighlightId,
|
|
1467
|
+
showCustomSelectionHandlesForActiveHighlights: true,
|
|
1468
|
+
showCustomSelectionHandlesForTextSelection: false,
|
|
1469
|
+
showCustomSelectionHandlesOnTouch: false,
|
|
1453
1470
|
}
|
|
1454
1471
|
|
|
1455
1472
|
console.info('Highlighter loaded');
|
package/package.json
CHANGED