@salesforcedevs/docs-components 1.17.6-hover-edit → 1.17.10-hover-edit
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/package.json
CHANGED
|
@@ -7,20 +7,19 @@
|
|
|
7
7
|
min-width: 320px;
|
|
8
8
|
max-width: 480px;
|
|
9
9
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
10
|
-
position: relative
|
|
10
|
+
position: fixed; /* Changed from relative to fixed for better positioning */
|
|
11
11
|
overflow: hidden;
|
|
12
12
|
opacity: 1;
|
|
13
13
|
visibility: visible;
|
|
14
14
|
transition: opacity 0.1s ease, visibility 0.1s ease;
|
|
15
|
+
z-index: 9999; /* Ensure it's above other content */
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
.text-selection-search-popover.hidden {
|
|
18
19
|
opacity: 0;
|
|
19
20
|
visibility: hidden;
|
|
20
21
|
pointer-events: none;
|
|
21
|
-
|
|
22
|
-
top: -9999px;
|
|
23
|
-
left: -9999px;
|
|
22
|
+
/* Remove the absolute positioning that was causing issues */
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
/* Header Styles */
|
|
@@ -19,26 +19,128 @@ export default class TextSelectionSearch extends LightningElement {
|
|
|
19
19
|
private selectionStart: number = 0;
|
|
20
20
|
private selectionEnd: number = 0;
|
|
21
21
|
private initialPopoverStyle: string = ""; // Store initial position
|
|
22
|
+
private mutationObserver: MutationObserver | null = null;
|
|
22
23
|
|
|
23
24
|
connectedCallback() {
|
|
25
|
+
console.log('TextSelectionSearch: Component connected');
|
|
26
|
+
console.log('TextSelectionSearch: Document ready state:', document.readyState);
|
|
27
|
+
console.log('TextSelectionSearch: Current page URL:', window.location.href);
|
|
24
28
|
this.setupTextSelectionListener();
|
|
29
|
+
this.setupContentObserver();
|
|
30
|
+
|
|
31
|
+
// Additional initialization for spec-based references
|
|
32
|
+
if (this.isSpecBasedReferencePage()) {
|
|
33
|
+
console.log('TextSelectionSearch: Detected spec-based reference page, setting up additional listeners');
|
|
34
|
+
this.setupSpecBasedReferenceHandling();
|
|
35
|
+
}
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
disconnectedCallback() {
|
|
39
|
+
console.log('TextSelectionSearch: Component disconnected');
|
|
28
40
|
this.removeTextSelectionListener();
|
|
41
|
+
this.removeContentObserver();
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
// Setup text selection listener
|
|
32
45
|
setupTextSelectionListener() {
|
|
33
46
|
console.log('TextSelectionSearch: Setting up text selection listeners');
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
try {
|
|
48
|
+
// Use capture phase to ensure we get the events
|
|
49
|
+
document.addEventListener("mouseup", (event) => this.handleTextSelection(event), true);
|
|
50
|
+
document.addEventListener("keyup", (event) => this.handleTextSelection(event), true);
|
|
51
|
+
console.log('TextSelectionSearch: Event listeners attached successfully');
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error('TextSelectionSearch: Error setting up event listeners:', error);
|
|
54
|
+
}
|
|
36
55
|
}
|
|
37
56
|
|
|
38
57
|
removeTextSelectionListener() {
|
|
39
58
|
console.log('TextSelectionSearch: Removing text selection listeners');
|
|
40
|
-
|
|
41
|
-
|
|
59
|
+
try {
|
|
60
|
+
document.removeEventListener("mouseup", (event) => this.handleTextSelection(event), true);
|
|
61
|
+
document.removeEventListener("keyup", (event) => this.handleTextSelection(event), true);
|
|
62
|
+
console.log('TextSelectionSearch: Event listeners removed successfully');
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error('TextSelectionSearch: Error removing event listeners:', error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Setup observer to detect when content is dynamically loaded
|
|
69
|
+
setupContentObserver() {
|
|
70
|
+
console.log('TextSelectionSearch: Setting up content observer');
|
|
71
|
+
try {
|
|
72
|
+
this.mutationObserver = new MutationObserver((mutations) => {
|
|
73
|
+
let shouldReinitialize = false;
|
|
74
|
+
|
|
75
|
+
for (const mutation of mutations) {
|
|
76
|
+
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
|
|
77
|
+
// Check if any added nodes contain text content
|
|
78
|
+
for (const node of Array.from(mutation.addedNodes)) {
|
|
79
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
80
|
+
const element = node as Element;
|
|
81
|
+
|
|
82
|
+
// Check for spec-based reference content (.api-documentation)
|
|
83
|
+
if (element.classList && element.classList.contains('api-documentation')) {
|
|
84
|
+
console.log('TextSelectionSearch: Detected .api-documentation container');
|
|
85
|
+
shouldReinitialize = true;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Check for doc-amf-topic component
|
|
90
|
+
if (element.tagName && element.tagName.toLowerCase() === 'doc-amf-topic') {
|
|
91
|
+
console.log('TextSelectionSearch: Detected doc-amf-topic component');
|
|
92
|
+
shouldReinitialize = true;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Check for shadow DOM content in spec-based references
|
|
97
|
+
if (this.isSpecBasedReferencePage() && element.shadowRoot) {
|
|
98
|
+
console.log('TextSelectionSearch: Detected shadow DOM content');
|
|
99
|
+
shouldReinitialize = true;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Check for common content containers
|
|
104
|
+
if (element.querySelector && (
|
|
105
|
+
element.querySelector('p, h1, h2, h3, h4, h5, h6, li, td, th, div') ||
|
|
106
|
+
element.matches('p, h1, h2, h3, h4, h5, h6, li, td, th, div')
|
|
107
|
+
)) {
|
|
108
|
+
shouldReinitialize = true;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (shouldReinitialize) {
|
|
117
|
+
console.log('TextSelectionSearch: Content detected, reinitializing listeners');
|
|
118
|
+
// Small delay to ensure content is fully rendered
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
this.setupTextSelectionListener();
|
|
121
|
+
}, 200); // Increased delay for spec-based references
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Observe the entire document for content changes
|
|
126
|
+
this.mutationObserver.observe(document.body, {
|
|
127
|
+
childList: true,
|
|
128
|
+
subtree: true
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
console.log('TextSelectionSearch: Content observer set up successfully');
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error('TextSelectionSearch: Error setting up content observer:', error);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
removeContentObserver() {
|
|
138
|
+
console.log('TextSelectionSearch: Removing content observer');
|
|
139
|
+
if (this.mutationObserver) {
|
|
140
|
+
this.mutationObserver.disconnect();
|
|
141
|
+
this.mutationObserver = null;
|
|
142
|
+
console.log('TextSelectionSearch: Content observer removed successfully');
|
|
143
|
+
}
|
|
42
144
|
}
|
|
43
145
|
|
|
44
146
|
// Handle text selection
|
|
@@ -50,6 +152,8 @@ export default class TextSelectionSearch extends LightningElement {
|
|
|
50
152
|
}
|
|
51
153
|
|
|
52
154
|
console.log('TextSelectionSearch: Text selection event triggered');
|
|
155
|
+
console.log('TextSelectionSearch: Event type:', event?.type);
|
|
156
|
+
console.log('TextSelectionSearch: Event target:', event?.target);
|
|
53
157
|
|
|
54
158
|
// Check if the event target is inside our popover
|
|
55
159
|
if (event && event.target) {
|
|
@@ -62,6 +166,9 @@ export default class TextSelectionSearch extends LightningElement {
|
|
|
62
166
|
}
|
|
63
167
|
|
|
64
168
|
const selection = window.getSelection();
|
|
169
|
+
console.log('TextSelectionSearch: Selection object:', selection);
|
|
170
|
+
console.log('TextSelectionSearch: Selection string:', selection?.toString());
|
|
171
|
+
console.log('TextSelectionSearch: Selection range count:', selection?.rangeCount);
|
|
65
172
|
|
|
66
173
|
if (!selection || selection.toString().trim() === "") {
|
|
67
174
|
// Only hide popover if it's currently visible and we're not clicking inside it
|
|
@@ -77,6 +184,31 @@ export default class TextSelectionSearch extends LightningElement {
|
|
|
77
184
|
this.selectedText = selection.toString().trim();
|
|
78
185
|
console.log('TextSelectionSearch: Selected text:', this.selectedText);
|
|
79
186
|
|
|
187
|
+
// For spec-based references, check if selection is within the API documentation container
|
|
188
|
+
if (this.isSpecBasedReferencePage()) {
|
|
189
|
+
const apiDocContainer = document.querySelector('.api-documentation');
|
|
190
|
+
if (apiDocContainer) {
|
|
191
|
+
const range = selection.getRangeAt(0);
|
|
192
|
+
const rect = range.getBoundingClientRect();
|
|
193
|
+
const containerRect = apiDocContainer.getBoundingClientRect();
|
|
194
|
+
|
|
195
|
+
// Check if the selection is within the API documentation container
|
|
196
|
+
const isWithinContainer = (
|
|
197
|
+
rect.top >= containerRect.top &&
|
|
198
|
+
rect.bottom <= containerRect.bottom &&
|
|
199
|
+
rect.left >= containerRect.left &&
|
|
200
|
+
rect.right <= containerRect.right
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
console.log('TextSelectionSearch: Selection within API container:', isWithinContainer);
|
|
204
|
+
|
|
205
|
+
if (!isWithinContainer) {
|
|
206
|
+
console.log('TextSelectionSearch: Selection outside API container, ignoring');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
80
212
|
if (this.selectedText.length > 0) {
|
|
81
213
|
this.showPopover();
|
|
82
214
|
}
|
|
@@ -94,16 +226,79 @@ export default class TextSelectionSearch extends LightningElement {
|
|
|
94
226
|
const range = selection.getRangeAt(0);
|
|
95
227
|
const rect = range.getBoundingClientRect();
|
|
96
228
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
229
|
+
console.log('TextSelectionSearch: Selection rect:', rect);
|
|
230
|
+
console.log('TextSelectionSearch: Window dimensions:', window.innerWidth, window.innerHeight);
|
|
231
|
+
console.log('TextSelectionSearch: Scroll position:', window.scrollX, window.scrollY);
|
|
232
|
+
console.log('TextSelectionSearch: Document height:', document.documentElement.scrollHeight);
|
|
233
|
+
|
|
234
|
+
// Check if we're on a spec-based reference page
|
|
235
|
+
const isSpecBased = this.isSpecBasedReferencePage();
|
|
236
|
+
console.log('TextSelectionSearch: Is spec-based reference:', isSpecBased);
|
|
101
237
|
|
|
102
|
-
|
|
238
|
+
// Calculate popover position with better positioning logic
|
|
239
|
+
let popoverTop: number;
|
|
240
|
+
let popoverLeft: number;
|
|
241
|
+
|
|
242
|
+
if (isSpecBased) {
|
|
243
|
+
// For spec-based references, we need to account for the dynamic content structure
|
|
244
|
+
// The content might be inside shadow DOM or have different positioning
|
|
245
|
+
const apiDocContainer = document.querySelector('.api-documentation');
|
|
246
|
+
if (apiDocContainer) {
|
|
247
|
+
const containerRect = apiDocContainer.getBoundingClientRect();
|
|
248
|
+
console.log('TextSelectionSearch: API documentation container rect:', containerRect);
|
|
249
|
+
|
|
250
|
+
// Position the popover relative to the selection within the container
|
|
251
|
+
popoverLeft = Math.max(10, Math.min(window.innerWidth - 360, rect.left + (rect.width / 2) - 180));
|
|
252
|
+
|
|
253
|
+
if (this.popoverPosition === "top") {
|
|
254
|
+
// Position above the selection, but ensure it's within the container bounds
|
|
255
|
+
popoverTop = Math.max(10, rect.top - 200);
|
|
256
|
+
// If it would go above the container, position it below instead
|
|
257
|
+
if (popoverTop < containerRect.top + 10) {
|
|
258
|
+
popoverTop = Math.min(window.innerHeight - 250, rect.bottom + 20);
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
// Position below the selection
|
|
262
|
+
popoverTop = Math.min(window.innerHeight - 250, rect.bottom + 20);
|
|
263
|
+
// If it would go below the container, position it above instead
|
|
264
|
+
if (popoverTop > containerRect.bottom - 250) {
|
|
265
|
+
popoverTop = Math.max(10, rect.top - 200);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
// Fallback to standard positioning if container not found
|
|
270
|
+
popoverLeft = Math.max(10, Math.min(window.innerWidth - 360, rect.left + (rect.width / 2) - 180));
|
|
271
|
+
if (this.popoverPosition === "top") {
|
|
272
|
+
popoverTop = Math.max(10, rect.top - 200);
|
|
273
|
+
} else {
|
|
274
|
+
popoverTop = Math.min(window.innerHeight - 250, rect.bottom + 20);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
// Standard positioning for markdown-based references
|
|
279
|
+
popoverLeft = Math.max(10, Math.min(window.innerWidth - 360, rect.left + (rect.width / 2) - 180));
|
|
280
|
+
|
|
281
|
+
if (this.popoverPosition === "top") {
|
|
282
|
+
// Position above the selection
|
|
283
|
+
popoverTop = Math.max(10, rect.top - 200); // 200px above selection
|
|
284
|
+
} else {
|
|
285
|
+
// Position below the selection
|
|
286
|
+
popoverTop = Math.min(window.innerHeight - 250, rect.bottom + 20);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Ensure the popover doesn't go off-screen
|
|
291
|
+
if (popoverTop < 10) {
|
|
292
|
+
popoverTop = 10;
|
|
293
|
+
}
|
|
294
|
+
if (popoverTop > window.innerHeight - 250) {
|
|
295
|
+
popoverTop = window.innerHeight - 250;
|
|
296
|
+
}
|
|
103
297
|
|
|
104
298
|
this.popoverStyle = `position: fixed; top: ${popoverTop}px; left: ${popoverLeft}px; z-index: 9999; width: 350px;`;
|
|
105
299
|
this.initialPopoverStyle = this.popoverStyle; // Store the initial position
|
|
106
300
|
console.log('TextSelectionSearch: Popover style:', this.popoverStyle);
|
|
301
|
+
console.log('TextSelectionSearch: Calculated position - top:', popoverTop, 'left:', popoverLeft);
|
|
107
302
|
|
|
108
303
|
this.isVisible = true;
|
|
109
304
|
this.isHidden = false;
|
|
@@ -239,19 +434,63 @@ export default class TextSelectionSearch extends LightningElement {
|
|
|
239
434
|
return this.isLoading || !this.searchQuery.trim();
|
|
240
435
|
}
|
|
241
436
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
437
|
+
// Find text content within shadow DOM elements
|
|
438
|
+
findTextInShadowDOM(element: Element): boolean {
|
|
439
|
+
// Check if element has shadow root
|
|
440
|
+
if (element.shadowRoot) {
|
|
441
|
+
const shadowContent = element.shadowRoot.querySelector('p, h1, h2, h3, h4, h5, h6, li, td, th, div, span');
|
|
442
|
+
if (shadowContent) {
|
|
443
|
+
console.log('TextSelectionSearch: Found content in shadow DOM');
|
|
444
|
+
return true;
|
|
248
445
|
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Recursively check child elements
|
|
449
|
+
for (const child of Array.from(element.children)) {
|
|
450
|
+
if (this.findTextInShadowDOM(child)) {
|
|
451
|
+
return true;
|
|
254
452
|
}
|
|
255
453
|
}
|
|
454
|
+
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Check if current page is a spec-based reference
|
|
459
|
+
isSpecBasedReferencePage(): boolean {
|
|
460
|
+
const url = window.location.href;
|
|
461
|
+
const hasMetaParam = url.includes('?meta=');
|
|
462
|
+
const isReferencePage = url.includes('/references/');
|
|
463
|
+
console.log('TextSelectionSearch: URL analysis - hasMetaParam:', hasMetaParam, 'isReferencePage:', isReferencePage);
|
|
464
|
+
return hasMetaParam && isReferencePage;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Additional setup for spec-based references
|
|
468
|
+
setupSpecBasedReferenceHandling() {
|
|
469
|
+
// Wait for the page to be fully loaded
|
|
470
|
+
if (document.readyState === 'loading') {
|
|
471
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
472
|
+
this.initializeForSpecBasedReference();
|
|
473
|
+
});
|
|
474
|
+
} else {
|
|
475
|
+
this.initializeForSpecBasedReference();
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
initializeForSpecBasedReference() {
|
|
480
|
+
console.log('TextSelectionSearch: Initializing for spec-based reference');
|
|
481
|
+
|
|
482
|
+
// Wait for the .api-documentation container to appear
|
|
483
|
+
const checkForApiDocumentation = () => {
|
|
484
|
+
const apiDocContainer = document.querySelector('.api-documentation');
|
|
485
|
+
if (apiDocContainer) {
|
|
486
|
+
console.log('TextSelectionSearch: Found .api-documentation container, setting up listeners');
|
|
487
|
+
this.setupTextSelectionListener();
|
|
488
|
+
} else {
|
|
489
|
+
console.log('TextSelectionSearch: .api-documentation container not found yet, retrying...');
|
|
490
|
+
setTimeout(checkForApiDocumentation, 500);
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
checkForApiDocumentation();
|
|
256
495
|
}
|
|
257
496
|
}
|