@salesforcedevs/docs-components 1.17.2 → 1.17.6-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/lwc.config.json +2 -0
- package/package.json +2 -2
- package/src/modules/doc/markdownEditor/markdownEditor.css +225 -0
- package/src/modules/doc/markdownEditor/markdownEditor.html +80 -0
- package/src/modules/doc/markdownEditor/markdownEditor.ts +148 -0
- package/src/modules/doc/textSelectionSearch/README.md +185 -0
- package/src/modules/doc/textSelectionSearch/textSelectionSearch.css +286 -0
- package/src/modules/doc/textSelectionSearch/textSelectionSearch.html +90 -0
- package/src/modules/doc/textSelectionSearch/textSelectionSearch.js +236 -0
- package/src/modules/doc/textSelectionSearch/textSelectionSearch.ts +257 -0
- package/src/modules/doc/xmlContent/xmlContent.html +1 -9
- package/src/modules/doc/xmlContent/xmlContent.ts +8 -18
- package/LICENSE +0 -12
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
.text-selection-search-popover {
|
|
2
|
+
background: white;
|
|
3
|
+
border: 1px solid #e1e5e9;
|
|
4
|
+
border-radius: 8px;
|
|
5
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
|
6
|
+
padding: 0;
|
|
7
|
+
min-width: 320px;
|
|
8
|
+
max-width: 480px;
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
10
|
+
position: relative;
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
opacity: 1;
|
|
13
|
+
visibility: visible;
|
|
14
|
+
transition: opacity 0.1s ease, visibility 0.1s ease;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.text-selection-search-popover.hidden {
|
|
18
|
+
opacity: 0;
|
|
19
|
+
visibility: hidden;
|
|
20
|
+
pointer-events: none;
|
|
21
|
+
position: absolute;
|
|
22
|
+
top: -9999px;
|
|
23
|
+
left: -9999px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Header Styles */
|
|
27
|
+
.popover-header {
|
|
28
|
+
background: #f8f9fa;
|
|
29
|
+
border-bottom: 1px solid #e9ecef;
|
|
30
|
+
padding: 12px 16px;
|
|
31
|
+
margin: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.popover-title {
|
|
35
|
+
margin: 0;
|
|
36
|
+
font-size: 14px;
|
|
37
|
+
font-weight: 600;
|
|
38
|
+
color: #495057;
|
|
39
|
+
text-transform: uppercase;
|
|
40
|
+
letter-spacing: 0.5px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Content Container */
|
|
44
|
+
.text-selection-search-popover > *:not(.popover-header):not(.popover-close) {
|
|
45
|
+
padding: 16px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Section Labels */
|
|
49
|
+
.section-label {
|
|
50
|
+
display: block;
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
font-size: 12px;
|
|
53
|
+
color: #6c757d;
|
|
54
|
+
margin-bottom: 6px;
|
|
55
|
+
text-transform: uppercase;
|
|
56
|
+
letter-spacing: 0.5px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Selected Text Display */
|
|
60
|
+
.selected-text-section {
|
|
61
|
+
margin-bottom: 16px;
|
|
62
|
+
padding-bottom: 12px;
|
|
63
|
+
border-bottom: 1px solid #f1f3f4;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.selected-text-display {
|
|
67
|
+
background: #f8f9fa;
|
|
68
|
+
border: 1px solid #e9ecef;
|
|
69
|
+
border-radius: 4px;
|
|
70
|
+
padding: 8px 12px;
|
|
71
|
+
font-size: 13px;
|
|
72
|
+
line-height: 1.4;
|
|
73
|
+
color: #495057;
|
|
74
|
+
min-height: 32px;
|
|
75
|
+
max-height: 60px;
|
|
76
|
+
overflow-y: auto;
|
|
77
|
+
word-wrap: break-word;
|
|
78
|
+
font-style: italic;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Edit Form */
|
|
82
|
+
.edit-form {
|
|
83
|
+
margin-bottom: 16px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.input-group {
|
|
87
|
+
margin-bottom: 16px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.input-group:last-child {
|
|
91
|
+
margin-bottom: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.input-with-button {
|
|
95
|
+
display: flex;
|
|
96
|
+
gap: 8px;
|
|
97
|
+
align-items: flex-end;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.edit-input {
|
|
101
|
+
flex: 1;
|
|
102
|
+
padding: 12px 16px;
|
|
103
|
+
border: 2px solid #e5e7eb;
|
|
104
|
+
border-radius: 6px;
|
|
105
|
+
font-size: 14px;
|
|
106
|
+
transition: border-color 0.2s ease;
|
|
107
|
+
background: white;
|
|
108
|
+
min-height: 48px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.edit-input:focus {
|
|
112
|
+
outline: none;
|
|
113
|
+
border-color: #0070d2;
|
|
114
|
+
box-shadow: 0 0 0 3px rgba(0, 112, 210, 0.1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.edit-input::placeholder {
|
|
118
|
+
color: #9ca3af;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.edit-button {
|
|
122
|
+
padding: 8px 16px;
|
|
123
|
+
background: #0070d2;
|
|
124
|
+
color: white;
|
|
125
|
+
border: none;
|
|
126
|
+
border-radius: 4px;
|
|
127
|
+
font-weight: 500;
|
|
128
|
+
font-size: 13px;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
transition: all 0.2s ease;
|
|
131
|
+
white-space: nowrap;
|
|
132
|
+
min-height: 48px;
|
|
133
|
+
text-transform: uppercase;
|
|
134
|
+
letter-spacing: 0.5px;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.edit-button:hover:not(:disabled) {
|
|
138
|
+
background: #005fb2;
|
|
139
|
+
transform: translateY(-1px);
|
|
140
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.edit-button:active:not(:disabled) {
|
|
144
|
+
transform: translateY(0);
|
|
145
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.edit-button:disabled {
|
|
149
|
+
background: #9ca3af;
|
|
150
|
+
cursor: not-allowed;
|
|
151
|
+
transform: none;
|
|
152
|
+
box-shadow: none;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Loading State */
|
|
156
|
+
.loading-state {
|
|
157
|
+
display: flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
gap: 12px;
|
|
160
|
+
padding: 12px;
|
|
161
|
+
background: #f8f9fa;
|
|
162
|
+
border-radius: 6px;
|
|
163
|
+
margin-top: 12px;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.loading-text {
|
|
167
|
+
font-size: 13px;
|
|
168
|
+
color: #6c757d;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* Error State */
|
|
172
|
+
.error-state {
|
|
173
|
+
padding: 12px;
|
|
174
|
+
background: #fef2f2;
|
|
175
|
+
border: 1px solid #fecaca;
|
|
176
|
+
border-radius: 6px;
|
|
177
|
+
margin-top: 12px;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.error-message {
|
|
181
|
+
color: #dc2626;
|
|
182
|
+
font-size: 13px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* Success State */
|
|
186
|
+
.success-state {
|
|
187
|
+
padding: 12px;
|
|
188
|
+
background: #f0fdf4;
|
|
189
|
+
border: 1px solid #bbf7d0;
|
|
190
|
+
border-radius: 6px;
|
|
191
|
+
margin-top: 12px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.success-message {
|
|
195
|
+
color: #16a34a;
|
|
196
|
+
font-size: 13px;
|
|
197
|
+
font-weight: 500;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* Close Button */
|
|
201
|
+
.popover-close {
|
|
202
|
+
position: absolute;
|
|
203
|
+
top: 8px;
|
|
204
|
+
right: 8px;
|
|
205
|
+
z-index: 10;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.close-button {
|
|
209
|
+
background: rgba(108, 117, 125, 0.1);
|
|
210
|
+
border: none;
|
|
211
|
+
color: #6c757d;
|
|
212
|
+
width: 24px;
|
|
213
|
+
height: 24px;
|
|
214
|
+
border-radius: 4px;
|
|
215
|
+
display: flex;
|
|
216
|
+
align-items: center;
|
|
217
|
+
justify-content: center;
|
|
218
|
+
cursor: pointer;
|
|
219
|
+
font-size: 14px;
|
|
220
|
+
font-weight: bold;
|
|
221
|
+
transition: background-color 0.2s ease;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.close-button:hover {
|
|
225
|
+
background: rgba(108, 117, 125, 0.2);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Responsive Design */
|
|
229
|
+
@media (max-width: 480px) {
|
|
230
|
+
.text-selection-search-popover {
|
|
231
|
+
min-width: 280px;
|
|
232
|
+
max-width: 90vw;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.input-with-button {
|
|
236
|
+
flex-direction: column;
|
|
237
|
+
align-items: stretch;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.edit-button {
|
|
241
|
+
margin-top: 8px;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.popover-header {
|
|
245
|
+
padding: 10px 12px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.popover-title {
|
|
249
|
+
font-size: 13px;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Animation for popover appearance */
|
|
254
|
+
@keyframes popoverFadeIn {
|
|
255
|
+
from {
|
|
256
|
+
opacity: 0;
|
|
257
|
+
transform: translateY(-10px);
|
|
258
|
+
}
|
|
259
|
+
to {
|
|
260
|
+
opacity: 1;
|
|
261
|
+
transform: translateY(0);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.text-selection-search-popover {
|
|
266
|
+
animation: popoverFadeIn 0.2s ease-out;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* Scrollbar styling for results */
|
|
270
|
+
.results-list::-webkit-scrollbar {
|
|
271
|
+
width: 6px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.results-list::-webkit-scrollbar-track {
|
|
275
|
+
background: #f1f1f1;
|
|
276
|
+
border-radius: 3px;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.results-list::-webkit-scrollbar-thumb {
|
|
280
|
+
background: #c1c1c1;
|
|
281
|
+
border-radius: 3px;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.results-list::-webkit-scrollbar-thumb:hover {
|
|
285
|
+
background: #a8a8a8;
|
|
286
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- Text Selection Search Popover -->
|
|
3
|
+
<template if:true={isVisible}>
|
|
4
|
+
<div
|
|
5
|
+
class="text-selection-search-popover"
|
|
6
|
+
class:hidden={isHidden}
|
|
7
|
+
onkeydown={handleKeyDown}
|
|
8
|
+
onclick={handlePopoverClick}
|
|
9
|
+
>
|
|
10
|
+
<!-- Header with Title -->
|
|
11
|
+
<div class="popover-header">
|
|
12
|
+
<h3 class="popover-title">Text Editor</h3>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<!-- Selected Text Display -->
|
|
16
|
+
<div class="selected-text-section">
|
|
17
|
+
<label class="section-label">Selected Text</label>
|
|
18
|
+
<div class="selected-text-display">
|
|
19
|
+
{selectedText}
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<!-- Edit Form -->
|
|
24
|
+
<div class="edit-form">
|
|
25
|
+
<form onsubmit={handleSearchSubmit}>
|
|
26
|
+
<div class="input-group">
|
|
27
|
+
<label class="section-label">Edit to:</label>
|
|
28
|
+
<div class="input-with-button">
|
|
29
|
+
<input
|
|
30
|
+
type="text"
|
|
31
|
+
class="edit-input"
|
|
32
|
+
value={searchQuery}
|
|
33
|
+
onchange={handleSearchInputChange}
|
|
34
|
+
onclick={handleInputClick}
|
|
35
|
+
placeholder="Enter your edited text here..."
|
|
36
|
+
autocomplete="off"
|
|
37
|
+
autofocus
|
|
38
|
+
/>
|
|
39
|
+
<dx-button
|
|
40
|
+
type="submit"
|
|
41
|
+
variant="primary"
|
|
42
|
+
disabled={searchButtonDisabled}
|
|
43
|
+
class="edit-button"
|
|
44
|
+
>
|
|
45
|
+
Edit
|
|
46
|
+
</dx-button>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</form>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<!-- Loading State -->
|
|
53
|
+
<template if:true={isLoading}>
|
|
54
|
+
<div class="loading-state">
|
|
55
|
+
<dx-spinner
|
|
56
|
+
size="small"
|
|
57
|
+
alternative-text="Editing..."
|
|
58
|
+
></dx-spinner>
|
|
59
|
+
<span class="loading-text">Processing your edit...</span>
|
|
60
|
+
</div>
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
<!-- Error State -->
|
|
64
|
+
<template if:true={hasError}>
|
|
65
|
+
<div class="error-state">
|
|
66
|
+
<span class="error-message">{errorMessage}</span>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<!-- Success State -->
|
|
71
|
+
<template if:true={isSuccess}>
|
|
72
|
+
<div class="success-state">
|
|
73
|
+
<span class="success-message">Text edited successfully!</span>
|
|
74
|
+
</div>
|
|
75
|
+
</template>
|
|
76
|
+
|
|
77
|
+
<!-- Close Button -->
|
|
78
|
+
<div class="popover-close">
|
|
79
|
+
<dx-button
|
|
80
|
+
onclick={hidePopover}
|
|
81
|
+
variant="tertiary"
|
|
82
|
+
class="close-button"
|
|
83
|
+
title="Close editor"
|
|
84
|
+
>
|
|
85
|
+
×
|
|
86
|
+
</dx-button>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</template>
|
|
90
|
+
</template>
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { LightningElement, api, track } from "lwc";
|
|
2
|
+
|
|
3
|
+
export default class TextSelectionSearch extends LightningElement {
|
|
4
|
+
@api searchApiUrl = "";
|
|
5
|
+
@api repoUrl = "";
|
|
6
|
+
@api placeholder = "Search for...";
|
|
7
|
+
@api popoverPosition = "top";
|
|
8
|
+
@api maxResults = 10;
|
|
9
|
+
|
|
10
|
+
@track isVisible = false;
|
|
11
|
+
@track isHidden = false;
|
|
12
|
+
@track searchQuery = "";
|
|
13
|
+
@track isLoading = false;
|
|
14
|
+
@track isSuccess = false;
|
|
15
|
+
@track errorMessage = "";
|
|
16
|
+
@track popoverStyle = "";
|
|
17
|
+
|
|
18
|
+
selectedText = "";
|
|
19
|
+
selectionStart = 0;
|
|
20
|
+
selectionEnd = 0;
|
|
21
|
+
initialPopoverStyle = "";
|
|
22
|
+
|
|
23
|
+
connectedCallback() {
|
|
24
|
+
this.setupTextSelectionListener();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
disconnectedCallback() {
|
|
28
|
+
this.removeTextSelectionListener();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
setupTextSelectionListener() {
|
|
32
|
+
console.log('TextSelectionSearch: Setting up text selection listeners');
|
|
33
|
+
document.addEventListener("mouseup", (event) => this.handleTextSelection(event));
|
|
34
|
+
document.addEventListener("keyup", (event) => this.handleTextSelection(event));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
removeTextSelectionListener() {
|
|
38
|
+
console.log('TextSelectionSearch: Removing text selection listeners');
|
|
39
|
+
document.removeEventListener("mouseup", (event) => this.handleTextSelection(event));
|
|
40
|
+
document.removeEventListener("keyup", (event) => this.handleTextSelection(event));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
handleTextSelection(event) {
|
|
44
|
+
if (this.isVisible) {
|
|
45
|
+
console.log('TextSelectionSearch: Popover is visible, ignoring text selection event');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log('TextSelectionSearch: Text selection event triggered');
|
|
50
|
+
|
|
51
|
+
if (event && event.target) {
|
|
52
|
+
const target = event.target;
|
|
53
|
+
const popover = this.template.querySelector('.text-selection-search-popover');
|
|
54
|
+
if (popover && popover.contains(target)) {
|
|
55
|
+
console.log('TextSelectionSearch: Click inside popover, ignoring selection event');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const selection = window.getSelection();
|
|
61
|
+
|
|
62
|
+
if (!selection || selection.toString().trim() === "") {
|
|
63
|
+
if (this.isVisible) {
|
|
64
|
+
console.log('TextSelectionSearch: No text selected, but popover is visible - keeping it open');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
console.log('TextSelectionSearch: No text selected, hiding popover');
|
|
68
|
+
this.hidePopover();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this.selectedText = selection.toString().trim();
|
|
73
|
+
console.log('TextSelectionSearch: Selected text:', this.selectedText);
|
|
74
|
+
|
|
75
|
+
if (this.selectedText.length > 0) {
|
|
76
|
+
this.showPopover();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
showPopover() {
|
|
81
|
+
console.log('TextSelectionSearch: Showing popover');
|
|
82
|
+
const selection = window.getSelection();
|
|
83
|
+
if (!selection || selection.rangeCount === 0) {
|
|
84
|
+
console.log('TextSelectionSearch: No selection range found');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const range = selection.getRangeAt(0);
|
|
89
|
+
const rect = range.getBoundingClientRect();
|
|
90
|
+
|
|
91
|
+
const popoverTop = this.popoverPosition === "top"
|
|
92
|
+
? Math.max(10, rect.top - 80)
|
|
93
|
+
: Math.min(window.innerHeight - 200, rect.bottom + 20);
|
|
94
|
+
|
|
95
|
+
const popoverLeft = Math.max(10, Math.min(window.innerWidth - 350, rect.left + (rect.width / 2) - 175));
|
|
96
|
+
|
|
97
|
+
this.popoverStyle = `position: fixed; top: ${popoverTop}px; left: ${popoverLeft}px; z-index: 9999; width: 350px;`;
|
|
98
|
+
this.initialPopoverStyle = this.popoverStyle;
|
|
99
|
+
console.log('TextSelectionSearch: Popover style:', this.popoverStyle);
|
|
100
|
+
|
|
101
|
+
this.isVisible = true;
|
|
102
|
+
this.isHidden = false;
|
|
103
|
+
this.searchQuery = this.selectedText;
|
|
104
|
+
this.errorMessage = "";
|
|
105
|
+
this.isSuccess = false;
|
|
106
|
+
|
|
107
|
+
console.log('TextSelectionSearch: Popover should now be visible');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
hidePopover() {
|
|
111
|
+
console.log('TextSelectionSearch: Hiding popover');
|
|
112
|
+
this.isHidden = true;
|
|
113
|
+
|
|
114
|
+
setTimeout(() => {
|
|
115
|
+
this.isVisible = false;
|
|
116
|
+
this.searchQuery = "";
|
|
117
|
+
this.errorMessage = "";
|
|
118
|
+
this.isSuccess = false;
|
|
119
|
+
this.popoverStyle = "";
|
|
120
|
+
this.initialPopoverStyle = "";
|
|
121
|
+
|
|
122
|
+
const selection = window.getSelection();
|
|
123
|
+
if (selection) {
|
|
124
|
+
selection.removeAllRanges();
|
|
125
|
+
}
|
|
126
|
+
}, 100);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
handlePopoverClick(event) {
|
|
130
|
+
event.stopPropagation();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
handleInputClick(event) {
|
|
134
|
+
event.stopPropagation();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
handleSearchInputChange(event) {
|
|
138
|
+
const target = event.target;
|
|
139
|
+
this.searchQuery = target.value;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async handleSearchSubmit(event) {
|
|
143
|
+
event.preventDefault();
|
|
144
|
+
|
|
145
|
+
if (!this.searchQuery.trim()) {
|
|
146
|
+
this.errorMessage = "Please enter edited text";
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!this.repoUrl.trim()) {
|
|
151
|
+
this.errorMessage = "Repository URL not configured";
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!this.searchApiUrl) {
|
|
156
|
+
this.errorMessage = "Search API URL not configured";
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
await this.performSearch();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async performSearch() {
|
|
164
|
+
this.isLoading = true;
|
|
165
|
+
this.errorMessage = "";
|
|
166
|
+
this.isSuccess = false;
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
const response = await fetch(this.searchApiUrl, {
|
|
170
|
+
method: "POST",
|
|
171
|
+
headers: {
|
|
172
|
+
"Content-Type": "application/json"
|
|
173
|
+
},
|
|
174
|
+
body: JSON.stringify({
|
|
175
|
+
repoUrl: this.repoUrl,
|
|
176
|
+
selectedText: this.selectedText,
|
|
177
|
+
editedText: this.searchQuery
|
|
178
|
+
})
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
if (response.ok) {
|
|
182
|
+
this.isSuccess = true;
|
|
183
|
+
|
|
184
|
+
this.dispatchEvent(
|
|
185
|
+
new CustomEvent("textedited", {
|
|
186
|
+
detail: {
|
|
187
|
+
repoUrl: this.repoUrl,
|
|
188
|
+
selectedText: this.selectedText,
|
|
189
|
+
editedText: this.searchQuery,
|
|
190
|
+
success: true
|
|
191
|
+
}
|
|
192
|
+
})
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
setTimeout(() => {
|
|
196
|
+
this.hidePopover();
|
|
197
|
+
}, 2000);
|
|
198
|
+
} else {
|
|
199
|
+
throw new Error(`Edit failed: ${response.status}`);
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error("Edit failed:", error);
|
|
203
|
+
this.errorMessage = "Edit failed. Please try again.";
|
|
204
|
+
} finally {
|
|
205
|
+
this.isLoading = false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
handleKeyDown(event) {
|
|
210
|
+
if (event.key === "Escape") {
|
|
211
|
+
this.hidePopover();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
get hasError() {
|
|
216
|
+
return this.errorMessage.length > 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
get searchButtonDisabled() {
|
|
220
|
+
return this.isLoading || !this.searchQuery.trim();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
renderedCallback() {
|
|
224
|
+
if (this.isVisible && this.initialPopoverStyle) {
|
|
225
|
+
const popover = this.template.querySelector('.text-selection-search-popover');
|
|
226
|
+
if (popover) {
|
|
227
|
+
popover.style.cssText = this.initialPopoverStyle;
|
|
228
|
+
}
|
|
229
|
+
} else if (!this.isVisible) {
|
|
230
|
+
const popover = this.template.querySelector('.text-selection-search-popover');
|
|
231
|
+
if (popover) {
|
|
232
|
+
popover.style.cssText = '';
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|