@searchstax-inc/searchstudio-ux-vue 1.0.48 → 2.0.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 +1084 -529
- package/README.mustache +644 -0
- package/dist/@searchstax-inc/components/SearchstaxAnswerWidget.vue.d.ts +1 -1
- package/dist/@searchstax-inc/components/SearchstaxAnswerWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/SearchstaxExternalPromotionsWidget.vue.d.ts +1 -1
- package/dist/@searchstax-inc/components/SearchstaxExternalPromotionsWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/SearchstaxFacetsWidget.vue.d.ts +16 -1
- package/dist/@searchstax-inc/components/SearchstaxFacetsWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/SearchstaxInputWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/SearchstaxLocationWidget.vue.d.ts +1 -1
- package/dist/@searchstax-inc/components/SearchstaxLocationWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/SearchstaxPaginationWidget.vue.d.ts +1 -1
- package/dist/@searchstax-inc/components/SearchstaxPaginationWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/SearchstaxRelatedSearchesWidget.vue.d.ts +1 -1
- package/dist/@searchstax-inc/components/SearchstaxRelatedSearchesWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/SearchstaxResultWidget.vue.d.ts +10 -1
- package/dist/@searchstax-inc/components/SearchstaxResultWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/SearchstaxSearchFeedbackWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/SearchstaxSortingWidget.vue.d.ts.map +1 -1
- package/dist/@searchstax-inc/components/templates/SearchstaxAnswerWidgetTemplate.vue.d.ts +22 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxAnswerWidgetTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxExternalPromotionsWidgetTemplate.vue.d.ts +22 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxExternalPromotionsWidgetTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxFacetsWidgetDesktopTemplate.vue.d.ts +64 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxFacetsWidgetDesktopTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxFacetsWidgetMobileTemplate.vue.d.ts +112 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxFacetsWidgetMobileTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxInputWidgetTemplate.vue.d.ts +38 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxInputWidgetTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxLocationWidgetTemplate.vue.d.ts +70 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxLocationWidgetTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxPaginationWidgetDefaultTemplate.vue.d.ts +30 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxPaginationWidgetDefaultTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxPaginationWidgetInfiniteScrollTemplate.vue.d.ts +13 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxPaginationWidgetInfiniteScrollTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxRelatedSearchesWidgetTemplate.vue.d.ts +22 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxRelatedSearchesWidgetTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxResultWidgetDefaultTemplate.vue.d.ts +22 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxResultWidgetDefaultTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxResultWidgetNoResultsTemplate.vue.d.ts +58 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxResultWidgetNoResultsTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxSearchFeedbackWidgetTemplate.vue.d.ts +22 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxSearchFeedbackWidgetTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxSortingWidgetTemplate.vue.d.ts +30 -0
- package/dist/@searchstax-inc/components/templates/SearchstaxSortingWidgetTemplate.vue.d.ts.map +1 -0
- package/dist/@searchstax-inc/searchstudio-ux-vue.cjs +70 -68
- package/dist/@searchstax-inc/searchstudio-ux-vue.iife.js +65 -63
- package/dist/@searchstax-inc/searchstudio-ux-vue.mjs +3296 -2681
- package/dist/@searchstax-inc/stores/searchstaxStore.d.ts +9 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ Initialization example
|
|
|
55
55
|
```
|
|
56
56
|
sampleConfig = {
|
|
57
57
|
language: "en",
|
|
58
|
-
model: "",
|
|
58
|
+
model: "Main Profile",
|
|
59
59
|
searchURL: "",
|
|
60
60
|
suggesterURL: "",
|
|
61
61
|
trackApiKey: "",
|
|
@@ -156,124 +156,90 @@ Following widgets are available:
|
|
|
156
156
|
[sorting Widget](#sorting-widget)
|
|
157
157
|
|
|
158
158
|
### Answer Widget ###
|
|
159
|
+
SearchStax Site Search solution offers Vue widgets to assist in building your custom search page.
|
|
160
|
+
|
|
161
|
+
The SearchstaxAnswerWidget component for Vue provides an AI answer widget for your searches.
|
|
162
|
+
|
|
163
|
+
**Usage**
|
|
159
164
|
|
|
160
|
-
example of answer widget initialization with minimum options
|
|
161
165
|
```
|
|
162
|
-
|
|
166
|
+
<SearchstaxAnswerWidget :showShowMoreAfterWordCount="10"></SearchstaxAnswerWidget>
|
|
163
167
|
```
|
|
164
168
|
|
|
169
|
+
**Props**
|
|
170
|
+
|
|
171
|
+
- showShowMoreAfterWordCount - number(default 100) determining after how many symbols UI will show “Read More” view.
|
|
172
|
+
- feedbackWidget – an optional object that configures thumbs-up and thumbs-down feedback functionality.
|
|
165
173
|
|
|
166
|
-
|
|
174
|
+
Example of feedbackWidget config:
|
|
167
175
|
```
|
|
168
|
-
feedbackConfig = {
|
|
176
|
+
const feedbackConfig = {
|
|
169
177
|
renderFeedbackWidget: true,
|
|
170
|
-
emailOverride:
|
|
178
|
+
emailOverride: searchstaxEmailOverride,
|
|
171
179
|
thumbsUpValue: 10,
|
|
172
|
-
thumbsDownValue: 0
|
|
173
|
-
lightweightTemplateOverride: `
|
|
174
|
-
<div class="searchstax-lightweight-widget-container">
|
|
175
|
-
<div class="searchstax-lightweight-widget-thumbs-up {{#thumbsUpActive}}active{{/thumbsUpActive}}">
|
|
176
|
-
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
177
|
-
<path d="M4.85079 7.59996L7.83141 1C8.4243 1 8.9929 1.23178 9.41213 1.64436C9.83136 2.05694 10.0669 2.61651 10.0669 3.19999V6.1333H14.2845C14.5005 6.13089 14.7145 6.17474 14.9116 6.26179C15.1087 6.34885 15.2842 6.47704 15.426 6.63747C15.5677 6.79791 15.6723 6.98676 15.7326 7.19094C15.7928 7.39513 15.8072 7.60975 15.7748 7.81996L14.7465 14.4199C14.6926 14.7696 14.5121 15.0884 14.2382 15.3175C13.9643 15.5466 13.6156 15.6706 13.2562 15.6666H4.85079M4.85079 7.59996V15.6666M4.85079 7.59996H2.61531C2.22006 7.59996 1.84099 7.75448 1.5615 8.02953C1.28201 8.30458 1.125 8.67763 1.125 9.06661V14.1999C1.125 14.5889 1.28201 14.9619 1.5615 15.237C1.84099 15.512 2.22006 15.6666 2.61531 15.6666H4.85079" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
178
|
-
</svg>
|
|
179
|
-
</div>
|
|
180
|
-
<div class="searchstax-lightweight-widget-separator"></div>
|
|
181
|
-
<div class="searchstax-lightweight-widget-thumbs-down {{#thumbsDownActive}}active{{/thumbsDownActive}}">
|
|
182
|
-
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
183
|
-
<path d="M12.1492 9.06801L9.16859 15.668C8.5757 15.668 8.0071 15.4362 7.58787 15.0236C7.16864 14.611 6.93311 14.0515 6.93311 13.468V10.5347H2.71552C2.4995 10.5371 2.28552 10.4932 2.08842 10.4062C1.89132 10.3191 1.71581 10.1909 1.57405 10.0305C1.43229 9.87006 1.32766 9.6812 1.26743 9.47702C1.2072 9.27284 1.19279 9.05822 1.22521 8.84801L2.25353 2.24806C2.30742 1.89833 2.48793 1.57955 2.76179 1.35046C3.03566 1.12136 3.38443 0.997398 3.74384 1.0014H12.1492M12.1492 9.06801V1.0014M12.1492 9.06801H14.3847C14.7799 9.06801 15.159 8.91349 15.4385 8.63844C15.718 8.36339 15.875 7.99034 15.875 7.60135V2.46805C15.875 2.07907 15.718 1.70602 15.4385 1.43097C15.159 1.15592 14.7799 1.0014 14.3847 1.0014H12.1492" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
184
|
-
</svg>
|
|
185
|
-
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
188
|
-
`
|
|
180
|
+
thumbsDownValue: 0
|
|
189
181
|
}
|
|
190
|
-
<SearchstaxAnswerWidget :showShowMoreAfterWordCount="100" :feedbackwidget="feedbackConfig">
|
|
191
|
-
<template #answer="{ answerData, showMore }">
|
|
192
|
-
<div v-if="answerData && answerData?.searchExecuted && answerData.shouldShowAnswer">
|
|
193
|
-
<div class="searchstax-answer-wrap">
|
|
194
|
-
<div class="searchstax-answer-icon"></div>
|
|
195
|
-
<div>
|
|
196
|
-
<div
|
|
197
|
-
:class="
|
|
198
|
-
'searchstax-answer-container ' + answerData.showMoreButtonVisible
|
|
199
|
-
? 'searchstax-answer-show-more'
|
|
200
|
-
: ''
|
|
201
|
-
"
|
|
202
|
-
>
|
|
203
|
-
<div class="searchstax-answer-title">Smart Answers</div>
|
|
204
|
-
<div class="searchstax-answer-error" v-if="answerData.shouldShowAnswerError" v-html="answerData.answerErrorMessage"></div>
|
|
205
|
-
<div
|
|
206
|
-
class="searchstax-answer-description"
|
|
207
|
-
v-html="answerData.fullAnswerFormatted"
|
|
208
|
-
></div>
|
|
209
|
-
<div v-if="answerData.answerLoading" class="searchstax-answer-loading"></div>
|
|
210
|
-
</div>
|
|
211
|
-
<div
|
|
212
|
-
v-if="answerData.showMoreButtonVisible"
|
|
213
|
-
class="searchstax-answer-load-more-button-container"
|
|
214
|
-
>
|
|
215
|
-
<button class="searchstax-answer-load-more-button" @click="showMore">
|
|
216
|
-
Read More
|
|
217
|
-
</button>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
<div class="searchstax-answer-footer">
|
|
221
|
-
<div id="feedbackWidgetContainer"></div>
|
|
222
|
-
<div class="searchstax-lightweight-widget-separator-inline"></div>
|
|
223
|
-
<p class="searchstax-disclaimer">Generative AI is Experimental</p>
|
|
224
|
-
</div>
|
|
225
|
-
</div>
|
|
226
|
-
</div>
|
|
227
|
-
</template>
|
|
228
|
-
</SearchstaxAnswerWidget>
|
|
229
182
|
```
|
|
230
183
|
|
|
231
|
-
|
|
184
|
+
|
|
185
|
+
**searchAnswerTemplate**
|
|
186
|
+
|
|
187
|
+
The templates prop allows customizing the answer UI.
|
|
188
|
+
|
|
189
|
+
It receives the following props:
|
|
190
|
+
|
|
191
|
+
- answerData – Data object of type: ISearchstaxAnswerData
|
|
192
|
+
- showMore - Handler for exiting the show more view
|
|
193
|
+
|
|
194
|
+
**Example**
|
|
195
|
+
|
|
232
196
|
```
|
|
233
|
-
|
|
197
|
+
<SearchstaxAnswerWidget :showShowMoreAfterWordCount="100" :feedbackwidget="feedbackConfig">
|
|
234
198
|
<template #answer="{ answerData, showMore }">
|
|
235
199
|
<div v-if="answerData && answerData?.searchExecuted && answerData.shouldShowAnswer">
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
Read More
|
|
260
|
-
</button>
|
|
261
|
-
</div>
|
|
262
|
-
</div>
|
|
263
|
-
<div class="searchstax-answer-footer">
|
|
264
|
-
<div id="feedbackWidgetContainer"></div>
|
|
265
|
-
<div class="searchstax-lightweight-widget-separator-inline"></div>
|
|
266
|
-
<p class="searchstax-disclaimer">Generative AI is Experimental</p>
|
|
267
|
-
</div>
|
|
268
|
-
</div>
|
|
200
|
+
<div class="searchstax-answer-wrap">
|
|
201
|
+
<div class="searchstax-answer-icon"></div>
|
|
202
|
+
<div>
|
|
203
|
+
<div
|
|
204
|
+
:class="{
|
|
205
|
+
'searchstax-answer-container': true,
|
|
206
|
+
'searchstax-answer-show-more': answerData.showMoreButtonVisible
|
|
207
|
+
}"
|
|
208
|
+
>
|
|
209
|
+
<div class="searchstax-answer-title">Smart Answers</div>
|
|
210
|
+
<div
|
|
211
|
+
class="searchstax-answer-error"
|
|
212
|
+
v-if="answerData.shouldShowAnswerError"
|
|
213
|
+
v-html="answerData.answerErrorMessage"
|
|
214
|
+
></div>
|
|
215
|
+
<div class="searchstax-answer-description" v-html="answerData.fullAnswerFormatted"></div>
|
|
216
|
+
<div v-if="answerData.answerLoading" class="searchstax-answer-loading"></div>
|
|
217
|
+
</div>
|
|
218
|
+
<div
|
|
219
|
+
v-if="answerData.showMoreButtonVisible"
|
|
220
|
+
class="searchstax-answer-load-more-button-container"
|
|
221
|
+
>
|
|
222
|
+
<button class="searchstax-answer-load-more-button" @click="showMore">Read More</button>
|
|
269
223
|
</div>
|
|
224
|
+
</div>
|
|
225
|
+
<div class="searchstax-answer-footer">
|
|
226
|
+
<div id="feedbackWidgetContainer"></div>
|
|
227
|
+
<div class="searchstax-lightweight-widget-separator-inline"></div>
|
|
228
|
+
<p class="searchstax-disclaimer">Generative AI is Experimental</p>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
270
232
|
</template>
|
|
271
233
|
</SearchstaxAnswerWidget>
|
|
272
234
|
```
|
|
273
235
|
|
|
274
236
|
### Input Widget ###
|
|
275
237
|
|
|
276
|
-
|
|
238
|
+
SearchStax Site Search solution offers a Vue search-input widget to assist with your custom search page.
|
|
239
|
+
|
|
240
|
+
The SearchstaxInputWidget provides a search input box with autosuggest/autocomplete functionality.
|
|
241
|
+
|
|
242
|
+
**Usage**
|
|
277
243
|
```
|
|
278
244
|
<SearchstaxInputWidget
|
|
279
245
|
:afterAutosuggest="afterAutosuggest"
|
|
@@ -282,8 +248,26 @@ example of input widget initialization with minimum options
|
|
|
282
248
|
></SearchstaxInputWidget>
|
|
283
249
|
```
|
|
284
250
|
|
|
251
|
+
**Props**
|
|
252
|
+
|
|
253
|
+
- suggestAfterMinChars - default 3. Number of characters needed for autosuggest to start triggering
|
|
254
|
+
- beforeAutosuggest - callback function that gets called before firing autosuggest. autosuggestProps are being passed as a property and can be modified, if passed along further search will execute with modified properties, if null is returned then event gets canceled and search never fires.
|
|
255
|
+
- afterAutosuggest - callback function that gets called after autosuggest has values but before rendering. It needs to return same type of data but it can be modified.
|
|
256
|
+
- inputTemplate - template override. look at examples below
|
|
285
257
|
|
|
286
|
-
|
|
258
|
+
|
|
259
|
+
**inputWidgetTemplate**
|
|
260
|
+
|
|
261
|
+
The inputTemplate prop allows customizing the input UI.
|
|
262
|
+
|
|
263
|
+
It receives the following props:
|
|
264
|
+
|
|
265
|
+
- suggestions – Array of autosuggestion results
|
|
266
|
+
- onMouseLeave - Handler for mouse leave event
|
|
267
|
+
- onMouseOver - Handler for mouse over event
|
|
268
|
+
- onMouseClick - Handler for mouse click event
|
|
269
|
+
|
|
270
|
+
**example**
|
|
287
271
|
```
|
|
288
272
|
<SearchstaxInputWidget
|
|
289
273
|
:afterAutosuggest="afterAutosuggest"
|
|
@@ -292,72 +276,312 @@ example of input widget initialization with template override
|
|
|
292
276
|
>
|
|
293
277
|
<template #input="{ suggestions, onMouseLeave, onMouseOver, onMouseClick }">
|
|
294
278
|
<div class="searchstax-search-input-wrapper">
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
279
|
+
<input
|
|
280
|
+
type="text"
|
|
281
|
+
id="searchstax-search-input"
|
|
282
|
+
class="searchstax-search-input"
|
|
283
|
+
placeholder="SEARCH FOR..."
|
|
284
|
+
aria-label="search"
|
|
285
|
+
/>
|
|
286
|
+
<div
|
|
287
|
+
class="searchstax-autosuggest-container"
|
|
288
|
+
:class="{ hidden: suggestions.length === 0 }"
|
|
289
|
+
@mouseleave="onMouseLeave"
|
|
290
|
+
>
|
|
291
|
+
<div
|
|
292
|
+
class="searchstax-autosuggest-item"
|
|
293
|
+
v-for="suggestion in suggestions"
|
|
294
|
+
:key="suggestion.term"
|
|
295
|
+
>
|
|
296
|
+
<div
|
|
297
|
+
class="searchstax-autosuggest-item-term-container"
|
|
298
|
+
v-html="suggestion.term"
|
|
299
|
+
tabindex="0"
|
|
300
|
+
@mouseover="onMouseOver(suggestion)"
|
|
301
|
+
@click.stop="onMouseClick()"
|
|
302
|
+
></div>
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
</div>
|
|
306
|
+
<SearchstaxLocationWidget />
|
|
307
|
+
<button
|
|
308
|
+
class="searchstax-spinner-icon"
|
|
309
|
+
id="searchstax-search-input-action-button"
|
|
310
|
+
aria-label="search"
|
|
311
|
+
role="button"
|
|
312
|
+
></button>
|
|
325
313
|
</template>
|
|
326
314
|
</SearchstaxInputWidget>
|
|
327
315
|
```
|
|
328
|
-
|
|
329
316
|
### Location Widget ###
|
|
330
317
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
318
|
+
SearchStax Site Search solution offers a Vue search-location widget to assist with your custom search page.
|
|
319
|
+
|
|
320
|
+
The SearchstaxLocationWidget provides a location search input with location-based search functionality.
|
|
321
|
+
|
|
322
|
+
**Usage**
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
const config = {
|
|
326
|
+
appId: "APP_ID",
|
|
327
|
+
relatedSearchesAPIKey: "KEY"
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const locationWidgetConfig = {
|
|
331
|
+
locationDecode: (term: string): Promise<ISearchstaxLocation> => {
|
|
345
332
|
return new Promise((resolve) => {
|
|
346
|
-
// make a request to geocoding API to
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
333
|
+
// make a request to google geocoding API to retrieve lat, lon and address
|
|
334
|
+
|
|
335
|
+
const geocodingAPIKey = "GEOCODING_API_KEY";
|
|
336
|
+
const geocodingURL = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(
|
|
337
|
+
term
|
|
338
|
+
)}&key=${geocodingAPIKey}`;
|
|
339
|
+
fetch(geocodingURL)
|
|
340
|
+
.then((response) => response.json())
|
|
341
|
+
.then((data) => {
|
|
342
|
+
if (data.status === "OK" && data.results.length > 0) {
|
|
343
|
+
const result = data.results[0];
|
|
344
|
+
const location = {
|
|
345
|
+
lat: result.geometry.location.lat,
|
|
346
|
+
lon: result.geometry.location.lng,
|
|
347
|
+
address: result.formatted_address,
|
|
348
|
+
};
|
|
349
|
+
resolve(location);
|
|
350
|
+
} else {
|
|
351
|
+
resolve({
|
|
352
|
+
address: undefined,
|
|
353
|
+
lat: undefined,
|
|
354
|
+
lon: undefined,
|
|
355
|
+
error: true,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
})
|
|
359
|
+
.catch(() => {
|
|
360
|
+
resolve({
|
|
361
|
+
address: undefined,
|
|
362
|
+
lat: undefined,
|
|
363
|
+
lon: undefined,
|
|
364
|
+
error: true,
|
|
365
|
+
});
|
|
366
|
+
});
|
|
353
367
|
});
|
|
354
|
-
}
|
|
355
|
-
|
|
368
|
+
},
|
|
369
|
+
locationDecodeCoordinatesToAddress: (lat: string, lon: string): Promise<ISearchstaxLocation> => {
|
|
370
|
+
return new Promise((resolve) => {
|
|
371
|
+
fetch(
|
|
372
|
+
`https://geocoding-staging.searchstax.co/reverse?location=${lat},${lon}&components=country:US&app_id=${config.appId}`,
|
|
373
|
+
{
|
|
374
|
+
method: "GET",
|
|
375
|
+
headers: {
|
|
376
|
+
Authorization: `Token ${config.relatedSearchesAPIKey}`,
|
|
377
|
+
},
|
|
378
|
+
}
|
|
379
|
+
)
|
|
380
|
+
.then((response) => response.json())
|
|
381
|
+
.then((data) => {
|
|
382
|
+
if (data.status === "OK" && data.results.length > 0) {
|
|
383
|
+
const result = data.results[0];
|
|
384
|
+
resolve({
|
|
385
|
+
address: result.formatted_address,
|
|
386
|
+
lat: lat,
|
|
387
|
+
lon: lon,
|
|
388
|
+
error: false,
|
|
389
|
+
});
|
|
390
|
+
} else {
|
|
391
|
+
resolve({
|
|
392
|
+
address: undefined,
|
|
393
|
+
lat: lat,
|
|
394
|
+
lon: lon,
|
|
395
|
+
error: true,
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
})
|
|
399
|
+
.catch(() => {
|
|
400
|
+
resolve({
|
|
401
|
+
address: undefined,
|
|
402
|
+
lat: lat,
|
|
403
|
+
lon: lon,
|
|
404
|
+
error: true,
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
},
|
|
409
|
+
locationSearchEnabled: false,
|
|
410
|
+
locationValuesOverride: {
|
|
411
|
+
locationDistanceEnabled: true,
|
|
412
|
+
filterValues: ["any", "1000"],
|
|
413
|
+
filterUnit: "miles",
|
|
414
|
+
locationFilterDefaultValue: "any"
|
|
415
|
+
},
|
|
416
|
+
}
|
|
417
|
+
<SearchstaxLocationWidget :locationDecode="locationWidgetConfig.locationDecodeFunction" :locationDecodeCoordinatesToAddress="locationWidgetConfig.locationDecodeCoordinatesToAddress" :locationValuesOverride="locationWidgetConfig.locationValuesOverride" :locationSearchEnabled="locationWidgetConfig.locationSearchEnabled">
|
|
356
418
|
</SearchstaxLocationWidget>
|
|
357
419
|
```
|
|
358
|
-
|
|
420
|
+
|
|
421
|
+
**Props**
|
|
422
|
+
|
|
423
|
+
- locationDecode - callback function to override location decoding
|
|
424
|
+
- locationDecodeCoordinatesToAddress - callback function to override location decoding
|
|
425
|
+
|
|
426
|
+
**Template Override**
|
|
427
|
+
|
|
428
|
+
The searchLocationTemplate prop allows customizing the location input UI.
|
|
429
|
+
|
|
430
|
+
It receives the following props:
|
|
431
|
+
|
|
432
|
+
- locationData – data containing info on when to show certain elements
|
|
433
|
+
- inputValue – value of location input
|
|
434
|
+
- locationBlur - Handler for location input blur
|
|
435
|
+
- radiusChange - Handler for location radius change
|
|
436
|
+
- selectValue - Value of radius select
|
|
437
|
+
- inputChange - location input change handler
|
|
438
|
+
- locationError - boolean stating if location has error
|
|
439
|
+
- getCurrentLocation - Handler for getting current location from browser
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
**Example**
|
|
443
|
+
|
|
359
444
|
```
|
|
360
|
-
|
|
445
|
+
const config = {
|
|
446
|
+
appId: "APP_ID",
|
|
447
|
+
relatedSearchesAPIKey: "KEY"
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const locationWidgetConfig = {
|
|
451
|
+
locationDecode: (term: string): Promise<ISearchstaxLocation> => {
|
|
452
|
+
return new Promise((resolve) => {
|
|
453
|
+
// make a request to google geocoding API to retrieve lat, lon and address
|
|
454
|
+
|
|
455
|
+
const geocodingAPIKey = "GEOCODING_API_KEY";
|
|
456
|
+
const geocodingURL = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(
|
|
457
|
+
term
|
|
458
|
+
)}&key=${geocodingAPIKey}`;
|
|
459
|
+
fetch(geocodingURL)
|
|
460
|
+
.then((response) => response.json())
|
|
461
|
+
.then((data) => {
|
|
462
|
+
if (data.status === "OK" && data.results.length > 0) {
|
|
463
|
+
const result = data.results[0];
|
|
464
|
+
const location = {
|
|
465
|
+
lat: result.geometry.location.lat,
|
|
466
|
+
lon: result.geometry.location.lng,
|
|
467
|
+
address: result.formatted_address,
|
|
468
|
+
};
|
|
469
|
+
resolve(location);
|
|
470
|
+
} else {
|
|
471
|
+
resolve({
|
|
472
|
+
address: undefined,
|
|
473
|
+
lat: undefined,
|
|
474
|
+
lon: undefined,
|
|
475
|
+
error: true,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
})
|
|
479
|
+
.catch(() => {
|
|
480
|
+
resolve({
|
|
481
|
+
address: undefined,
|
|
482
|
+
lat: undefined,
|
|
483
|
+
lon: undefined,
|
|
484
|
+
error: true,
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
},
|
|
489
|
+
locationDecodeCoordinatesToAddress: (lat: string, lon: string): Promise<ISearchstaxLocation> => {
|
|
490
|
+
return new Promise((resolve) => {
|
|
491
|
+
fetch(
|
|
492
|
+
`https://geocoding-staging.searchstax.co/reverse?location=${lat},${lon}&components=country:US&app_id=${config.appId}`,
|
|
493
|
+
{
|
|
494
|
+
method: "GET",
|
|
495
|
+
headers: {
|
|
496
|
+
Authorization: `Token ${config.relatedSearchesAPIKey}`,
|
|
497
|
+
},
|
|
498
|
+
}
|
|
499
|
+
)
|
|
500
|
+
.then((response) => response.json())
|
|
501
|
+
.then((data) => {
|
|
502
|
+
if (data.status === "OK" && data.results.length > 0) {
|
|
503
|
+
const result = data.results[0];
|
|
504
|
+
resolve({
|
|
505
|
+
address: result.formatted_address,
|
|
506
|
+
lat: lat,
|
|
507
|
+
lon: lon,
|
|
508
|
+
error: false,
|
|
509
|
+
});
|
|
510
|
+
} else {
|
|
511
|
+
resolve({
|
|
512
|
+
address: undefined,
|
|
513
|
+
lat: lat,
|
|
514
|
+
lon: lon,
|
|
515
|
+
error: true,
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
})
|
|
519
|
+
.catch(() => {
|
|
520
|
+
resolve({
|
|
521
|
+
address: undefined,
|
|
522
|
+
lat: lat,
|
|
523
|
+
lon: lon,
|
|
524
|
+
error: true,
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
},
|
|
529
|
+
locationSearchEnabled: false,
|
|
530
|
+
locationValuesOverride: {
|
|
531
|
+
locationDistanceEnabled: true,
|
|
532
|
+
filterValues: ["any", "1000"],
|
|
533
|
+
filterUnit: "miles",
|
|
534
|
+
locationFilterDefaultValue: "any"
|
|
535
|
+
},
|
|
536
|
+
}
|
|
537
|
+
<div
|
|
538
|
+
class="searchstax-location-input-container"
|
|
539
|
+
data-test-id="searchstax-location-input-container"
|
|
540
|
+
>
|
|
541
|
+
<div class="searchstax-location-input-wrapper">
|
|
542
|
+
<span class="searchstax-location-input-label">NEAR</span>
|
|
543
|
+
<div class="searchstax-location-input-wrapper-inner">
|
|
544
|
+
<input
|
|
545
|
+
type="text"
|
|
546
|
+
id="searchstax-location-input"
|
|
547
|
+
class="searchstax-location-input"
|
|
548
|
+
:class="{ 'searchstax-input-location-error': locationError }"
|
|
549
|
+
placeholder="Zip, Postal Code or City..."
|
|
550
|
+
aria-label="Search Location Input"
|
|
551
|
+
data-test-id="searchstax-location-input"
|
|
552
|
+
@change="inputChange"
|
|
553
|
+
:value="inputValue"
|
|
554
|
+
@blur="locationBlur"
|
|
555
|
+
/>
|
|
556
|
+
<button @click="getCurrentLocation" class="searchstax-get-current-location-button">
|
|
557
|
+
Use my current location
|
|
558
|
+
</button>
|
|
559
|
+
</div>
|
|
560
|
+
<span
|
|
561
|
+
v-if="locationData.shouldShowLocationDistanceDropdown"
|
|
562
|
+
class="searchstax-location-input-label"
|
|
563
|
+
>WITHIN</span
|
|
564
|
+
>
|
|
565
|
+
<select
|
|
566
|
+
v-if="locationData.shouldShowLocationDistanceDropdown"
|
|
567
|
+
id="searchstax-location-radius-select"
|
|
568
|
+
class="searchstax-location-radius-select"
|
|
569
|
+
aria-label="Search Location Radius Select"
|
|
570
|
+
data-test-id="searchstax-location-radius-select"
|
|
571
|
+
@change="radiusChange"
|
|
572
|
+
:value="selectValue"
|
|
573
|
+
>
|
|
574
|
+
<option
|
|
575
|
+
v-for="value in locationData.locationSearchDistanceValues"
|
|
576
|
+
:value="value.value"
|
|
577
|
+
:key="value.value"
|
|
578
|
+
>
|
|
579
|
+
{{ value.label }}
|
|
580
|
+
</option>
|
|
581
|
+
</select>
|
|
582
|
+
</div>
|
|
583
|
+
</div>
|
|
584
|
+
<SearchstaxLocationWidget :locationDecode="locationWidgetConfig.locationDecode" :locationDecodeCoordinatesToAddress="locationWidgetConfig.locationDecodeCoordinatesToAddress" :locationValuesOverride="locationWidgetConfig.locationValuesOverride" :locationSearchEnabled="locationWidgetConfig.locationSearchEnabled">
|
|
361
585
|
<template
|
|
362
586
|
#location="{
|
|
363
587
|
locationData,
|
|
@@ -370,7 +594,7 @@ example of location widget initialization with template override
|
|
|
370
594
|
getCurrentLocation
|
|
371
595
|
}"
|
|
372
596
|
>
|
|
373
|
-
|
|
597
|
+
<div
|
|
374
598
|
class="searchstax-location-input-container"
|
|
375
599
|
data-test-id="searchstax-location-input-container"
|
|
376
600
|
>
|
|
@@ -420,135 +644,338 @@ example of location widget initialization with template override
|
|
|
420
644
|
</template>
|
|
421
645
|
</SearchstaxLocationWidget>
|
|
422
646
|
```
|
|
647
|
+
|
|
423
648
|
### Result Widget ###
|
|
424
649
|
|
|
425
|
-
|
|
650
|
+
The SearchStax Site Search solution offers a Vue results widget to assist with your custom search page.
|
|
651
|
+
|
|
652
|
+
The SearchstaxResultsWidget component displays the search results.
|
|
653
|
+
|
|
654
|
+
**Usage**
|
|
655
|
+
|
|
426
656
|
```
|
|
427
657
|
<SearchstaxResultWidget :afterLinkClick="afterLinkClick"></SearchstaxResultWidget>
|
|
428
658
|
```
|
|
429
659
|
|
|
430
|
-
|
|
660
|
+
**Result Template Override**
|
|
661
|
+
|
|
662
|
+
The resultsTemplate prop allows customizing the result UI.
|
|
663
|
+
|
|
664
|
+
It receives following props:
|
|
665
|
+
- searchResults - Array of result items
|
|
666
|
+
- resultClicked - Handler for result click events
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
**No Results Template Override**
|
|
670
|
+
|
|
671
|
+
The noResultTemplate prop allows customizing the result UI.
|
|
672
|
+
|
|
673
|
+
It receives following props:
|
|
674
|
+
|
|
675
|
+
- searchResults - Array of result items
|
|
676
|
+
- resultClicked - Handler for result click events
|
|
677
|
+
- searchTerm - Search input term
|
|
678
|
+
- metadata - Metadata object
|
|
679
|
+
- executeSearch - Handler for executing srearch
|
|
680
|
+
- store - Main store of app
|
|
681
|
+
|
|
682
|
+
**Example of default render method**
|
|
431
683
|
```
|
|
432
|
-
<SearchstaxResultWidget :afterLinkClick="afterLinkClick"
|
|
684
|
+
<SearchstaxResultWidget :afterLinkClick="afterLinkClick">
|
|
685
|
+
<template #results="{ searchResults, resultClicked }">
|
|
686
|
+
<div class="searchstax-search-results" v-if="searchResults && searchResults.length">
|
|
687
|
+
<a
|
|
688
|
+
:key="searchResult.uniqueId"
|
|
689
|
+
v-for="searchResult in searchResults"
|
|
690
|
+
:href="searchResult.url"
|
|
691
|
+
:data-searchstax-unique-result-id="searchResult.uniqueId"
|
|
692
|
+
@click="resultClicked(searchResult, $event)"
|
|
693
|
+
@keyup.enter="resultClicked(searchResult, $event)"
|
|
694
|
+
@keyup.space="resultClicked(searchResult, $event)"
|
|
695
|
+
class="searchstax-result-item-link searchstax-result-item-link-wrapping"
|
|
696
|
+
tabindex="0"
|
|
697
|
+
>
|
|
698
|
+
<div
|
|
699
|
+
class="searchstax-search-result"
|
|
700
|
+
:class="{
|
|
701
|
+
'has-thumbnail': searchResult.thumbnail,
|
|
702
|
+
promoted: searchResult.promoted
|
|
703
|
+
}"
|
|
704
|
+
>
|
|
705
|
+
<div v-if="searchResult.promoted" class="searchstax-search-result-promoted"></div>
|
|
706
|
+
<div
|
|
707
|
+
v-if="searchResult.ribbon"
|
|
708
|
+
v-html="searchResult.ribbon"
|
|
709
|
+
class="searchstax-search-result-ribbon"
|
|
710
|
+
></div>
|
|
711
|
+
<img
|
|
712
|
+
alt=""
|
|
713
|
+
v-if="searchResult.thumbnail"
|
|
714
|
+
:src="searchResult.thumbnail"
|
|
715
|
+
class="searchstax-thumbnail"
|
|
716
|
+
/>
|
|
717
|
+
<div class="searchstax-search-result-title-container">
|
|
718
|
+
<span class="searchstax-search-result-title" v-html="searchResult.title"></span>
|
|
719
|
+
</div>
|
|
720
|
+
<p
|
|
721
|
+
v-if="searchResult.paths"
|
|
722
|
+
v-html="searchResult.paths"
|
|
723
|
+
class="searchstax-search-result-common"
|
|
724
|
+
></p>
|
|
725
|
+
<p
|
|
726
|
+
v-if="searchResult.description"
|
|
727
|
+
v-html="searchResult.description"
|
|
728
|
+
class="searchstax-search-result-description searchstax-search-result-common"
|
|
729
|
+
></p>
|
|
730
|
+
<div :key="unmappedField.key" v-for="unmappedField in searchResult.unmappedFields">
|
|
731
|
+
<div
|
|
732
|
+
v-if="unmappedField.isImage && typeof unmappedField.value === 'string'"
|
|
733
|
+
class="searchstax-search-result-image-container"
|
|
734
|
+
>
|
|
735
|
+
<img alt="" :src="unmappedField.value" class="searchstax-result-image" />
|
|
736
|
+
</div>
|
|
737
|
+
<div v-else>
|
|
738
|
+
<p class="searchstax-search-result-common" v-html="unmappedField.value"></p>
|
|
739
|
+
</div>
|
|
740
|
+
</div>
|
|
741
|
+
</div>
|
|
742
|
+
</a>
|
|
743
|
+
</div>
|
|
744
|
+
</template>
|
|
745
|
+
<template #noResult="{ searchResults, resultClicked, searchTerm, metadata, executeSearch, store }">
|
|
746
|
+
<div
|
|
747
|
+
v-if="
|
|
748
|
+
searchResults &&
|
|
749
|
+
searchResults.length === 0 &&
|
|
750
|
+
searchTerm !== '' &&
|
|
751
|
+
searchTerm !== '*' &&
|
|
752
|
+
store.searchstax.dataLayer.parsedData.firstSearchHappened
|
|
753
|
+
"
|
|
754
|
+
>
|
|
755
|
+
<div class="searchstax-no-results">
|
|
756
|
+
Showing <strong>no results</strong> for <strong>"{{ searchTerm }}"</strong>
|
|
757
|
+
<br />
|
|
758
|
+
<span v-if="metadata?.spellingSuggestion"
|
|
759
|
+
>Did you mean
|
|
760
|
+
<a
|
|
761
|
+
href="#"
|
|
762
|
+
class="searchstax-suggestion-term"
|
|
763
|
+
@click="executeSearch(metadata?.spellingSuggestion, $event)"
|
|
764
|
+
>
|
|
765
|
+
{{ metadata?.spellingSuggestion }}</a
|
|
766
|
+
>?</span
|
|
767
|
+
>
|
|
768
|
+
</div>
|
|
769
|
+
<ul>
|
|
770
|
+
<li>
|
|
771
|
+
Try searching for search related terms or topics. We offer a wide variety of content to help
|
|
772
|
+
you get the information you need.
|
|
773
|
+
</li>
|
|
774
|
+
<li>Lost? Click on the ‘X” in the Search Box to reset your search.</li>
|
|
775
|
+
</ul>
|
|
776
|
+
</div>
|
|
777
|
+
</template>
|
|
778
|
+
</SearchstaxResultWidget>
|
|
433
779
|
```
|
|
434
780
|
|
|
435
|
-
|
|
781
|
+
**Example of infinite scroll and pagination render methods**
|
|
436
782
|
```
|
|
437
|
-
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
<SearchstaxResultWidget :afterLinkClick="afterLinkClick" :renderMethod="'infiniteScroll'">
|
|
438
786
|
<template #results="{ searchResults, resultClicked }">
|
|
787
|
+
<div class="searchstax-search-results" v-if="searchResults && searchResults.length">
|
|
788
|
+
<a
|
|
789
|
+
:key="searchResult.uniqueId"
|
|
790
|
+
v-for="searchResult in searchResults"
|
|
791
|
+
:href="searchResult.url"
|
|
792
|
+
:data-searchstax-unique-result-id="searchResult.uniqueId"
|
|
793
|
+
@click="resultClicked(searchResult, $event)"
|
|
794
|
+
@keyup.enter="resultClicked(searchResult, $event)"
|
|
795
|
+
@keyup.space="resultClicked(searchResult, $event)"
|
|
796
|
+
class="searchstax-result-item-link searchstax-result-item-link-wrapping"
|
|
797
|
+
tabindex="0"
|
|
798
|
+
>
|
|
799
|
+
<div
|
|
800
|
+
class="searchstax-search-result"
|
|
801
|
+
:class="{
|
|
802
|
+
'has-thumbnail': searchResult.thumbnail,
|
|
803
|
+
promoted: searchResult.promoted
|
|
804
|
+
}"
|
|
805
|
+
>
|
|
806
|
+
<div v-if="searchResult.promoted" class="searchstax-search-result-promoted"></div>
|
|
807
|
+
<div
|
|
808
|
+
v-if="searchResult.ribbon"
|
|
809
|
+
v-html="searchResult.ribbon"
|
|
810
|
+
class="searchstax-search-result-ribbon"
|
|
811
|
+
></div>
|
|
812
|
+
<img
|
|
813
|
+
alt=""
|
|
814
|
+
v-if="searchResult.thumbnail"
|
|
815
|
+
:src="searchResult.thumbnail"
|
|
816
|
+
class="searchstax-thumbnail"
|
|
817
|
+
/>
|
|
818
|
+
<div class="searchstax-search-result-title-container">
|
|
819
|
+
<span class="searchstax-search-result-title" v-html="searchResult.title"></span>
|
|
820
|
+
</div>
|
|
821
|
+
<p
|
|
822
|
+
v-if="searchResult.paths"
|
|
823
|
+
v-html="searchResult.paths"
|
|
824
|
+
class="searchstax-search-result-common"
|
|
825
|
+
></p>
|
|
826
|
+
<p
|
|
827
|
+
v-if="searchResult.description"
|
|
828
|
+
v-html="searchResult.description"
|
|
829
|
+
class="searchstax-search-result-description searchstax-search-result-common"
|
|
830
|
+
></p>
|
|
831
|
+
<div :key="unmappedField.key" v-for="unmappedField in searchResult.unmappedFields">
|
|
832
|
+
<div
|
|
833
|
+
v-if="unmappedField.isImage && typeof unmappedField.value === 'string'"
|
|
834
|
+
class="searchstax-search-result-image-container"
|
|
835
|
+
>
|
|
836
|
+
<img alt="" :src="unmappedField.value" class="searchstax-result-image" />
|
|
837
|
+
</div>
|
|
838
|
+
<div v-else>
|
|
839
|
+
<p class="searchstax-search-result-common" v-html="unmappedField.value"></p>
|
|
840
|
+
</div>
|
|
841
|
+
</div>
|
|
842
|
+
</div>
|
|
843
|
+
</a>
|
|
844
|
+
</div>
|
|
845
|
+
</template>
|
|
846
|
+
<template #noResult="{ searchResults, resultClicked, searchTerm, metadata, executeSearch, store }">
|
|
439
847
|
<div
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
<span class="searchstax-search-result-title">{{ searchResult.title }}</span>
|
|
471
|
-
</div>
|
|
472
|
-
<p
|
|
473
|
-
v-if="searchResult.paths"
|
|
474
|
-
class="searchstax-search-result-common"
|
|
475
|
-
> {{ searchResult.paths }} </p>
|
|
476
|
-
<p
|
|
477
|
-
v-if="searchResult.description"
|
|
478
|
-
class="searchstax-search-result-description searchstax-search-result-common"
|
|
479
|
-
> {{ searchResult.description }} </p>
|
|
480
|
-
<div
|
|
481
|
-
:key="unmappedField.key"
|
|
482
|
-
v-for="unmappedField in searchResult.unmappedFields"
|
|
483
|
-
>
|
|
484
|
-
<div
|
|
485
|
-
v-if="unmappedField.isImage && typeof unmappedField.value === 'string'"
|
|
486
|
-
class="searchstax-search-result-image-container"
|
|
487
|
-
>
|
|
488
|
-
<img
|
|
489
|
-
:src="unmappedField.value"
|
|
490
|
-
class="searchstax-result-image"
|
|
491
|
-
/>
|
|
492
|
-
</div>
|
|
493
|
-
<div v-else>
|
|
494
|
-
<p class="searchstax-search-result-common"> {{ unmappedField.value }} </p>
|
|
495
|
-
</div>
|
|
496
|
-
</div>
|
|
497
|
-
</div>
|
|
498
|
-
</div>
|
|
848
|
+
v-if="
|
|
849
|
+
searchResults &&
|
|
850
|
+
searchResults.length === 0 &&
|
|
851
|
+
searchTerm !== '' &&
|
|
852
|
+
searchTerm !== '*' &&
|
|
853
|
+
store.searchstax.dataLayer.parsedData.firstSearchHappened
|
|
854
|
+
"
|
|
855
|
+
>
|
|
856
|
+
<div class="searchstax-no-results">
|
|
857
|
+
Showing <strong>no results</strong> for <strong>"{{ searchTerm }}"</strong>
|
|
858
|
+
<br />
|
|
859
|
+
<span v-if="metadata?.spellingSuggestion"
|
|
860
|
+
>Did you mean
|
|
861
|
+
<a
|
|
862
|
+
href="#"
|
|
863
|
+
class="searchstax-suggestion-term"
|
|
864
|
+
@click="executeSearch(metadata?.spellingSuggestion, $event)"
|
|
865
|
+
>
|
|
866
|
+
{{ metadata?.spellingSuggestion }}</a
|
|
867
|
+
>?</span
|
|
868
|
+
>
|
|
869
|
+
</div>
|
|
870
|
+
<ul>
|
|
871
|
+
<li>
|
|
872
|
+
Try searching for search related terms or topics. We offer a wide variety of content to help
|
|
873
|
+
you get the information you need.
|
|
874
|
+
</li>
|
|
875
|
+
<li>Lost? Click on the ‘X” in the Search Box to reset your search.</li>
|
|
876
|
+
</ul>
|
|
877
|
+
</div>
|
|
499
878
|
</template>
|
|
500
879
|
</SearchstaxResultWidget>
|
|
880
|
+
|
|
501
881
|
```
|
|
502
882
|
|
|
503
883
|
### Pagination Widget ###
|
|
504
884
|
|
|
885
|
+
The SearchStax Site Search solution offers a Vue pagination widget to assist with you custom search page.
|
|
886
|
+
|
|
887
|
+
The SearchstaxPaginationWidget component displays pagination controls for search results.
|
|
888
|
+
|
|
889
|
+
**Usage**
|
|
505
890
|
|
|
506
|
-
example of pagination widget initialization with minimum options
|
|
507
891
|
```
|
|
508
892
|
<SearchstaxPaginationWidget></SearchstaxPaginationWidget>
|
|
509
893
|
```
|
|
510
894
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
>Next ></a>
|
|
533
|
-
</div>
|
|
534
|
-
</div>
|
|
535
|
-
</template>
|
|
536
|
-
```
|
|
537
|
-
example of pagination widget initialization with infinite scroll template override
|
|
895
|
+
**Main Template Override**
|
|
896
|
+
|
|
897
|
+
Main template for the pagination controls.
|
|
898
|
+
|
|
899
|
+
It receives following props:
|
|
900
|
+
|
|
901
|
+
- paginationData – Pagination info object
|
|
902
|
+
- previousPage – Handler for previous page click
|
|
903
|
+
- nextPage - – Handler for next page click
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
**Infinite Scroll Template Override**
|
|
907
|
+
|
|
908
|
+
Main template for the pagination controls in infinite scroll mode.
|
|
909
|
+
|
|
910
|
+
It receives following props:
|
|
911
|
+
- isLastPage - boolean, true if its last page
|
|
912
|
+
- results - results.length can be used if there are results
|
|
913
|
+
|
|
914
|
+
**Example**
|
|
915
|
+
|
|
538
916
|
```
|
|
539
|
-
<
|
|
540
|
-
<
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
917
|
+
<SearchstaxPaginationWidget>
|
|
918
|
+
<template #pagination="{ paginationData, previousPage, nextPage }">
|
|
919
|
+
<div class="searchstax-pagination-container" v-if="paginationData">
|
|
920
|
+
<div class="searchstax-pagination-content">
|
|
921
|
+
<a
|
|
922
|
+
class="searchstax-pagination-previous"
|
|
923
|
+
:class="paginationData.isFirstPage ? 'disabled' : ''"
|
|
924
|
+
:disabled="paginationData?.isFirstPage"
|
|
925
|
+
@click="previousPage"
|
|
926
|
+
@keyup.enter="previousPage"
|
|
927
|
+
@keyup.space="previousPage"
|
|
928
|
+
tabindex="0"
|
|
929
|
+
id="searchstax-pagination-previous"
|
|
930
|
+
>
|
|
931
|
+
< Previous
|
|
932
|
+
</a>
|
|
933
|
+
<div class="searchstax-pagination-details">
|
|
934
|
+
{{ paginationData?.startResultIndex }} - {{ paginationData?.endResultIndex }} of
|
|
935
|
+
{{ paginationData?.totalResults }}
|
|
936
|
+
</div>
|
|
937
|
+
<a
|
|
938
|
+
class="searchstax-pagination-next"
|
|
939
|
+
:class="paginationData.isLastPage ? 'disabled' : ''"
|
|
940
|
+
:disabled="paginationData?.isLastPage"
|
|
941
|
+
tabindex="0"
|
|
942
|
+
@click="nextPage"
|
|
943
|
+
@keyup.enter="nextPage"
|
|
944
|
+
@keyup.space="nextPage"
|
|
945
|
+
id="searchstax-pagination-next"
|
|
946
|
+
>Next ></a
|
|
947
|
+
>
|
|
948
|
+
</div>
|
|
949
|
+
</div>
|
|
950
|
+
</template>
|
|
951
|
+
</SearchstaxPaginationWidget>
|
|
952
|
+
// infinite scroll example
|
|
953
|
+
<SearchstaxPaginationWidget>
|
|
954
|
+
<template #infiniteScroll="{ nextPage }">
|
|
955
|
+
<div className="searchstax-pagination-container">
|
|
956
|
+
<a
|
|
957
|
+
class="searchstax-pagination-load-more"
|
|
958
|
+
tabindex="0"
|
|
959
|
+
@click="nextPage"
|
|
960
|
+
@keyup.enter="nextPage"
|
|
961
|
+
@keyup.space="nextPage"
|
|
962
|
+
>Load More</a
|
|
963
|
+
>
|
|
964
|
+
</div>
|
|
965
|
+
</template>
|
|
966
|
+
</SearchstaxPaginationWidget>
|
|
547
967
|
```
|
|
548
968
|
|
|
549
969
|
### Facets Widget ###
|
|
550
970
|
|
|
551
|
-
|
|
971
|
+
The SearchStax Site Search solution offers a Vue SearchstaxFacetsWidget component to display facets on your custom search page.
|
|
972
|
+
|
|
973
|
+
**Facet Selection and Order**
|
|
974
|
+
|
|
975
|
+
Facet lists are configured and ordered on the Site Search [Faceting Tab](https://www.searchstax.com/docs/searchstudio/faceting-tab/).
|
|
976
|
+
|
|
977
|
+
**Usage**
|
|
978
|
+
|
|
552
979
|
```
|
|
553
980
|
<SearchstaxFacetsWidget
|
|
554
981
|
:facetingType="'or'"
|
|
@@ -557,316 +984,428 @@ example of facets widget initialization with minimum options
|
|
|
557
984
|
></SearchstaxFacetsWidget>
|
|
558
985
|
```
|
|
559
986
|
|
|
987
|
+
**Props**
|
|
988
|
+
|
|
989
|
+
- facetingType: "and" | "or" | "showUnavailable" | "tabs"; // type that determines how facets will behave
|
|
990
|
+
- specificFacets?: string[]; // optional array of facet names that if provided will only render those facets
|
|
991
|
+
- itemsPerPageDesktop: number; // default expanded facets for desktop
|
|
992
|
+
- itemsPerPageMobile: number; // default expanded facets for mobile
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
**Main Template Desktop Override**
|
|
996
|
+
|
|
997
|
+
Main wrapper template for desktop facets display.
|
|
998
|
+
|
|
999
|
+
It receives following props:
|
|
1000
|
+
- facetsTemplateDataDesktop - Facets data object
|
|
1001
|
+
- isNotDeactivated - Check if facet group is active
|
|
1002
|
+
- toggleFacetGroup - Toggle facet group active state
|
|
1003
|
+
- isChecked - Check if facet value is selected
|
|
1004
|
+
- selectFacet - Handler for facet select
|
|
1005
|
+
- showMoreLessDesktop - Show more/less facets handler
|
|
1006
|
+
- facetContainers - Object of facet DOM containers
|
|
1007
|
+
- updateRefDesktop - Handler for keeping checkbox references
|
|
1008
|
+
|
|
560
1009
|
|
|
561
|
-
|
|
1010
|
+
**Main Template Mobile Override**
|
|
1011
|
+
|
|
1012
|
+
Main wrapper template for mobile facets display.
|
|
1013
|
+
|
|
1014
|
+
It receives following props:
|
|
1015
|
+
- facetsTemplateDataMobile - Facets data object
|
|
1016
|
+
- selectedFacetsCheckboxes - Selected facet values
|
|
1017
|
+
- isNotDeactivated - Check if facet group is active
|
|
1018
|
+
- toggleFacetGroup - Toggle facet group active state
|
|
1019
|
+
- isChecked - Check if facet value is selected
|
|
1020
|
+
- selectFacet - Handler for facet select
|
|
1021
|
+
- showMoreLessDesktop - Show more/less facets handler
|
|
1022
|
+
- facetContainers - Object of facet DOM containers
|
|
1023
|
+
- openOverlay - Handler to open mobile overlay
|
|
1024
|
+
- unselectFacet - Handler to unselect specific facet
|
|
1025
|
+
- unselectAll - Handler to unselect all facets
|
|
1026
|
+
- closeOverlay - Handler to close mobile overlay
|
|
1027
|
+
- updateRefMobile - Handler for keeping mobile checkbox references
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
**Example**
|
|
562
1031
|
```
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
1032
|
+
<SearchstaxFacetsWidget
|
|
1033
|
+
:facetingType="'or'"
|
|
1034
|
+
:itemsPerPageDesktop="3"
|
|
1035
|
+
:itemsPerPageMobile="99"
|
|
1036
|
+
>
|
|
1037
|
+
<template
|
|
1038
|
+
#desktopFacets="{ facetsTemplateDataDesktop, isNotDeactivated, toggleFacetGroup, isChecked, selectFacet, showMoreLessDesktop, facetContainers, updateRefDesktop }"
|
|
1039
|
+
>
|
|
1040
|
+
<div
|
|
1041
|
+
v-if="facetsTemplateDataDesktop?.hasResultsOrExternalPromotions"
|
|
1042
|
+
class="searchstax-facets-container-desktop"
|
|
1043
|
+
>
|
|
1044
|
+
<div
|
|
1045
|
+
v-for="facet in facetsTemplateDataDesktop.facets"
|
|
1046
|
+
:key="facet.name + 'desktop'"
|
|
1047
|
+
class="searchstax-facet-container"
|
|
1048
|
+
:class="{ active: isNotDeactivated(facet.name) }"
|
|
1049
|
+
>
|
|
1050
|
+
<div>
|
|
1051
|
+
<div class="searchstax-facet-title-container" @click="toggleFacetGroup(facet.name)">
|
|
1052
|
+
<div class="searchstax-facet-title">{{ facet.label }}</div>
|
|
1053
|
+
<div class="searchstax-facet-title-arrow active"></div>
|
|
1054
|
+
</div>
|
|
1055
|
+
<div class="searchstax-facet-values-container" aria-live="polite">
|
|
1056
|
+
<div
|
|
1057
|
+
v-for="(facetValue) in (facet.values as IFacetValueData[])"
|
|
1058
|
+
:key="facetValue.value + facetValue.parentName"
|
|
1059
|
+
class="searchstax-facet-value-container"
|
|
1060
|
+
:class="{ 'searchstax-facet-value-disabled': facetValue.disabled }"
|
|
1061
|
+
:ref="(el) => updateRefDesktop(el, facetValue)"
|
|
1062
|
+
>
|
|
1063
|
+
<div class="searchstax-facet-input">
|
|
1064
|
+
<input
|
|
1065
|
+
type="checkbox"
|
|
1066
|
+
class="searchstax-facet-input-checkbox"
|
|
1067
|
+
:checked="isChecked(facetValue)"
|
|
1068
|
+
:disabled="facetValue.disabled"
|
|
1069
|
+
:aria-label="facetValue.value + ' ' + facetValue.count"
|
|
1070
|
+
@click="selectFacet(facetValue.value + '-desktop', $event, facetValue, true)"
|
|
1071
|
+
/>
|
|
1072
|
+
</div>
|
|
1073
|
+
<div
|
|
1074
|
+
class="searchstax-facet-value-label"
|
|
1075
|
+
@click="selectFacet(facetValue.value + '-desktop', $event, facetValue, false)"
|
|
1076
|
+
>
|
|
1077
|
+
{{ facetValue.value }}
|
|
1078
|
+
</div>
|
|
1079
|
+
<div
|
|
1080
|
+
class="searchstax-facet-value-count"
|
|
1081
|
+
@click="selectFacet(facetValue.value + '-desktop', $event, facetValue, false)"
|
|
567
1082
|
>
|
|
568
|
-
|
|
569
|
-
|
|
1083
|
+
({{ facetValue.count }})
|
|
1084
|
+
</div>
|
|
1085
|
+
</div>
|
|
1086
|
+
<div class="searchstax-facet-show-more-container" v-if="facet.hasMoreFacets">
|
|
1087
|
+
<div
|
|
1088
|
+
class="searchstax-facet-show-more-container"
|
|
1089
|
+
@click="showMoreLessDesktop($event, facet)"
|
|
1090
|
+
@keyup.space="
|
|
1091
|
+
$event.preventDefault();
|
|
1092
|
+
showMoreLessDesktop($event, facet)
|
|
1093
|
+
"
|
|
1094
|
+
@keyup.enter="showMoreLessDesktop($event, facet)"
|
|
1095
|
+
tabindex="0"
|
|
1096
|
+
>
|
|
1097
|
+
<div
|
|
1098
|
+
v-if="facet.showingAllFacets"
|
|
1099
|
+
class="searchstax-facet-show-less-button searchstax-facet-show-button"
|
|
570
1100
|
>
|
|
1101
|
+
less
|
|
1102
|
+
</div>
|
|
1103
|
+
<div v-else class="searchstax-facet-show-more-button searchstax-facet-show-button">
|
|
1104
|
+
more
|
|
1105
|
+
</div>
|
|
1106
|
+
</div>
|
|
1107
|
+
</div>
|
|
1108
|
+
</div>
|
|
1109
|
+
</div>
|
|
1110
|
+
</div>
|
|
1111
|
+
</div>
|
|
1112
|
+
</template>
|
|
1113
|
+
<template
|
|
1114
|
+
#mobileFacets="{ facetsTemplateDataMobile, selectedFacetsCheckboxes, isNotDeactivated, toggleFacetGroup, isChecked, selectFacet, showMoreLessDesktop, facetContainers, openOverlay, unselectFacet, unselectAll, closeOverlay, updateRefMobile }"
|
|
1115
|
+
>
|
|
1116
|
+
<div
|
|
1117
|
+
class="searchstax-facets-container-mobile"
|
|
1118
|
+
v-if="facetsTemplateDataMobile?.hasResultsOrExternalPromotions"
|
|
1119
|
+
>
|
|
1120
|
+
<div class="searchstax-facets-pills-container">
|
|
1121
|
+
<div class="searchstax-facets-pill searchstax-facets-pill-filter-by" @click="openOverlay">
|
|
1122
|
+
<div class="searchstax-facets-pill-label">Filter By</div>
|
|
1123
|
+
</div>
|
|
1124
|
+
<div class="searchstax-facets-pills-selected">
|
|
1125
|
+
<div
|
|
1126
|
+
class="searchstax-facets-pill searchstax-facets-pill-facets"
|
|
1127
|
+
v-for="facet in selectedFacetsCheckboxes"
|
|
1128
|
+
:key="facet.value"
|
|
1129
|
+
@click="unselectFacet(facet)"
|
|
1130
|
+
>
|
|
1131
|
+
<div class="searchstax-facets-pill-label">{{ facet.value }} ({{ facet.count }})</div>
|
|
1132
|
+
<div class="searchstax-facets-pill-icon-close"></div>
|
|
1133
|
+
</div>
|
|
1134
|
+
</div>
|
|
1135
|
+
<div
|
|
1136
|
+
class="searchstax-facets-pill searchstax-clear-filters searchstax-facets-pill-clear-all"
|
|
1137
|
+
v-if="selectedFacetsCheckboxes.length"
|
|
1138
|
+
@click="unselectAll"
|
|
1139
|
+
>
|
|
1140
|
+
<div class="searchstax-facets-pill-label">Clear Filters</div>
|
|
1141
|
+
</div>
|
|
1142
|
+
</div>
|
|
1143
|
+
<div
|
|
1144
|
+
class="searchstax-facets-mobile-overlay"
|
|
1145
|
+
:class="{ 'searchstax-show': (facetsTemplateDataMobile as any)?.overlayOpened }"
|
|
1146
|
+
>
|
|
1147
|
+
<div class="searchstax-facets-mobile-overlay-header">
|
|
1148
|
+
<div class="searchstax-facets-mobile-overlay-header-title">Filter By</div>
|
|
1149
|
+
<div class="searchstax-search-close" @click="closeOverlay"></div>
|
|
1150
|
+
</div>
|
|
1151
|
+
<div class="searchstax-facets-container-mobile">
|
|
1152
|
+
<div
|
|
1153
|
+
v-for="facet in facetsTemplateDataMobile?.facets"
|
|
1154
|
+
:key="facet.name + 'mobile'"
|
|
1155
|
+
class="searchstax-facet-container"
|
|
1156
|
+
:class="{ active: isNotDeactivated(facet.name) }"
|
|
1157
|
+
>
|
|
1158
|
+
<div>
|
|
1159
|
+
<div class="searchstax-facet-title-container" @click="toggleFacetGroup(facet.name)">
|
|
1160
|
+
<div class="searchstax-facet-title">{{ facet.label }}</div>
|
|
1161
|
+
<div class="searchstax-facet-title-arrow active"></div>
|
|
1162
|
+
</div>
|
|
1163
|
+
<div class="searchstax-facet-values-container" aria-live="polite">
|
|
1164
|
+
<div
|
|
1165
|
+
v-for="(facetValue) in facet.values as IFacetValueData[]"
|
|
1166
|
+
:key="facetValue.value + facetValue.parentName"
|
|
1167
|
+
class="searchstax-facet-value-container"
|
|
1168
|
+
:class="{ 'searchstax-facet-value-disabled': facetValue.disabled }"
|
|
1169
|
+
:ref="
|
|
1170
|
+
(el) => {
|
|
1171
|
+
updateRefMobile(el, facetValue)
|
|
1172
|
+
}
|
|
1173
|
+
"
|
|
1174
|
+
>
|
|
1175
|
+
<div class="searchstax-facet-input">
|
|
1176
|
+
<input
|
|
1177
|
+
type="checkbox"
|
|
1178
|
+
class="searchstax-facet-input-checkbox"
|
|
1179
|
+
:checked="isChecked(facetValue)"
|
|
1180
|
+
:disabled="facetValue.disabled"
|
|
1181
|
+
:aria-label="facetValue.value + ' ' + facetValue.count"
|
|
1182
|
+
@click="selectFacet(facetValue.value + '-mobile', $event, facetValue, true)"
|
|
1183
|
+
/>
|
|
1184
|
+
</div>
|
|
571
1185
|
<div
|
|
572
|
-
|
|
573
|
-
|
|
1186
|
+
class="searchstax-facet-value-label"
|
|
1187
|
+
@click="selectFacet(facetValue.value + '-mobile', $event, facetValue, false)"
|
|
574
1188
|
>
|
|
575
|
-
|
|
576
|
-
v-for="facet in facetsTemplateDataDesktop.facets"
|
|
577
|
-
:key="facet"
|
|
578
|
-
class="searchstax-facet-container"
|
|
579
|
-
:class="{ 'active': isNotDeactivated(facet.name) }"
|
|
580
|
-
>
|
|
581
|
-
<div>
|
|
582
|
-
<div
|
|
583
|
-
class="searchstax-facet-title-container"
|
|
584
|
-
@click="toggleFacetGroup(facet.name)"
|
|
585
|
-
>
|
|
586
|
-
<div class="searchstax-facet-title"> {{ facet.label }} </div>
|
|
587
|
-
<div class="searchstax-facet-title-arrow active"></div>
|
|
588
|
-
</div>
|
|
589
|
-
<div class="searchstax-facet-values-container">
|
|
590
|
-
<div
|
|
591
|
-
v-for="(facetValue, key) in facet.values"
|
|
592
|
-
:key="facetValue.value + facetValue.parentName"
|
|
593
|
-
class="searchstax-facet-value-container"
|
|
594
|
-
:class="{ 'searchstax-facet-value-disabled': facetValue.disabled }"
|
|
595
|
-
:ref="el => { facetContainers[key + facet.name] = el }"
|
|
596
|
-
>
|
|
597
|
-
<div class="searchstax-facet-input">
|
|
598
|
-
<input
|
|
599
|
-
type="checkbox"
|
|
600
|
-
class="searchstax-facet-input-checkbox"
|
|
601
|
-
:checked="isChecked(facetValue)"
|
|
602
|
-
:disabled="facetValue.disabled"
|
|
603
|
-
@click="selectFacet(key + facet.name, $event, facetValue, true)"
|
|
604
|
-
/>
|
|
605
|
-
</div>
|
|
606
|
-
<div
|
|
607
|
-
class="searchstax-facet-value-label"
|
|
608
|
-
@click="selectFacet(key + facet.name, $event, facetValue, false)"
|
|
609
|
-
>{{ facetValue.value }}</div>
|
|
610
|
-
<div
|
|
611
|
-
class="searchstax-facet-value-count"
|
|
612
|
-
@click="selectFacet(key + facet.name, $event, facetValue, false)"
|
|
613
|
-
>({{ facetValue.count }})</div>
|
|
614
|
-
</div>
|
|
615
|
-
<div
|
|
616
|
-
class="searchstax-facet-show-more-container"
|
|
617
|
-
v-if="facet.hasMoreFacets"
|
|
618
|
-
>
|
|
619
|
-
<div
|
|
620
|
-
class="searchstax-facet-show-more-container"
|
|
621
|
-
@click="showMoreLessDesktop($event, facet)"
|
|
622
|
-
>
|
|
623
|
-
<div
|
|
624
|
-
v-if="facet.showingAllFacets"
|
|
625
|
-
class="searchstax-facet-show-less-button searchstax-facet-show-button"
|
|
626
|
-
>less</div>
|
|
627
|
-
<div
|
|
628
|
-
v-else
|
|
629
|
-
class="searchstax-facet-show-more-button searchstax-facet-show-button"
|
|
630
|
-
>more</div>
|
|
631
|
-
</div>
|
|
632
|
-
</div>
|
|
633
|
-
</div>
|
|
634
|
-
</div>
|
|
635
|
-
</div>
|
|
1189
|
+
{{ facetValue.value }}
|
|
636
1190
|
</div>
|
|
637
|
-
</template>
|
|
638
|
-
<template
|
|
639
|
-
#mobileFacets="{ facetsTemplateDataMobile, selectedFacetsCheckboxes, isNotDeactivated, toggleFacetGroup, isChecked, selectFacet, showMoreLessDesktop, facetContainers, openOverlay, unselectFacet, unselectAll, closeOverlay }"
|
|
640
|
-
>
|
|
641
1191
|
<div
|
|
642
|
-
class="searchstax-
|
|
643
|
-
|
|
1192
|
+
class="searchstax-facet-value-count"
|
|
1193
|
+
@click="selectFacet(facetValue.value + '-mobile', $event, facetValue, false)"
|
|
644
1194
|
>
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
</div>
|
|
662
|
-
</div>
|
|
663
|
-
<div
|
|
664
|
-
class="searchstax-facets-pill searchstax-clear-filters searchstax-facets-pill-clear-all"
|
|
665
|
-
v-if="selectedFacetsCheckboxes.length"
|
|
666
|
-
@click="unselectAll"
|
|
667
|
-
>
|
|
668
|
-
<div class="searchstax-facets-pill-label">Clear Filters</div>
|
|
669
|
-
</div>
|
|
1195
|
+
({{ facetValue.count }})
|
|
1196
|
+
</div>
|
|
1197
|
+
</div>
|
|
1198
|
+
<div class="searchstax-facet-show-more-container" v-if="facet.hasMoreFacets">
|
|
1199
|
+
<div
|
|
1200
|
+
class="searchstax-facet-show-more-container"
|
|
1201
|
+
@click="showMoreLessMobile($event, facet)"
|
|
1202
|
+
@keyup.space="showMoreLessMobile($event, facet)"
|
|
1203
|
+
@keyup.enter="showMoreLessMobile($event, facet)"
|
|
1204
|
+
tabindex="0"
|
|
1205
|
+
>
|
|
1206
|
+
<div
|
|
1207
|
+
v-if="facet.showingAllFacets"
|
|
1208
|
+
class="searchstax-facet-show-less-button searchstax-facet-show-button"
|
|
1209
|
+
>
|
|
1210
|
+
less
|
|
670
1211
|
</div>
|
|
671
1212
|
<div
|
|
672
|
-
|
|
673
|
-
|
|
1213
|
+
v-else
|
|
1214
|
+
class="searchstax-facet-show-more-button searchstax-facet-show-button"
|
|
674
1215
|
>
|
|
675
|
-
|
|
676
|
-
<div class="searchstax-facets-mobile-overlay-header-title">Filter By</div>
|
|
677
|
-
<div
|
|
678
|
-
class="searchstax-search-close"
|
|
679
|
-
@click="closeOverlay"
|
|
680
|
-
></div>
|
|
681
|
-
</div>
|
|
682
|
-
<div class="searchstax-facets-container-mobile">
|
|
683
|
-
<div
|
|
684
|
-
v-for="facet in facetsTemplateDataMobile?.facets"
|
|
685
|
-
:key="facet"
|
|
686
|
-
class="searchstax-facet-container"
|
|
687
|
-
:class="{ 'active': isNotDeactivated(facet.name) }"
|
|
688
|
-
>
|
|
689
|
-
<div>
|
|
690
|
-
<div
|
|
691
|
-
class="searchstax-facet-title-container"
|
|
692
|
-
@click="toggleFacetGroup(facet.name)"
|
|
693
|
-
>
|
|
694
|
-
<div class="searchstax-facet-title"> {{ facet.label }} </div>
|
|
695
|
-
<div class="searchstax-facet-title-arrow active"></div>
|
|
696
|
-
</div>
|
|
697
|
-
<div class="searchstax-facet-values-container">
|
|
698
|
-
<div
|
|
699
|
-
v-for="(facetValue, key) in facet.values"
|
|
700
|
-
:key="facetValue.value + facetValue.parentName"
|
|
701
|
-
class="searchstax-facet-value-container"
|
|
702
|
-
:class="{ 'searchstax-facet-value-disabled': facetValue.disabled }"
|
|
703
|
-
:ref="el => { facetContainers[key + facet.name] = el }"
|
|
704
|
-
>
|
|
705
|
-
<div class="searchstax-facet-input">
|
|
706
|
-
<input
|
|
707
|
-
type="checkbox"
|
|
708
|
-
class="searchstax-facet-input-checkbox"
|
|
709
|
-
:checked="isChecked(facetValue)"
|
|
710
|
-
:disabled="facetValue.disabled"
|
|
711
|
-
@click="selectFacet(key + facet.name, $event, facetValue, true)"
|
|
712
|
-
/>
|
|
713
|
-
</div>
|
|
714
|
-
<div
|
|
715
|
-
class="searchstax-facet-value-label"
|
|
716
|
-
@click="selectFacet(key + facet.name, $event, facetValue, false)"
|
|
717
|
-
>{{ facetValue.value }}</div>
|
|
718
|
-
<div
|
|
719
|
-
class="searchstax-facet-value-count"
|
|
720
|
-
@click="selectFacet(key + facet.name, $event, facetValue, false)"
|
|
721
|
-
>({{ facetValue.count }})</div>
|
|
722
|
-
</div>
|
|
723
|
-
<div
|
|
724
|
-
class="searchstax-facet-show-more-container"
|
|
725
|
-
v-if="facet.hasMoreFacets"
|
|
726
|
-
>
|
|
727
|
-
<div
|
|
728
|
-
class="searchstax-facet-show-more-container"
|
|
729
|
-
@click="showMoreLessDesktop($event, facet)"
|
|
730
|
-
>
|
|
731
|
-
<div
|
|
732
|
-
v-if="facet.showingAllFacets"
|
|
733
|
-
class="searchstax-facet-show-less-button searchstax-facet-show-button"
|
|
734
|
-
>less</div>
|
|
735
|
-
<div
|
|
736
|
-
v-else
|
|
737
|
-
class="searchstax-facet-show-more-button searchstax-facet-show-button"
|
|
738
|
-
>more</div>
|
|
739
|
-
</div>
|
|
740
|
-
</div>
|
|
741
|
-
</div>
|
|
742
|
-
</div>
|
|
743
|
-
</div>
|
|
744
|
-
</div>
|
|
745
|
-
<button
|
|
746
|
-
class="searchstax-facets-mobile-overlay-done"
|
|
747
|
-
@click="closeOverlay"
|
|
748
|
-
>Done</button>
|
|
1216
|
+
more
|
|
749
1217
|
</div>
|
|
750
1218
|
</div>
|
|
751
|
-
</
|
|
752
|
-
</
|
|
1219
|
+
</div>
|
|
1220
|
+
</div>
|
|
1221
|
+
</div>
|
|
1222
|
+
</div>
|
|
1223
|
+
</div>
|
|
1224
|
+
<button class="searchstax-facets-mobile-overlay-done" @click="closeOverlay">Done</button>
|
|
1225
|
+
</div>
|
|
1226
|
+
</div>
|
|
1227
|
+
</template>
|
|
1228
|
+
</SearchstaxFacetsWidget>
|
|
753
1229
|
```
|
|
754
1230
|
|
|
755
1231
|
### SearchFeedback Widget ###
|
|
756
1232
|
|
|
757
|
-
|
|
1233
|
+
The SearchStax Site Search solution provides a search feedback widget to support your Vue search pages.
|
|
1234
|
+
|
|
1235
|
+
The SearchstaxSearchFeedbackWidget displays search feedback and stats.
|
|
1236
|
+
|
|
1237
|
+
**Usage**
|
|
1238
|
+
|
|
758
1239
|
```
|
|
759
1240
|
<SearchstaxSearchFeedbackWidget></SearchstaxSearchFeedbackWidget>
|
|
760
1241
|
```
|
|
761
1242
|
|
|
1243
|
+
**Main Template Override**
|
|
1244
|
+
|
|
1245
|
+
Main template for the search feedback message.
|
|
762
1246
|
|
|
763
|
-
|
|
1247
|
+
It receives following props:
|
|
1248
|
+
- searchFeedbackData - Feedback data object
|
|
1249
|
+
- onOriginalQueryClick - Handler for clicking on original query suggestion
|
|
1250
|
+
|
|
1251
|
+
**Example**
|
|
764
1252
|
```
|
|
765
1253
|
<SearchstaxSearchFeedbackWidget>
|
|
766
1254
|
<template #searchFeedback="{ searchFeedbackData, onOriginalQueryClick }">
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1255
|
+
<h2
|
|
1256
|
+
class="searchstax-feedback-container"
|
|
1257
|
+
v-if="
|
|
1258
|
+
searchFeedbackData && searchFeedbackData?.searchExecuted && searchFeedbackData?.totalResults
|
|
1259
|
+
"
|
|
1260
|
+
>
|
|
1261
|
+
Showing
|
|
1262
|
+
<b>{{ searchFeedbackData.startResultIndex }} - {{ searchFeedbackData.endResultIndex }}</b> of
|
|
1263
|
+
<b>{{ searchFeedbackData.totalResults }}</b> results
|
|
1264
|
+
<span v-if="searchFeedbackData.searchTerm"
|
|
1265
|
+
>for "<b>{{ searchFeedbackData.searchTerm }}</b
|
|
1266
|
+
>"
|
|
1267
|
+
</span>
|
|
1268
|
+
<div class="searchstax-feedback-container-suggested">
|
|
1269
|
+
<div v-if="searchFeedbackData.autoCorrectedQuery">
|
|
1270
|
+
Search instead for
|
|
1271
|
+
<a
|
|
1272
|
+
href="#"
|
|
1273
|
+
@click.prevent="onOriginalQueryClick($event)"
|
|
1274
|
+
class="searchstax-feedback-original-query"
|
|
1275
|
+
:aria-label="'Search instead for ' + searchFeedbackData.originalQuery"
|
|
1276
|
+
>{{ searchFeedbackData.originalQuery }}</a
|
|
1277
|
+
>
|
|
1278
|
+
</div>
|
|
1279
|
+
</div>
|
|
1280
|
+
</h2>
|
|
782
1281
|
</template>
|
|
783
1282
|
</SearchstaxSearchFeedbackWidget>
|
|
784
1283
|
```
|
|
785
1284
|
|
|
786
|
-
|
|
1285
|
+
### RelatedSearches widget ###
|
|
787
1286
|
|
|
1287
|
+
The SearchStax Site Search solution offers a Vue widget for displaying related searches.
|
|
788
1288
|
|
|
1289
|
+
The SearchstaxRelatedSearchesWidget for Vue component displays related searches.
|
|
789
1290
|
|
|
790
|
-
|
|
1291
|
+
**Usage**
|
|
791
1292
|
```
|
|
792
|
-
<SearchstaxRelatedSearchesWidget
|
|
1293
|
+
<SearchstaxRelatedSearchesWidget
|
|
793
1294
|
:relatedSearchesURL="config.relatedSearchesURL"
|
|
794
1295
|
:relatedSearchesAPIKey="config.relatedSearchesAPIKey"
|
|
795
1296
|
></SearchstaxRelatedSearchesWidget>
|
|
796
1297
|
```
|
|
797
1298
|
|
|
1299
|
+
**Props**
|
|
1300
|
+
|
|
1301
|
+
- relatedSearchesURL: API URL for fetching related searches
|
|
1302
|
+
- relatedSearchesAPIKey?: API key for related searches API
|
|
1303
|
+
|
|
1304
|
+
**Main Template Override**
|
|
1305
|
+
|
|
1306
|
+
Main template for related searches.
|
|
1307
|
+
|
|
1308
|
+
It receives following props:
|
|
1309
|
+
|
|
1310
|
+
- relatedData - Related searches data object
|
|
1311
|
+
- executeSearch - Handler to run new search from related term
|
|
1312
|
+
|
|
1313
|
+
**Example**
|
|
798
1314
|
|
|
799
|
-
example of search feedback widget initialization with template overrides
|
|
800
1315
|
```
|
|
801
1316
|
<SearchstaxRelatedSearchesWidget
|
|
802
1317
|
:relatedSearchesURL="config.relatedSearchesURL"
|
|
803
1318
|
:relatedSearchesAPIKey="config.relatedSearchesAPIKey"
|
|
804
1319
|
>
|
|
805
1320
|
<template #related="{ relatedData, executeSearch }">
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
1321
|
+
<div
|
|
1322
|
+
class="searchstax-related-searches-container"
|
|
1323
|
+
id="searchstax-related-searches-container"
|
|
1324
|
+
v-if="relatedData && relatedData?.searchExecuted && relatedData?.hasRelatedSearches"
|
|
1325
|
+
>
|
|
1326
|
+
Related searches: <span id="searchstax-related-searches"></span>
|
|
1327
|
+
<span class="searchstax-related-search" v-if="relatedData.relatedSearches">
|
|
1328
|
+
<span
|
|
1329
|
+
v-for="related in relatedData.relatedSearches"
|
|
1330
|
+
:key="related.related_search"
|
|
1331
|
+
@click="executeSearch(related)"
|
|
1332
|
+
@keyup.enter="executeSearch(related)"
|
|
1333
|
+
@keyup.space="executeSearch(related)"
|
|
1334
|
+
tabindex="0"
|
|
1335
|
+
class="searchstax-related-search searchstax-related-search-item"
|
|
1336
|
+
:aria-label="'Related search: ' + related.related_search"
|
|
1337
|
+
>
|
|
1338
|
+
{{ related.related_search }}<span v-if="!related.last">,</span>
|
|
1339
|
+
</span>
|
|
1340
|
+
</span>
|
|
1341
|
+
</div>
|
|
824
1342
|
</template>
|
|
825
1343
|
</SearchstaxRelatedSearchesWidget>
|
|
826
1344
|
```
|
|
827
1345
|
|
|
828
1346
|
### ExternalPromotions widget ###
|
|
829
1347
|
|
|
830
|
-
|
|
1348
|
+
The SearchStax Site Search solution offers a Vue external-promotions widget for your custom search page.
|
|
1349
|
+
|
|
1350
|
+
The SearchstaxExternalPromotionsWidget component displays external promotions fetched from the API.
|
|
1351
|
+
|
|
1352
|
+
**Usage**
|
|
1353
|
+
|
|
831
1354
|
```
|
|
832
1355
|
<SearchstaxExternalPromotionsWidget></SearchstaxExternalPromotionsWidget>
|
|
833
1356
|
```
|
|
834
1357
|
|
|
1358
|
+
**Main Template Override**
|
|
1359
|
+
|
|
1360
|
+
Main template for external promotions.
|
|
1361
|
+
|
|
1362
|
+
It receives following props:
|
|
1363
|
+
|
|
1364
|
+
- externalPromotionsData – External promotions data object
|
|
1365
|
+
- trackClick – Handler for tracking link clicks
|
|
835
1366
|
|
|
836
|
-
|
|
1367
|
+
**Example**
|
|
837
1368
|
```
|
|
838
1369
|
<SearchstaxExternalPromotionsWidget>
|
|
839
1370
|
<template #externalPromotions="{ externalPromotionsData, trackClick }">
|
|
840
1371
|
<div
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1372
|
+
class="searchstax-external-promotions-container"
|
|
1373
|
+
id="searchstax-external-promotions-container"
|
|
1374
|
+
v-if="
|
|
1375
|
+
externalPromotionsData &&
|
|
1376
|
+
externalPromotionsData?.searchExecuted &&
|
|
1377
|
+
externalPromotionsData?.hasExternalPromotions
|
|
1378
|
+
"
|
|
1379
|
+
>
|
|
1380
|
+
<div
|
|
1381
|
+
class="searchstax-external-promotion searchstax-search-result"
|
|
1382
|
+
v-for="externalPromotion in externalPromotionsData.externalPromotions"
|
|
1383
|
+
:key="externalPromotion.id"
|
|
1384
|
+
>
|
|
1385
|
+
<div class="icon-elevated"></div>
|
|
1386
|
+
<a
|
|
1387
|
+
v-if="externalPromotion.url"
|
|
1388
|
+
href="{{externalPromotion.url}}"
|
|
1389
|
+
@click="trackClick(externalPromotion, $event)"
|
|
1390
|
+
class="searchstax-result-item-link"
|
|
1391
|
+
></a>
|
|
1392
|
+
<div class="searchstax-search-result-title-container">
|
|
1393
|
+
<span class="searchstax-search-result-title">{{ externalPromotion.name }}</span>
|
|
1394
|
+
</div>
|
|
1395
|
+
<p
|
|
1396
|
+
v-if="externalPromotion.description"
|
|
1397
|
+
class="searchstax-search-result-description searchstax-search-result-common"
|
|
1398
|
+
>
|
|
1399
|
+
{{ externalPromotion.description }}
|
|
1400
|
+
</p>
|
|
1401
|
+
<p
|
|
1402
|
+
v-if="externalPromotion.url"
|
|
1403
|
+
class="searchstax-search-result-description searchstax-search-result-common"
|
|
1404
|
+
>
|
|
1405
|
+
{{ externalPromotion.url }}
|
|
1406
|
+
</p>
|
|
1407
|
+
</div>
|
|
1408
|
+
</div>
|
|
870
1409
|
</template>
|
|
871
1410
|
</SearchstaxExternalPromotionsWidget>
|
|
872
1411
|
```
|
|
@@ -874,42 +1413,58 @@ example of search feedback widget initialization with template overrides
|
|
|
874
1413
|
|
|
875
1414
|
### Sorting Widget ###
|
|
876
1415
|
|
|
877
|
-
|
|
1416
|
+
The SearchStax Site Search solution offers a Vue sorting widget for your custom search page.
|
|
1417
|
+
|
|
1418
|
+
The SearchstaxSortingWidget component displays sorting options for search results.
|
|
1419
|
+
|
|
1420
|
+
**Usage**
|
|
1421
|
+
|
|
878
1422
|
```
|
|
879
1423
|
<SearchstaxSortingWidget></SearchstaxSortingWidget>
|
|
880
1424
|
```
|
|
881
1425
|
|
|
1426
|
+
**Main Template Override**
|
|
1427
|
+
|
|
1428
|
+
Main template for sorting widget.
|
|
1429
|
+
|
|
1430
|
+
It receives following props:
|
|
1431
|
+
|
|
1432
|
+
- sortingData – Sorting data object
|
|
1433
|
+
- orderChange – Handler for sorting change
|
|
1434
|
+
- selectedSorting – Current selected sorting
|
|
1435
|
+
|
|
1436
|
+
**Example**
|
|
882
1437
|
|
|
883
|
-
example of sorting widget initialization with template override
|
|
884
1438
|
```
|
|
885
1439
|
<SearchstaxSortingWidget>
|
|
886
1440
|
<template #sorting="{ sortingData, orderChange, selectedSorting }">
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1441
|
+
<div
|
|
1442
|
+
class="searchstax-sorting-container"
|
|
1443
|
+
v-if="sortingData && sortingData?.searchExecuted && sortingData?.hasResultsOrExternalPromotions"
|
|
1444
|
+
>
|
|
1445
|
+
<label class="searchstax-sorting-label" for="searchstax-search-order-select">Sort By</label>
|
|
1446
|
+
<select
|
|
1447
|
+
id="searchstax-search-order-select"
|
|
1448
|
+
class="searchstax-search-order-select"
|
|
1449
|
+
:value="selectedSorting"
|
|
1450
|
+
@change="orderChange($event)"
|
|
1451
|
+
>
|
|
1452
|
+
<option
|
|
1453
|
+
v-for="sortOption in sortingData.sortOptions"
|
|
1454
|
+
:key="sortOption.key"
|
|
1455
|
+
:value="sortOption.key"
|
|
1456
|
+
>
|
|
1457
|
+
{{ sortOption.value }}
|
|
1458
|
+
</option>
|
|
1459
|
+
</select>
|
|
1460
|
+
</div>
|
|
906
1461
|
</template>
|
|
907
1462
|
</SearchstaxSortingWidget>
|
|
908
1463
|
```
|
|
909
1464
|
|
|
910
1465
|
|
|
911
1466
|
## Template overrides
|
|
912
|
-
Templates use vue
|
|
1467
|
+
Templates use vue templating.
|
|
913
1468
|
|
|
914
1469
|
## STYLING
|
|
915
1470
|
|
|
@@ -921,4 +1476,4 @@ css can be taken from
|
|
|
921
1476
|
|
|
922
1477
|
```
|
|
923
1478
|
./../node_modules/@searchstax-inc/searchstudio-ux-js/dist/styles/mainTheme.css
|
|
924
|
-
```
|
|
1479
|
+
```
|