@salesforcedevs/dx-components 1.31.0 → 1.32.0-alpha.10
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/LICENSE +12 -0
- package/lwc.config.json +1 -0
- package/package.json +3 -2
- package/src/modules/dx/dropdownOption/dropdownOption.css +13 -8
- package/src/modules/dx/searchResults/searchResults.css +107 -6
- package/src/modules/dx/searchResults/searchResults.html +87 -91
- package/src/modules/dx/searchResults/searchResults.ts +174 -477
- package/src/modules/dx/sidebar/sidebar.css +1 -0
- package/src/modules/dx/sidebar/sidebar.html +1 -5
- package/src/modules/dx/sidebar/sidebar.ts +44 -29
- package/src/modules/dx/sidebarSearch/sidebarSearch.ts +159 -343
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.css +57 -23
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.ts +12 -4
- package/src/modules/dxUtils/data360Search/data360Search.ts +168 -0
|
@@ -1,75 +1,71 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import debounce from "debounce";
|
|
3
|
+
import { track as trackGTM } from "dxUtils/analytics";
|
|
3
4
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
loadAdvancedSearchQueryActions,
|
|
14
|
-
SearchEngine,
|
|
15
|
-
SearchAppState,
|
|
16
|
-
loadQueryActions
|
|
17
|
-
} from "@coveo/headless";
|
|
18
|
-
import { buildSearchEngine, getSidebarSearchParams } from "dxUtils/coveo";
|
|
5
|
+
type Data360SearchCacheItem,
|
|
6
|
+
type Data360SearchResultItem,
|
|
7
|
+
fetchSearch,
|
|
8
|
+
getBaseUrlPath,
|
|
9
|
+
getStoredSearch,
|
|
10
|
+
isCacheStale,
|
|
11
|
+
setStoredSearch
|
|
12
|
+
} from "dxUtils/data360Search";
|
|
13
|
+
import { createSearchRegExp } from "dxUtils/regexps";
|
|
19
14
|
import { RecentSearches } from "dxUtils/recentSearches";
|
|
20
|
-
import { toJson } from "dxUtils/normalizers";
|
|
21
15
|
import {
|
|
16
|
+
type HighlightedSections,
|
|
22
17
|
Option,
|
|
23
18
|
PopoverRequestCloseType,
|
|
24
19
|
SidebarSearchResult
|
|
25
20
|
} from "typings/custom";
|
|
26
21
|
|
|
27
|
-
const RESULT_CLICK_LOCAL_STORAGE_KEY = "dx-sidebar-search-result-click";
|
|
28
|
-
export const SESSION_KEY = "dx-sidebar-search-state";
|
|
29
|
-
|
|
30
|
-
const DEFAULT_RESULT_COUNT = 20;
|
|
31
22
|
const SEARCH_DEBOUNCE_DELAY = 1200;
|
|
32
23
|
|
|
33
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Find all matches of the search query in text and return ranges for highlighting.
|
|
26
|
+
* Uses the same regex as the full-doc highlighter (createSearchRegExp) so sidebar
|
|
27
|
+
* and doc highlight the same phrases (including spaces between words).
|
|
28
|
+
*/
|
|
29
|
+
function getHighlightRanges(
|
|
30
|
+
text: string,
|
|
31
|
+
searchQuery: string
|
|
32
|
+
): HighlightedSections {
|
|
33
|
+
if (!text || !searchQuery.trim()) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
const re = createSearchRegExp(searchQuery.trim());
|
|
37
|
+
const ranges: HighlightedSections = [];
|
|
38
|
+
let match: RegExpExecArray | null;
|
|
39
|
+
while ((match = re.exec(text)) !== null) {
|
|
40
|
+
ranges.push({ offset: match.index, length: match[0].length });
|
|
41
|
+
}
|
|
42
|
+
return ranges;
|
|
43
|
+
}
|
|
34
44
|
|
|
35
|
-
const
|
|
36
|
-
version?.split(".").join("\\.");
|
|
45
|
+
const UserRecentSearches = new RecentSearches();
|
|
37
46
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
@api coveoSearchHub!: string;
|
|
42
|
-
@api
|
|
43
|
-
get coveoAdvancedQueryConfig(): { [key: string]: any } {
|
|
44
|
-
return this._coveoAdvancedQueryConfig;
|
|
45
|
-
}
|
|
46
|
-
set coveoAdvancedQueryConfig(value) {
|
|
47
|
-
const jsonValue = toJson(value);
|
|
48
|
-
const hasChanged =
|
|
49
|
-
this._coveoAdvancedQueryConfig &&
|
|
50
|
-
Object.entries(jsonValue).some(
|
|
51
|
-
([key, val]: [string, any]) =>
|
|
52
|
-
this._coveoAdvancedQueryConfig[key] !== val
|
|
53
|
-
);
|
|
54
|
-
this._coveoAdvancedQueryConfig = jsonValue;
|
|
47
|
+
function resultPathFromHref(href: string): string {
|
|
48
|
+
return href.startsWith("http") ? new URL(href).pathname : href;
|
|
49
|
+
}
|
|
55
50
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
function applySelectedAndSelect(
|
|
52
|
+
items: Data360SearchCacheItem[]
|
|
53
|
+
): SidebarSearchResult[] {
|
|
54
|
+
const currentPath = window.location.pathname;
|
|
55
|
+
return items.map((item) => ({
|
|
56
|
+
...item,
|
|
57
|
+
selected: !!item.href && resultPathFromHref(item.href) === currentPath,
|
|
58
|
+
select: () => {}
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.setAdvancedFilters(this.engine);
|
|
63
|
-
this.submitSearch(true);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
62
|
+
const getSearchQueryParam = (): string =>
|
|
63
|
+
new URLSearchParams(window.location.search).get("q") ?? "";
|
|
66
64
|
|
|
65
|
+
export default class SidebarSearch extends LightningElement {
|
|
67
66
|
@api
|
|
68
67
|
public fetchMoreResults() {
|
|
69
|
-
|
|
70
|
-
this.fetchingMoreResults = true;
|
|
71
|
-
this.resultList.fetchMoreResults();
|
|
72
|
-
}
|
|
68
|
+
// Data 360 Search API does not expose pagination in the same way; no-op
|
|
73
69
|
}
|
|
74
70
|
|
|
75
71
|
@api
|
|
@@ -85,313 +81,144 @@ export default class SidebarSearch extends LightningElement {
|
|
|
85
81
|
this.dropdownRequestedOpen = value;
|
|
86
82
|
}
|
|
87
83
|
|
|
88
|
-
private _coveoAdvancedQueryConfig!: { [key: string]: any };
|
|
89
84
|
private dropdownRequestedOpen: boolean = false;
|
|
90
85
|
private recentSearches: Option[] = [];
|
|
91
|
-
private
|
|
92
|
-
private resultList: ResultList | null = null;
|
|
93
|
-
private resultsPerPage: ResultsPerPage | null = null;
|
|
94
|
-
private preloadedState?: SearchAppState;
|
|
95
|
-
private searchBox: SearchBox | null = null;
|
|
96
|
-
private value?: string = "";
|
|
97
|
-
private engine: SearchEngine | null = null;
|
|
98
|
-
private fetchingMoreResults: boolean = false;
|
|
86
|
+
private value: string = "";
|
|
99
87
|
private didRender = false;
|
|
100
|
-
|
|
101
|
-
private
|
|
102
|
-
const coveoConfigurations = [
|
|
103
|
-
this.coveoOrganizationId,
|
|
104
|
-
this.coveoPublicAccessToken,
|
|
105
|
-
this.coveoSearchHub,
|
|
106
|
-
this.coveoAdvancedQueryConfig
|
|
107
|
-
];
|
|
108
|
-
|
|
109
|
-
return coveoConfigurations.every(
|
|
110
|
-
(val) =>
|
|
111
|
-
!!val && (typeof val === "string" || typeof val === "object")
|
|
112
|
-
);
|
|
113
|
-
}
|
|
88
|
+
private data360SearchInitialized: boolean = false;
|
|
89
|
+
private didTrackThisSearch: boolean = false;
|
|
114
90
|
|
|
115
91
|
private get isDropdownOpen() {
|
|
116
92
|
return (
|
|
117
93
|
this.dropdownRequestedOpen &&
|
|
118
|
-
this.recentSearches &&
|
|
119
|
-
this.recentSearches.length > 0 &&
|
|
94
|
+
this.recentSearches?.length > 0 &&
|
|
120
95
|
!this.value
|
|
121
96
|
);
|
|
122
97
|
}
|
|
123
98
|
|
|
124
99
|
constructor() {
|
|
125
100
|
super();
|
|
126
|
-
|
|
127
101
|
this.updateRecentSearches();
|
|
128
|
-
this.value =
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
disconnectedCallback() {
|
|
132
|
-
this.unsubscribeFromResultList();
|
|
102
|
+
this.value = getSearchQueryParam();
|
|
133
103
|
}
|
|
134
104
|
|
|
135
105
|
renderedCallback() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
106
|
+
if (!this.data360SearchInitialized) {
|
|
107
|
+
this.data360SearchInitialized = true;
|
|
108
|
+
if (this.value) {
|
|
109
|
+
const baseUrlPath = getBaseUrlPath();
|
|
110
|
+
const cached = getStoredSearch(baseUrlPath);
|
|
111
|
+
const queryTrimmed = this.value.trim();
|
|
112
|
+
if (
|
|
113
|
+
cached?.query === queryTrimmed &&
|
|
114
|
+
Array.isArray(cached.results) &&
|
|
115
|
+
!isCacheStale(cached)
|
|
116
|
+
) {
|
|
117
|
+
if (!this.didRender) {
|
|
118
|
+
this.dispatchHighlightedTermChange();
|
|
119
|
+
}
|
|
120
|
+
const results = applySelectedAndSelect(cached.results);
|
|
121
|
+
this.dispatchChange(results);
|
|
122
|
+
this.dispatchOnLoading(false);
|
|
123
|
+
} else {
|
|
124
|
+
if (!this.didRender) {
|
|
125
|
+
this.dispatchHighlightedTermChange();
|
|
126
|
+
}
|
|
127
|
+
this.dispatchOnLoading(true);
|
|
128
|
+
this.fetchDataCloudSearch();
|
|
150
129
|
}
|
|
151
|
-
|
|
130
|
+
} else {
|
|
131
|
+
// No URL query: restore search bar and results from localStorage for this path
|
|
132
|
+
const baseUrlPath = getBaseUrlPath();
|
|
133
|
+
const cached = getStoredSearch(baseUrlPath);
|
|
134
|
+
if (cached?.query && !isCacheStale(cached)) {
|
|
135
|
+
this.value = cached.query;
|
|
136
|
+
const results = applySelectedAndSelect(
|
|
137
|
+
cached.results ?? []
|
|
138
|
+
);
|
|
139
|
+
this.dispatchChange(results);
|
|
140
|
+
this.dispatchHighlightedTermChange();
|
|
141
|
+
}
|
|
142
|
+
this.dispatchOnLoading(false);
|
|
143
|
+
}
|
|
152
144
|
}
|
|
153
|
-
|
|
154
|
-
// If this is the first render and there is a search value, trigger
|
|
155
|
-
// term highlighting
|
|
156
145
|
if (!this.didRender && this.value) {
|
|
157
146
|
this.dispatchHighlightedTermChange();
|
|
158
147
|
}
|
|
159
|
-
|
|
160
148
|
this.didRender = true;
|
|
161
149
|
}
|
|
162
150
|
|
|
163
|
-
private
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
151
|
+
private normalizeDataCloudResult = (
|
|
152
|
+
item: Data360SearchResultItem,
|
|
153
|
+
index: number
|
|
154
|
+
): SidebarSearchResult => {
|
|
155
|
+
const href = item.url ?? "";
|
|
156
|
+
const resultPath = href.startsWith("http")
|
|
157
|
+
? new URL(href).pathname
|
|
158
|
+
: href;
|
|
159
|
+
const isSelected =
|
|
160
|
+
!!resultPath && resultPath === window.location.pathname;
|
|
161
|
+
const title = item.title ?? "";
|
|
162
|
+
const excerpt = item.matchedText ?? "";
|
|
163
|
+
const searchQuery = this.value.trim();
|
|
164
|
+
return {
|
|
165
|
+
title,
|
|
166
|
+
titleHighlights: getHighlightRanges(title, searchQuery),
|
|
167
|
+
excerpt,
|
|
168
|
+
excerptHighlights: getHighlightRanges(excerpt, searchQuery),
|
|
169
|
+
uniqueId: href || `result-${index}`,
|
|
170
|
+
href,
|
|
171
|
+
selected: isSelected,
|
|
172
|
+
select: () => {}
|
|
173
|
+
};
|
|
174
|
+
};
|
|
169
175
|
|
|
176
|
+
private async fetchDataCloudSearch(): Promise<void> {
|
|
170
177
|
try {
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
).every(
|
|
176
|
-
([key, value]: [string, any]) =>
|
|
177
|
-
this.coveoAdvancedQueryConfig[key] === value
|
|
178
|
+
const query = this.value.trim();
|
|
179
|
+
const rawResults = await fetchSearch(query);
|
|
180
|
+
const results: SidebarSearchResult[] = rawResults.map(
|
|
181
|
+
this.normalizeDataCloudResult
|
|
178
182
|
);
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
private initializeCoveo = () => {
|
|
193
|
-
try {
|
|
194
|
-
this.engine = buildSearchEngine({
|
|
195
|
-
organizationId: this.coveoOrganizationId,
|
|
196
|
-
publicAccessToken: this.coveoPublicAccessToken,
|
|
197
|
-
searchHub: this.coveoSearchHub,
|
|
198
|
-
preloadedState: this.preloadedState
|
|
199
|
-
});
|
|
200
|
-
} catch (ex) {
|
|
201
|
-
console.error(`Coveo engine failed to initialize (${ex})`);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (!this.engine) {
|
|
205
|
-
console.error("Coveo engine failed to initialize!");
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (this.preloadedState) {
|
|
210
|
-
const actions = loadQueryActions(this.engine);
|
|
211
|
-
this.engine.dispatch(actions.updateQuery({ q: this.value || "" }));
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
this.resultList = buildResultList(this.engine, {
|
|
215
|
-
options: { fieldsToInclude: ["sfhtml_url__c"] }
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
this.resultsPerPage = buildResultsPerPage(this.engine, {
|
|
219
|
-
initialState: {
|
|
220
|
-
numberOfResults: DEFAULT_RESULT_COUNT
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
this.searchBox = buildSearchBox(this.engine, {
|
|
225
|
-
options: { numberOfSuggestions: 3 }
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
this.setAdvancedFilters(this.engine);
|
|
229
|
-
|
|
230
|
-
this.unsubscribeFromResultList = this.resultList?.subscribe(
|
|
231
|
-
this.onResultListChange
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
if (this.value) {
|
|
235
|
-
this.dispatchHighlightedTermChange();
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (!this.preloadedState) {
|
|
239
|
-
if (this.value) {
|
|
240
|
-
this.submitSearch();
|
|
241
|
-
} else {
|
|
242
|
-
this.dispatchOnLoading(false);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
this.syncAnalytics();
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
private syncAnalytics = () => {
|
|
250
|
-
const storedResult = window.localStorage.getItem(
|
|
251
|
-
RESULT_CLICK_LOCAL_STORAGE_KEY
|
|
252
|
-
);
|
|
253
|
-
if (storedResult) {
|
|
254
|
-
const interactiveResult = buildInteractiveResult(this.engine!, {
|
|
255
|
-
options: { result: JSON.parse(storedResult) }
|
|
183
|
+
this.dispatchChange(results);
|
|
184
|
+
this.trackSearchResultsOnce(query, results.length);
|
|
185
|
+
const cacheItems: Data360SearchCacheItem[] = results.map((r) => ({
|
|
186
|
+
title: r.title,
|
|
187
|
+
titleHighlights: r.titleHighlights,
|
|
188
|
+
excerpt: r.excerpt,
|
|
189
|
+
excerptHighlights: r.excerptHighlights,
|
|
190
|
+
uniqueId: r.uniqueId,
|
|
191
|
+
href: r.href
|
|
192
|
+
}));
|
|
193
|
+
setStoredSearch(getBaseUrlPath(), {
|
|
194
|
+
query: this.value.trim(),
|
|
195
|
+
results: cacheItems
|
|
256
196
|
});
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
private onResultListChange = () => {
|
|
264
|
-
if (!this.resultList) {
|
|
265
|
-
return;
|
|
197
|
+
} catch (err) {
|
|
198
|
+
console.error("Data 360 Search request failed", err);
|
|
199
|
+
this.dispatchChange([]);
|
|
200
|
+
} finally {
|
|
201
|
+
this.dispatchOnLoading(false);
|
|
266
202
|
}
|
|
203
|
+
}
|
|
267
204
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if ((!firstSearchExecuted && !isLoading) || !this.value) {
|
|
272
|
-
// coveo search is firing off some unwanted payloads on startup
|
|
205
|
+
private trackSearchResultsOnce(term: string, resultCount: number): void {
|
|
206
|
+
if (this.didTrackThisSearch || !term) {
|
|
273
207
|
return;
|
|
274
208
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
this.dispatchOnLoading(isLoading);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (!isLoading && this.fetchingMoreResults) {
|
|
285
|
-
this.fetchingMoreResults = false;
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
private setAdvancedFilters(engine: SearchEngine) {
|
|
290
|
-
const aq = Object.entries(this.coveoAdvancedQueryConfig).reduce(
|
|
291
|
-
(result, [key, value]) =>
|
|
292
|
-
`${result}(@${key}=="${normalizeCoveoAdvancedQueryValue(
|
|
293
|
-
value
|
|
294
|
-
)}")`,
|
|
295
|
-
""
|
|
296
|
-
);
|
|
297
|
-
|
|
298
|
-
const registerSearchQueryAction = loadAdvancedSearchQueryActions(
|
|
299
|
-
engine
|
|
300
|
-
).registerAdvancedSearchQueries({
|
|
301
|
-
aq: aq
|
|
209
|
+
this.didTrackThisSearch = true;
|
|
210
|
+
trackGTM(this.template.host, "custEv_scopedSearch", {
|
|
211
|
+
search_term: term,
|
|
212
|
+
search_category: "",
|
|
213
|
+
search_type: "site search",
|
|
214
|
+
search_result_count: resultCount
|
|
302
215
|
});
|
|
303
|
-
|
|
304
|
-
engine.dispatch(registerSearchQueryAction);
|
|
305
216
|
}
|
|
306
217
|
|
|
307
|
-
private
|
|
308
|
-
const {
|
|
309
|
-
clickUri,
|
|
310
|
-
excerpt,
|
|
311
|
-
excerptHighlights,
|
|
312
|
-
raw: { sfhtml_url__c },
|
|
313
|
-
title,
|
|
314
|
-
titleHighlights,
|
|
315
|
-
uniqueId
|
|
316
|
-
} = result;
|
|
317
|
-
|
|
318
|
-
// discussion about this normalization here: https://salesforce-internal.slack.com/archives/C020S6784JX/p1639506238376600
|
|
319
|
-
|
|
320
|
-
let pathname, queryParam;
|
|
321
|
-
if (sfhtml_url__c) {
|
|
322
|
-
pathname = `/docs/${sfhtml_url__c}`;
|
|
323
|
-
} else {
|
|
324
|
-
const isNestedGuide = clickUri.includes("/guide/");
|
|
325
|
-
const url = new URL(clickUri);
|
|
326
|
-
const extension =
|
|
327
|
-
isNestedGuide && !url.pathname?.endsWith(".html")
|
|
328
|
-
? ".html"
|
|
329
|
-
: "";
|
|
330
|
-
pathname = `${url.pathname}${extension}`;
|
|
331
|
-
queryParam = url.search;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
let href;
|
|
335
|
-
let isSelected = false;
|
|
336
|
-
const isReferenceUrl = clickUri.includes("/references/");
|
|
337
|
-
if (isReferenceUrl) {
|
|
338
|
-
if (queryParam) {
|
|
339
|
-
href = `${pathname}${queryParam}&q=${this.value}`;
|
|
340
|
-
} else {
|
|
341
|
-
href = `${pathname}?q=${this.value}`;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
//NOTE: This is specific to references related comparison
|
|
345
|
-
const resultHrefWithMetaQuery = `${pathname}${queryParam}`;
|
|
346
|
-
|
|
347
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
348
|
-
const metaQueryParam = urlParams.get("meta");
|
|
349
|
-
|
|
350
|
-
let currentUrlPathWithQuery = window.location.pathname;
|
|
351
|
-
if (metaQueryParam) {
|
|
352
|
-
currentUrlPathWithQuery = `${currentUrlPathWithQuery}?meta=${metaQueryParam}`;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
isSelected = resultHrefWithMetaQuery === currentUrlPathWithQuery;
|
|
356
|
-
} else {
|
|
357
|
-
href = `${pathname}?q=${this.value}`;
|
|
358
|
-
isSelected = pathname === window.location.pathname;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return {
|
|
362
|
-
title,
|
|
363
|
-
titleHighlights,
|
|
364
|
-
excerpt,
|
|
365
|
-
excerptHighlights,
|
|
366
|
-
uniqueId,
|
|
367
|
-
href,
|
|
368
|
-
selected: isSelected,
|
|
369
|
-
select: () =>
|
|
370
|
-
window.localStorage.setItem(
|
|
371
|
-
RESULT_CLICK_LOCAL_STORAGE_KEY,
|
|
372
|
-
JSON.stringify(result)
|
|
373
|
-
)
|
|
374
|
-
};
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
private updateSessionStorage() {
|
|
378
|
-
window.sessionStorage.setItem(
|
|
379
|
-
SESSION_KEY,
|
|
380
|
-
JSON.stringify({
|
|
381
|
-
coveoAdvancedQueryConfig: this.coveoAdvancedQueryConfig,
|
|
382
|
-
state: this.engine?.state
|
|
383
|
-
})
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
private dispatchOnChangeEvent(results: Result[]) {
|
|
388
|
-
this.updateSessionStorage();
|
|
218
|
+
private dispatchChange(results: SidebarSearchResult[]) {
|
|
389
219
|
this.dispatchEvent(
|
|
390
220
|
new CustomEvent("change", {
|
|
391
|
-
detail: {
|
|
392
|
-
results: results.map(this.normalizeCoveoResult),
|
|
393
|
-
value: this.value
|
|
394
|
-
}
|
|
221
|
+
detail: { results, value: this.value }
|
|
395
222
|
})
|
|
396
223
|
);
|
|
397
224
|
}
|
|
@@ -427,24 +254,18 @@ export default class SidebarSearch extends LightningElement {
|
|
|
427
254
|
}
|
|
428
255
|
|
|
429
256
|
private submitSearch = debounce((isSyncingSearchValue = false) => {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
// When `isSyncingSearchValue` is true, we are submitting in a case
|
|
435
|
-
// where the search box is already synced correctly.
|
|
436
|
-
if (!isSyncingSearchValue) {
|
|
437
|
-
this.dispatchSidebarSearchChange(this.value);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
this.searchBox.updateText(this.value || "");
|
|
441
|
-
this.searchBox.submit();
|
|
257
|
+
UserRecentSearches.add(this.value);
|
|
258
|
+
this.updateRecentSearches();
|
|
259
|
+
if (!isSyncingSearchValue) {
|
|
260
|
+
this.dispatchSidebarSearchChange(this.value);
|
|
442
261
|
}
|
|
262
|
+
this.fetchDataCloudSearch();
|
|
443
263
|
}, SEARCH_DEBOUNCE_DELAY);
|
|
444
264
|
|
|
445
265
|
private onClickRecentSearch(e: CustomEvent) {
|
|
446
266
|
this.value = e.detail;
|
|
447
267
|
this.dispatchSidebarSearchChange(this.value);
|
|
268
|
+
this.dispatchOnLoading(true);
|
|
448
269
|
this.submitSearch(true);
|
|
449
270
|
}
|
|
450
271
|
|
|
@@ -461,7 +282,6 @@ export default class SidebarSearch extends LightningElement {
|
|
|
461
282
|
|
|
462
283
|
private onInputChange(e: CustomEvent) {
|
|
463
284
|
this.value = e.detail;
|
|
464
|
-
|
|
465
285
|
this.handleValueChange(false);
|
|
466
286
|
this.dispatchHighlightedTermChange();
|
|
467
287
|
}
|
|
@@ -476,18 +296,14 @@ export default class SidebarSearch extends LightningElement {
|
|
|
476
296
|
|
|
477
297
|
private handleValueChange(isSyncingSearchValue = false) {
|
|
478
298
|
if (this.value) {
|
|
299
|
+
this.didTrackThisSearch = false;
|
|
479
300
|
this.dispatchOnLoading(true);
|
|
480
|
-
|
|
481
|
-
this.submitSearch(isSyncingSearchValue);
|
|
482
|
-
}
|
|
301
|
+
this.submitSearch(isSyncingSearchValue);
|
|
483
302
|
} else {
|
|
484
|
-
// coveo's reaction to an empty value triggers a return of results
|
|
485
|
-
// bootlegging our own ux here`
|
|
486
303
|
this.dispatchOnLoading(false);
|
|
487
|
-
this.
|
|
488
|
-
// Empty search values are not submitted for search, so we need to manually
|
|
489
|
-
// trigger a search change on our own here
|
|
304
|
+
this.dispatchChange([]);
|
|
490
305
|
this.dispatchSidebarSearchChange(this.value);
|
|
306
|
+
setStoredSearch(getBaseUrlPath(), { query: "", results: [] });
|
|
491
307
|
}
|
|
492
308
|
}
|
|
493
309
|
}
|