@trustquery/browser 0.2.5 → 0.2.8
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/trustquery.js +187 -5
- package/dist/trustquery.js.map +1 -1
- package/package.json +1 -1
- package/src/InteractionHandler.js +75 -4
- package/src/TrustQuery.js +112 -1
package/dist/trustquery.js
CHANGED
|
@@ -1506,15 +1506,84 @@ class InteractionHandler {
|
|
|
1506
1506
|
const behavior = matchEl.getAttribute('data-behavior');
|
|
1507
1507
|
const matchData = this.getMatchData(matchEl);
|
|
1508
1508
|
|
|
1509
|
-
console.log('[InteractionHandler]
|
|
1509
|
+
console.log('[InteractionHandler] ===== CLICK EVENT START =====');
|
|
1510
|
+
console.log('[InteractionHandler] Click details:', {
|
|
1511
|
+
behavior: behavior,
|
|
1512
|
+
matchText: matchData.text,
|
|
1513
|
+
eventType: e.type,
|
|
1514
|
+
target: e.target.tagName,
|
|
1515
|
+
currentTarget: e.currentTarget.tagName,
|
|
1516
|
+
button: e.button,
|
|
1517
|
+
buttons: e.buttons,
|
|
1518
|
+
clientX: e.clientX,
|
|
1519
|
+
clientY: e.clientY,
|
|
1520
|
+
offsetX: e.offsetX,
|
|
1521
|
+
offsetY: e.offsetY
|
|
1522
|
+
});
|
|
1523
|
+
console.log('[InteractionHandler] Match element:', {
|
|
1524
|
+
textContent: matchEl.textContent,
|
|
1525
|
+
offsetWidth: matchEl.offsetWidth,
|
|
1526
|
+
offsetHeight: matchEl.offsetHeight,
|
|
1527
|
+
attributes: {
|
|
1528
|
+
'data-line': matchEl.getAttribute('data-line'),
|
|
1529
|
+
'data-col': matchEl.getAttribute('data-col'),
|
|
1530
|
+
'data-behavior': behavior
|
|
1531
|
+
}
|
|
1532
|
+
});
|
|
1533
|
+
console.log('[InteractionHandler] Active element before click:', document.activeElement.tagName, document.activeElement.id || '(no id)');
|
|
1510
1534
|
|
|
1511
|
-
//
|
|
1512
|
-
|
|
1513
|
-
|
|
1535
|
+
// For non-interactive elements (bubbles), manually pass click to textarea
|
|
1536
|
+
if (behavior !== 'dropdown' && behavior !== 'action') {
|
|
1537
|
+
console.log('[InteractionHandler] Non-interactive match - manually focusing textarea');
|
|
1514
1538
|
e.preventDefault();
|
|
1515
1539
|
e.stopPropagation();
|
|
1540
|
+
|
|
1541
|
+
// Focus textarea and position cursor at click location
|
|
1542
|
+
if (this.options.textarea) {
|
|
1543
|
+
this.options.textarea.focus();
|
|
1544
|
+
console.log('[InteractionHandler] Textarea focused. Active element now:', document.activeElement.tagName, document.activeElement.id || '(no id)');
|
|
1545
|
+
|
|
1546
|
+
// Get the character offset by finding the match position
|
|
1547
|
+
const line = parseInt(matchEl.getAttribute('data-line'));
|
|
1548
|
+
const col = parseInt(matchEl.getAttribute('data-col'));
|
|
1549
|
+
|
|
1550
|
+
// Calculate absolute position in textarea
|
|
1551
|
+
const lines = this.options.textarea.value.split('\n');
|
|
1552
|
+
let offset = 0;
|
|
1553
|
+
for (let i = 0; i < line; i++) {
|
|
1554
|
+
offset += lines[i].length + 1; // +1 for newline
|
|
1555
|
+
}
|
|
1556
|
+
const clickOffsetInMatch = (e.offsetX / matchEl.offsetWidth * matchEl.textContent.length);
|
|
1557
|
+
offset += col + clickOffsetInMatch;
|
|
1558
|
+
|
|
1559
|
+
console.log('[InteractionHandler] Cursor positioning:', {
|
|
1560
|
+
line: line,
|
|
1561
|
+
col: col,
|
|
1562
|
+
clickOffsetInMatch: clickOffsetInMatch,
|
|
1563
|
+
finalOffset: offset,
|
|
1564
|
+
textareaValue: this.options.textarea.value,
|
|
1565
|
+
textareaValueLength: this.options.textarea.value.length
|
|
1566
|
+
});
|
|
1567
|
+
|
|
1568
|
+
// Set cursor position
|
|
1569
|
+
this.options.textarea.setSelectionRange(offset, offset);
|
|
1570
|
+
|
|
1571
|
+
console.log('[InteractionHandler] Selection set:', {
|
|
1572
|
+
selectionStart: this.options.textarea.selectionStart,
|
|
1573
|
+
selectionEnd: this.options.textarea.selectionEnd,
|
|
1574
|
+
selectedText: this.options.textarea.value.substring(this.options.textarea.selectionStart, this.options.textarea.selectionEnd)
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
console.log('[InteractionHandler] ===== CLICK EVENT END (non-interactive) =====');
|
|
1579
|
+
return; // Don't process further for bubbles
|
|
1516
1580
|
}
|
|
1517
1581
|
|
|
1582
|
+
console.log('[InteractionHandler] Interactive match - handling dropdown/action');
|
|
1583
|
+
// Prevent default for interactive elements (dropdown/action)
|
|
1584
|
+
e.preventDefault();
|
|
1585
|
+
e.stopPropagation();
|
|
1586
|
+
|
|
1518
1587
|
// Handle different behaviors
|
|
1519
1588
|
if (behavior === 'dropdown') {
|
|
1520
1589
|
// Toggle dropdown - close if already open for this match, otherwise show
|
|
@@ -1534,6 +1603,8 @@ class InteractionHandler {
|
|
|
1534
1603
|
if (this.options.onWordClick && !(behavior === 'dropdown' && this.dropdownManager.activeDropdownMatch === matchEl)) {
|
|
1535
1604
|
this.options.onWordClick(matchData);
|
|
1536
1605
|
}
|
|
1606
|
+
|
|
1607
|
+
console.log('[InteractionHandler] ===== CLICK EVENT END (interactive) =====');
|
|
1537
1608
|
}
|
|
1538
1609
|
|
|
1539
1610
|
/**
|
|
@@ -2949,12 +3020,121 @@ class TrustQuery {
|
|
|
2949
3020
|
this.overlay.scrollLeft = this.textarea.scrollLeft;
|
|
2950
3021
|
});
|
|
2951
3022
|
|
|
3023
|
+
// Keyboard event logging for debugging selection issues
|
|
3024
|
+
this.textarea.addEventListener('keydown', (e) => {
|
|
3025
|
+
const isCmdOrCtrl = e.metaKey || e.ctrlKey;
|
|
3026
|
+
const isSelectAll = (e.metaKey || e.ctrlKey) && e.key === 'a';
|
|
3027
|
+
|
|
3028
|
+
if (isCmdOrCtrl || isSelectAll) {
|
|
3029
|
+
console.log('[TrustQuery] ===== KEYBOARD EVENT =====');
|
|
3030
|
+
console.log('[TrustQuery] Key pressed:', {
|
|
3031
|
+
key: e.key,
|
|
3032
|
+
code: e.code,
|
|
3033
|
+
metaKey: e.metaKey,
|
|
3034
|
+
ctrlKey: e.ctrlKey,
|
|
3035
|
+
shiftKey: e.shiftKey,
|
|
3036
|
+
altKey: e.altKey,
|
|
3037
|
+
isSelectAll: isSelectAll
|
|
3038
|
+
});
|
|
3039
|
+
console.log('[TrustQuery] Active element:', document.activeElement.tagName, document.activeElement.id || '(no id)');
|
|
3040
|
+
console.log('[TrustQuery] Textarea state BEFORE:', {
|
|
3041
|
+
value: this.textarea.value,
|
|
3042
|
+
valueLength: this.textarea.value.length,
|
|
3043
|
+
selectionStart: this.textarea.selectionStart,
|
|
3044
|
+
selectionEnd: this.textarea.selectionEnd,
|
|
3045
|
+
selectedText: this.textarea.value.substring(this.textarea.selectionStart, this.textarea.selectionEnd)
|
|
3046
|
+
});
|
|
3047
|
+
|
|
3048
|
+
if (isSelectAll) {
|
|
3049
|
+
// Log state after select all (use setTimeout to let browser process the event)
|
|
3050
|
+
setTimeout(() => {
|
|
3051
|
+
console.log('[TrustQuery] Textarea state AFTER CMD+A:', {
|
|
3052
|
+
selectionStart: this.textarea.selectionStart,
|
|
3053
|
+
selectionEnd: this.textarea.selectionEnd,
|
|
3054
|
+
selectedText: this.textarea.value.substring(this.textarea.selectionStart, this.textarea.selectionEnd),
|
|
3055
|
+
selectedLength: this.textarea.selectionEnd - this.textarea.selectionStart
|
|
3056
|
+
});
|
|
3057
|
+
console.log('[TrustQuery] ===== KEYBOARD EVENT END =====');
|
|
3058
|
+
}, 0);
|
|
3059
|
+
} else {
|
|
3060
|
+
console.log('[TrustQuery] ===== KEYBOARD EVENT END =====');
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
});
|
|
3064
|
+
|
|
3065
|
+
// Selection change event
|
|
3066
|
+
this.textarea.addEventListener('select', (e) => {
|
|
3067
|
+
console.log('[TrustQuery] ===== SELECTION CHANGE EVENT =====');
|
|
3068
|
+
console.log('[TrustQuery] Selection:', {
|
|
3069
|
+
selectionStart: this.textarea.selectionStart,
|
|
3070
|
+
selectionEnd: this.textarea.selectionEnd,
|
|
3071
|
+
selectedText: this.textarea.value.substring(this.textarea.selectionStart, this.textarea.selectionEnd),
|
|
3072
|
+
selectedLength: this.textarea.selectionEnd - this.textarea.selectionStart
|
|
3073
|
+
});
|
|
3074
|
+
});
|
|
3075
|
+
|
|
3076
|
+
// Context menu event - prevent keyboard-triggered context menu
|
|
3077
|
+
this.textarea.addEventListener('contextmenu', (e) => {
|
|
3078
|
+
console.log('[TrustQuery] ===== CONTEXTMENU EVENT =====');
|
|
3079
|
+
console.log('[TrustQuery] Context menu triggered:', {
|
|
3080
|
+
type: e.type,
|
|
3081
|
+
isTrusted: e.isTrusted,
|
|
3082
|
+
button: e.button,
|
|
3083
|
+
buttons: e.buttons,
|
|
3084
|
+
clientX: e.clientX,
|
|
3085
|
+
clientY: e.clientY,
|
|
3086
|
+
ctrlKey: e.ctrlKey,
|
|
3087
|
+
metaKey: e.metaKey,
|
|
3088
|
+
target: e.target.tagName
|
|
3089
|
+
});
|
|
3090
|
+
|
|
3091
|
+
// Prevent context menu if triggered by keyboard (button === -1)
|
|
3092
|
+
// This prevents the macOS context menu from opening after CMD+A
|
|
3093
|
+
if (e.button === -1 && e.buttons === 0) {
|
|
3094
|
+
console.log('[TrustQuery] Preventing keyboard-triggered context menu');
|
|
3095
|
+
e.preventDefault();
|
|
3096
|
+
e.stopPropagation();
|
|
3097
|
+
return;
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
console.log('[TrustQuery] Allowing mouse-triggered context menu');
|
|
3101
|
+
});
|
|
3102
|
+
|
|
3103
|
+
// Also prevent context menu on overlay (it interferes with text selection)
|
|
3104
|
+
this.overlay.addEventListener('contextmenu', (e) => {
|
|
3105
|
+
console.log('[TrustQuery] ===== CONTEXTMENU EVENT ON OVERLAY =====');
|
|
3106
|
+
console.log('[TrustQuery] Context menu on overlay - preventing');
|
|
3107
|
+
|
|
3108
|
+
// Always prevent context menu on overlay
|
|
3109
|
+
// The overlay should be transparent to user interactions
|
|
3110
|
+
e.preventDefault();
|
|
3111
|
+
e.stopPropagation();
|
|
3112
|
+
});
|
|
3113
|
+
|
|
2952
3114
|
// Focus/blur events - add/remove focus class
|
|
2953
|
-
this.textarea.addEventListener('focus', () => {
|
|
3115
|
+
this.textarea.addEventListener('focus', (e) => {
|
|
3116
|
+
console.log('[TrustQuery] ===== FOCUS EVENT =====');
|
|
3117
|
+
console.log('[TrustQuery] Textarea focused. Active element:', document.activeElement.tagName, document.activeElement.id || '(no id)');
|
|
3118
|
+
console.log('[TrustQuery] Current selection:', {
|
|
3119
|
+
selectionStart: this.textarea.selectionStart,
|
|
3120
|
+
selectionEnd: this.textarea.selectionEnd
|
|
3121
|
+
});
|
|
2954
3122
|
this.wrapper.classList.add('tq-focused');
|
|
2955
3123
|
});
|
|
2956
3124
|
|
|
2957
3125
|
this.textarea.addEventListener('blur', (e) => {
|
|
3126
|
+
console.log('[TrustQuery] ===== BLUR EVENT =====');
|
|
3127
|
+
console.log('[TrustQuery] Textarea blurred. Related target:', e.relatedTarget?.tagName || '(none)');
|
|
3128
|
+
console.log('[TrustQuery] Blur event details:', {
|
|
3129
|
+
type: e.type,
|
|
3130
|
+
isTrusted: e.isTrusted,
|
|
3131
|
+
eventPhase: e.eventPhase,
|
|
3132
|
+
target: e.target.tagName,
|
|
3133
|
+
currentTarget: e.currentTarget.tagName
|
|
3134
|
+
});
|
|
3135
|
+
console.log('[TrustQuery] Stack trace at blur:');
|
|
3136
|
+
console.trace();
|
|
3137
|
+
|
|
2958
3138
|
// Close dropdown when textarea loses focus (unless interacting with dropdown)
|
|
2959
3139
|
if (this.interactionHandler) {
|
|
2960
3140
|
// Use setTimeout to let the new focus target be set and check if clicking on dropdown
|
|
@@ -2965,6 +3145,8 @@ class TrustQuery {
|
|
|
2965
3145
|
activeElement.closest('.tq-dropdown') // Check if clicking anywhere in dropdown
|
|
2966
3146
|
);
|
|
2967
3147
|
|
|
3148
|
+
console.log('[TrustQuery] After blur - active element:', activeElement?.tagName || '(none)', 'isDropdownRelated:', isDropdownRelated);
|
|
3149
|
+
|
|
2968
3150
|
// Only close if not interacting with dropdown
|
|
2969
3151
|
if (!isDropdownRelated) {
|
|
2970
3152
|
this.interactionHandler.hideDropdown();
|