@searchspring/snap-controller 0.20.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +167 -0
  3. package/dist/cjs/Abstract/AbstractController.d.ts +40 -0
  4. package/dist/cjs/Abstract/AbstractController.d.ts.map +1 -0
  5. package/dist/cjs/Abstract/AbstractController.js +281 -0
  6. package/dist/cjs/Autocomplete/AutocompleteController.d.ts +40 -0
  7. package/dist/cjs/Autocomplete/AutocompleteController.d.ts.map +1 -0
  8. package/dist/cjs/Autocomplete/AutocompleteController.js +687 -0
  9. package/dist/cjs/Finder/FinderController.d.ts +14 -0
  10. package/dist/cjs/Finder/FinderController.d.ts.map +1 -0
  11. package/dist/cjs/Finder/FinderController.js +286 -0
  12. package/dist/cjs/Recommendation/RecommendationController.d.ts +31 -0
  13. package/dist/cjs/Recommendation/RecommendationController.d.ts.map +1 -0
  14. package/dist/cjs/Recommendation/RecommendationController.js +452 -0
  15. package/dist/cjs/Search/SearchController.d.ts +23 -0
  16. package/dist/cjs/Search/SearchController.d.ts.map +1 -0
  17. package/dist/cjs/Search/SearchController.js +429 -0
  18. package/dist/cjs/index.d.ts +7 -0
  19. package/dist/cjs/index.d.ts.map +1 -0
  20. package/dist/cjs/index.js +24 -0
  21. package/dist/cjs/types.d.ts +52 -0
  22. package/dist/cjs/types.d.ts.map +1 -0
  23. package/dist/cjs/types.js +2 -0
  24. package/dist/cjs/utils/getParams.d.ts +2 -0
  25. package/dist/cjs/utils/getParams.d.ts.map +1 -0
  26. package/dist/cjs/utils/getParams.js +72 -0
  27. package/dist/esm/Abstract/AbstractController.d.ts +40 -0
  28. package/dist/esm/Abstract/AbstractController.d.ts.map +1 -0
  29. package/dist/esm/Abstract/AbstractController.js +181 -0
  30. package/dist/esm/Autocomplete/AutocompleteController.d.ts +40 -0
  31. package/dist/esm/Autocomplete/AutocompleteController.d.ts.map +1 -0
  32. package/dist/esm/Autocomplete/AutocompleteController.js +472 -0
  33. package/dist/esm/Finder/FinderController.d.ts +14 -0
  34. package/dist/esm/Finder/FinderController.d.ts.map +1 -0
  35. package/dist/esm/Finder/FinderController.js +164 -0
  36. package/dist/esm/Recommendation/RecommendationController.d.ts +31 -0
  37. package/dist/esm/Recommendation/RecommendationController.d.ts.map +1 -0
  38. package/dist/esm/Recommendation/RecommendationController.js +330 -0
  39. package/dist/esm/Search/SearchController.d.ts +23 -0
  40. package/dist/esm/Search/SearchController.d.ts.map +1 -0
  41. package/dist/esm/Search/SearchController.js +282 -0
  42. package/dist/esm/index.d.ts +7 -0
  43. package/dist/esm/index.d.ts.map +1 -0
  44. package/dist/esm/index.js +6 -0
  45. package/dist/esm/types.d.ts +52 -0
  46. package/dist/esm/types.d.ts.map +1 -0
  47. package/dist/esm/types.js +1 -0
  48. package/dist/esm/utils/getParams.d.ts +2 -0
  49. package/dist/esm/utils/getParams.d.ts.map +1 -0
  50. package/dist/esm/utils/getParams.js +68 -0
  51. package/package.json +40 -0
@@ -0,0 +1,687 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ var __assign = (this && this.__assign) || function () {
18
+ __assign = Object.assign || function(t) {
19
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
20
+ s = arguments[i];
21
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
22
+ t[p] = s[p];
23
+ }
24
+ return t;
25
+ };
26
+ return __assign.apply(this, arguments);
27
+ };
28
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
29
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
30
+ return new (P || (P = Promise))(function (resolve, reject) {
31
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
32
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
33
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
34
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
35
+ });
36
+ };
37
+ var __generator = (this && this.__generator) || function (thisArg, body) {
38
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
39
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
40
+ function verb(n) { return function (v) { return step([n, v]); }; }
41
+ function step(op) {
42
+ if (f) throw new TypeError("Generator is already executing.");
43
+ while (_) try {
44
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
45
+ if (y = 0, t) op = [op[0] & 2, t.value];
46
+ switch (op[0]) {
47
+ case 0: case 1: t = op; break;
48
+ case 4: _.label++; return { value: op[1], done: false };
49
+ case 5: _.label++; y = op[1]; op = [0]; continue;
50
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
51
+ default:
52
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
53
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
54
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
55
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
56
+ if (t[2]) _.ops.pop();
57
+ _.trys.pop(); continue;
58
+ }
59
+ op = body.call(thisArg, _);
60
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
61
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
62
+ }
63
+ };
64
+ var __importDefault = (this && this.__importDefault) || function (mod) {
65
+ return (mod && mod.__esModule) ? mod : { "default": mod };
66
+ };
67
+ Object.defineProperty(exports, "__esModule", { value: true });
68
+ exports.AutocompleteController = void 0;
69
+ var deepmerge_1 = __importDefault(require("deepmerge"));
70
+ var snap_store_mobx_1 = require("@searchspring/snap-store-mobx");
71
+ var snap_toolbox_1 = require("@searchspring/snap-toolbox");
72
+ var AbstractController_1 = require("../Abstract/AbstractController");
73
+ var getParams_1 = require("../utils/getParams");
74
+ var INPUT_ATTRIBUTE = 'ss-autocomplete-input';
75
+ var INPUT_DELAY = 200;
76
+ var KEY_ENTER = 13;
77
+ var KEY_ESCAPE = 27;
78
+ var PARAM_ORIGINAL_QUERY = 'oq';
79
+ var defaultConfig = {
80
+ id: 'autocomplete',
81
+ selector: '',
82
+ action: '',
83
+ globals: {},
84
+ settings: {
85
+ initializeFromUrl: true,
86
+ syncInputs: true,
87
+ facets: {
88
+ trim: true,
89
+ pinFiltered: true,
90
+ },
91
+ },
92
+ };
93
+ var AutocompleteController = /** @class */ (function (_super) {
94
+ __extends(AutocompleteController, _super);
95
+ function AutocompleteController(config, _a) {
96
+ var client = _a.client, store = _a.store, urlManager = _a.urlManager, eventManager = _a.eventManager, profiler = _a.profiler, logger = _a.logger, tracker = _a.tracker;
97
+ var _this = _super.call(this, config, { client: client, store: store, urlManager: urlManager, eventManager: eventManager, profiler: profiler, logger: logger, tracker: tracker }) || this;
98
+ _this.type = 'autocomplete';
99
+ _this.track = {
100
+ // TODO: add in future when autocomplete supports result click tracking
101
+ product: {
102
+ click: function (e, result) {
103
+ _this.log.warn('product.click tracking is not currently supported in this controller type');
104
+ },
105
+ },
106
+ };
107
+ _this.handlers = {
108
+ input: {
109
+ enterKey: function (e) { return __awaiter(_this, void 0, void 0, function () {
110
+ var actionUrl, input, inputParam, err_1, newUrl;
111
+ var _a, _b, _c;
112
+ return __generator(this, function (_d) {
113
+ switch (_d.label) {
114
+ case 0:
115
+ if (!(e.keyCode == KEY_ENTER)) return [3 /*break*/, 10];
116
+ actionUrl = (0, snap_toolbox_1.url)(this.config.action);
117
+ input = e.target;
118
+ if (!((_c = (_b = (_a = this.config.globals) === null || _a === void 0 ? void 0 : _a.search) === null || _b === void 0 ? void 0 : _b.query) === null || _c === void 0 ? void 0 : _c.spellCorrection)) return [3 /*break*/, 5];
119
+ // wait until loading is complete before submission
120
+ // TODO make this better
121
+ return [4 /*yield*/, timeout(INPUT_DELAY + 1)];
122
+ case 1:
123
+ // wait until loading is complete before submission
124
+ // TODO make this better
125
+ _d.sent();
126
+ _d.label = 2;
127
+ case 2:
128
+ if (!this.store.loading) return [3 /*break*/, 4];
129
+ return [4 /*yield*/, timeout(INPUT_DELAY)];
130
+ case 3:
131
+ _d.sent();
132
+ return [3 /*break*/, 2];
133
+ case 4:
134
+ // use corrected query and originalQuery
135
+ if (this.store.search.originalQuery) {
136
+ input.value = this.store.search.query.string;
137
+ actionUrl.params.query[PARAM_ORIGINAL_QUERY] = this.store.search.originalQuery.string;
138
+ }
139
+ _d.label = 5;
140
+ case 5:
141
+ inputParam = input.name || this.urlManager.getTranslatorConfig().queryParameter;
142
+ actionUrl.params.query[inputParam] = input.value;
143
+ _d.label = 6;
144
+ case 6:
145
+ _d.trys.push([6, 8, , 9]);
146
+ return [4 /*yield*/, this.eventManager.fire('beforeSubmit', {
147
+ controller: this,
148
+ input: input,
149
+ })];
150
+ case 7:
151
+ _d.sent();
152
+ return [3 /*break*/, 9];
153
+ case 8:
154
+ err_1 = _d.sent();
155
+ if ((err_1 === null || err_1 === void 0 ? void 0 : err_1.message) == 'cancelled') {
156
+ this.log.warn("'beforeSubmit' middleware cancelled");
157
+ return [2 /*return*/];
158
+ }
159
+ else {
160
+ this.log.error("error in 'beforeSubmit' middleware");
161
+ console.error(err_1);
162
+ }
163
+ return [3 /*break*/, 9];
164
+ case 9:
165
+ newUrl = actionUrl.url();
166
+ window.location.href = newUrl;
167
+ _d.label = 10;
168
+ case 10: return [2 /*return*/];
169
+ }
170
+ });
171
+ }); },
172
+ escKey: function (e) {
173
+ if (e.keyCode == KEY_ESCAPE) {
174
+ e.target.blur();
175
+ _this.setFocused();
176
+ }
177
+ },
178
+ focus: function (e) {
179
+ e.stopPropagation();
180
+ // timeout to ensure focus happens AFTER click
181
+ setTimeout(function () {
182
+ _this.setFocused(e.target);
183
+ });
184
+ },
185
+ formSubmit: function (e) { return __awaiter(_this, void 0, void 0, function () {
186
+ var form, input, err_2;
187
+ var _a, _b, _c;
188
+ return __generator(this, function (_d) {
189
+ switch (_d.label) {
190
+ case 0:
191
+ form = e.target;
192
+ input = form.querySelector("input[".concat(INPUT_ATTRIBUTE, "]"));
193
+ e.preventDefault();
194
+ if (!((_c = (_b = (_a = this.config.globals) === null || _a === void 0 ? void 0 : _a.search) === null || _b === void 0 ? void 0 : _b.query) === null || _c === void 0 ? void 0 : _c.spellCorrection)) return [3 /*break*/, 5];
195
+ // wait until loading is complete before submission
196
+ // TODO make this better
197
+ return [4 /*yield*/, timeout(INPUT_DELAY + 1)];
198
+ case 1:
199
+ // wait until loading is complete before submission
200
+ // TODO make this better
201
+ _d.sent();
202
+ _d.label = 2;
203
+ case 2:
204
+ if (!this.store.loading) return [3 /*break*/, 4];
205
+ return [4 /*yield*/, timeout(INPUT_DELAY)];
206
+ case 3:
207
+ _d.sent();
208
+ return [3 /*break*/, 2];
209
+ case 4:
210
+ if (this.store.search.originalQuery) {
211
+ input.value = this.store.search.query.string;
212
+ addHiddenFormInput(form, PARAM_ORIGINAL_QUERY, this.store.search.originalQuery.string);
213
+ }
214
+ _d.label = 5;
215
+ case 5:
216
+ _d.trys.push([5, 7, , 8]);
217
+ return [4 /*yield*/, this.eventManager.fire('beforeSubmit', {
218
+ controller: this,
219
+ input: input,
220
+ })];
221
+ case 6:
222
+ _d.sent();
223
+ return [3 /*break*/, 8];
224
+ case 7:
225
+ err_2 = _d.sent();
226
+ if ((err_2 === null || err_2 === void 0 ? void 0 : err_2.message) == 'cancelled') {
227
+ this.log.warn("'beforeSubmit' middleware cancelled");
228
+ return [2 /*return*/];
229
+ }
230
+ else {
231
+ this.log.error("error in 'beforeSubmit' middleware");
232
+ console.error(err_2);
233
+ }
234
+ return [3 /*break*/, 8];
235
+ case 8:
236
+ form.submit();
237
+ return [2 /*return*/];
238
+ }
239
+ });
240
+ }); },
241
+ keyUp: function (e) {
242
+ // ignore enter and escape keys
243
+ if ((e === null || e === void 0 ? void 0 : e.keyCode) == KEY_ENTER || (e === null || e === void 0 ? void 0 : e.keyCode) == KEY_ESCAPE)
244
+ return;
245
+ // return focus on keyup if it was lost
246
+ if (e.isTrusted && _this.store.state.focusedInput !== e.target) {
247
+ _this.setFocused(e.target);
248
+ }
249
+ var value = e.target.value;
250
+ // prevent search when value is unchanged
251
+ if (_this.store.state.input == value && _this.store.loaded) {
252
+ return;
253
+ }
254
+ _this.store.state.input = value;
255
+ if (_this.config.settings.syncInputs) {
256
+ var inputs = document.querySelectorAll(_this.config.selector);
257
+ inputs.forEach(function (input) {
258
+ input.value = value;
259
+ });
260
+ }
261
+ clearTimeout(_this.handlers.input.timeoutDelay);
262
+ if (!value) {
263
+ // TODO cancel any current requests?
264
+ _this.store.reset();
265
+ _this.urlManager.reset().go();
266
+ }
267
+ else {
268
+ _this.handlers.input.timeoutDelay = setTimeout(function () {
269
+ _this.store.state.locks.terms.unlock();
270
+ _this.store.state.locks.facets.unlock();
271
+ _this.urlManager.set({ query: _this.store.state.input }).go();
272
+ }, INPUT_DELAY);
273
+ }
274
+ },
275
+ timeoutDelay: undefined,
276
+ },
277
+ document: {
278
+ click: function (e) {
279
+ var inputs = document.querySelectorAll(_this.config.selector);
280
+ if (Array.from(inputs).includes(e.target)) {
281
+ e.stopPropagation();
282
+ }
283
+ else {
284
+ _this.setFocused();
285
+ }
286
+ },
287
+ },
288
+ };
289
+ _this.searchTrending = function () { return __awaiter(_this, void 0, void 0, function () {
290
+ var terms, storedTerms, trendingParams, trendingProfile;
291
+ var _a, _b;
292
+ return __generator(this, function (_c) {
293
+ switch (_c.label) {
294
+ case 0:
295
+ storedTerms = this.storage.get('terms');
296
+ if (!storedTerms) return [3 /*break*/, 1];
297
+ // terms exist in storage, update store
298
+ terms = JSON.parse(storedTerms);
299
+ return [3 /*break*/, 3];
300
+ case 1:
301
+ trendingParams = {
302
+ limit: ((_b = (_a = this.config.settings) === null || _a === void 0 ? void 0 : _a.trending) === null || _b === void 0 ? void 0 : _b.limit) || 5,
303
+ };
304
+ trendingProfile = this.profiler.create({ type: 'event', name: 'trending', context: trendingParams }).start();
305
+ return [4 /*yield*/, this.client.trending(trendingParams)];
306
+ case 2:
307
+ terms = _c.sent();
308
+ trendingProfile.stop();
309
+ this.log.profile(trendingProfile);
310
+ this.storage.set('terms', JSON.stringify(terms));
311
+ _c.label = 3;
312
+ case 3:
313
+ this.store.updateTrendingTerms(terms);
314
+ return [2 /*return*/];
315
+ }
316
+ });
317
+ }); };
318
+ _this.search = function () { return __awaiter(_this, void 0, void 0, function () {
319
+ var params, err_3, searchProfile, _a, meta, response, afterSearchProfile, err_4, afterStoreProfile, err_5, err_6;
320
+ var _b, _c;
321
+ return __generator(this, function (_d) {
322
+ switch (_d.label) {
323
+ case 0:
324
+ params = this.params;
325
+ if (!((_c = (_b = params === null || params === void 0 ? void 0 : params.search) === null || _b === void 0 ? void 0 : _b.query) === null || _c === void 0 ? void 0 : _c.string)) {
326
+ return [2 /*return*/];
327
+ }
328
+ _d.label = 1;
329
+ case 1:
330
+ _d.trys.push([1, 15, , 16]);
331
+ _d.label = 2;
332
+ case 2:
333
+ _d.trys.push([2, 4, , 5]);
334
+ return [4 /*yield*/, this.eventManager.fire('beforeSearch', {
335
+ controller: this,
336
+ request: params,
337
+ })];
338
+ case 3:
339
+ _d.sent();
340
+ return [3 /*break*/, 5];
341
+ case 4:
342
+ err_3 = _d.sent();
343
+ if ((err_3 === null || err_3 === void 0 ? void 0 : err_3.message) == 'cancelled') {
344
+ this.log.warn("'beforeSearch' middleware cancelled");
345
+ return [2 /*return*/];
346
+ }
347
+ else {
348
+ this.log.error("error in 'beforeSearch' middleware");
349
+ throw err_3;
350
+ }
351
+ return [3 /*break*/, 5];
352
+ case 5:
353
+ searchProfile = this.profiler.create({ type: 'event', name: 'search', context: params }).start();
354
+ return [4 /*yield*/, this.client.autocomplete(params)];
355
+ case 6:
356
+ _a = _d.sent(), meta = _a[0], response = _a[1];
357
+ if (!response.meta) {
358
+ /**
359
+ * MockClient will overwrite the client search() method and use
360
+ * SearchData to return mock data which already contains meta data
361
+ */
362
+ response.meta = meta;
363
+ }
364
+ searchProfile.stop();
365
+ this.log.profile(searchProfile);
366
+ afterSearchProfile = this.profiler.create({ type: 'event', name: 'afterSearch', context: params }).start();
367
+ _d.label = 7;
368
+ case 7:
369
+ _d.trys.push([7, 9, , 10]);
370
+ return [4 /*yield*/, this.eventManager.fire('afterSearch', {
371
+ controller: this,
372
+ request: params,
373
+ response: response,
374
+ })];
375
+ case 8:
376
+ _d.sent();
377
+ return [3 /*break*/, 10];
378
+ case 9:
379
+ err_4 = _d.sent();
380
+ if ((err_4 === null || err_4 === void 0 ? void 0 : err_4.message) == 'cancelled') {
381
+ this.log.warn("'afterSearch' middleware cancelled");
382
+ afterSearchProfile.stop();
383
+ return [2 /*return*/];
384
+ }
385
+ else {
386
+ this.log.error("error in 'afterSearch' middleware");
387
+ throw err_4;
388
+ }
389
+ return [3 /*break*/, 10];
390
+ case 10:
391
+ afterSearchProfile.stop();
392
+ this.log.profile(afterSearchProfile);
393
+ // update the store
394
+ this.store.update(response);
395
+ afterStoreProfile = this.profiler.create({ type: 'event', name: 'afterStore', context: params }).start();
396
+ _d.label = 11;
397
+ case 11:
398
+ _d.trys.push([11, 13, , 14]);
399
+ return [4 /*yield*/, this.eventManager.fire('afterStore', {
400
+ controller: this,
401
+ request: params,
402
+ response: response,
403
+ })];
404
+ case 12:
405
+ _d.sent();
406
+ return [3 /*break*/, 14];
407
+ case 13:
408
+ err_5 = _d.sent();
409
+ if ((err_5 === null || err_5 === void 0 ? void 0 : err_5.message) == 'cancelled') {
410
+ this.log.warn("'afterStore' middleware cancelled");
411
+ afterStoreProfile.stop();
412
+ return [2 /*return*/];
413
+ }
414
+ else {
415
+ this.log.error("error in 'afterStore' middleware");
416
+ throw err_5;
417
+ }
418
+ return [3 /*break*/, 14];
419
+ case 14:
420
+ afterStoreProfile.stop();
421
+ this.log.profile(afterStoreProfile);
422
+ return [3 /*break*/, 16];
423
+ case 15:
424
+ err_6 = _d.sent();
425
+ if (err_6) {
426
+ switch (err_6) {
427
+ case 429:
428
+ this.store.error = {
429
+ code: 429,
430
+ type: snap_store_mobx_1.ErrorType.WARNING,
431
+ message: 'Too many requests try again later',
432
+ };
433
+ this.log.warn(this.store.error);
434
+ break;
435
+ case 500:
436
+ this.store.error = {
437
+ code: 500,
438
+ type: snap_store_mobx_1.ErrorType.ERROR,
439
+ message: 'Invalid Search Request or Service Unavailable',
440
+ };
441
+ this.log.error(this.store.error);
442
+ break;
443
+ default:
444
+ this.log.error(err_6);
445
+ break;
446
+ }
447
+ this.store.loading = false;
448
+ }
449
+ return [3 /*break*/, 16];
450
+ case 16: return [2 /*return*/];
451
+ }
452
+ });
453
+ }); };
454
+ // deep merge config with defaults
455
+ _this.config = (0, deepmerge_1.default)(defaultConfig, _this.config);
456
+ _this.store.setConfig(_this.config);
457
+ // get current search from url before detaching
458
+ if (_this.config.settings.initializeFromUrl) {
459
+ _this.store.state.input = _this.urlManager.state.query;
460
+ // reset to force search on focus
461
+ // TODO: make a config setting for this
462
+ _this.urlManager.reset().go();
463
+ }
464
+ // persist trending terms in local storage
465
+ _this.storage = new snap_store_mobx_1.StorageStore({
466
+ type: snap_store_mobx_1.StorageType.SESSION,
467
+ key: "ss-controller-".concat(_this.config.id),
468
+ });
469
+ // add 'beforeSearch' middleware
470
+ _this.eventManager.on('beforeSearch', function (ac, next) { return __awaiter(_this, void 0, void 0, function () {
471
+ return __generator(this, function (_a) {
472
+ switch (_a.label) {
473
+ case 0:
474
+ ac.controller.store.loading = true;
475
+ return [4 /*yield*/, next()];
476
+ case 1:
477
+ _a.sent();
478
+ return [2 /*return*/];
479
+ }
480
+ });
481
+ }); });
482
+ // add 'afterSearch' middleware
483
+ _this.eventManager.on('afterSearch', function (ac, next) { return __awaiter(_this, void 0, void 0, function () {
484
+ return __generator(this, function (_a) {
485
+ switch (_a.label) {
486
+ case 0: return [4 /*yield*/, next()];
487
+ case 1:
488
+ _a.sent();
489
+ // cancel search if no input or query doesn't match current urlState
490
+ if (ac.response.autocomplete.query != ac.controller.urlManager.state.query) {
491
+ return [2 /*return*/, false];
492
+ }
493
+ return [2 /*return*/];
494
+ }
495
+ });
496
+ }); });
497
+ // add 'afterStore' middleware
498
+ _this.eventManager.on('afterStore', function (ac, next) { return __awaiter(_this, void 0, void 0, function () {
499
+ return __generator(this, function (_a) {
500
+ switch (_a.label) {
501
+ case 0: return [4 /*yield*/, next()];
502
+ case 1:
503
+ _a.sent();
504
+ ac.controller.store.loading = false;
505
+ return [2 /*return*/];
506
+ }
507
+ });
508
+ }); });
509
+ // attach config plugins and event middleware
510
+ _this.use(_this.config);
511
+ return _this;
512
+ }
513
+ Object.defineProperty(AutocompleteController.prototype, "params", {
514
+ get: function () {
515
+ var _a, _b;
516
+ var urlState = this.urlManager.state;
517
+ var params = (0, deepmerge_1.default)(__assign({}, (0, getParams_1.getSearchParams)(urlState)), this.config.globals);
518
+ var userId = this.tracker.getUserId();
519
+ if (userId) {
520
+ params.tracking = params.tracking || {};
521
+ params.tracking.userId = userId;
522
+ }
523
+ if (!((_b = (_a = this.config.globals) === null || _a === void 0 ? void 0 : _a.personalization) === null || _b === void 0 ? void 0 : _b.disabled)) {
524
+ var cartItems = this.tracker.cookies.cart.get();
525
+ if (cartItems.length) {
526
+ params.personalization = params.personalization || {};
527
+ params.personalization.cart = cartItems.join(',');
528
+ }
529
+ var lastViewedItems = this.tracker.cookies.viewed.get();
530
+ if (lastViewedItems.length) {
531
+ params.personalization = params.personalization || {};
532
+ params.personalization.lastViewed = lastViewedItems.join(',');
533
+ }
534
+ var shopperId = this.tracker.getShopperId();
535
+ if (shopperId) {
536
+ params.personalization = params.personalization || {};
537
+ params.personalization.shopper = shopperId;
538
+ }
539
+ }
540
+ return params;
541
+ },
542
+ enumerable: false,
543
+ configurable: true
544
+ });
545
+ AutocompleteController.prototype.setFocused = function (inputElement) {
546
+ return __awaiter(this, void 0, void 0, function () {
547
+ var err_7, err_8;
548
+ return __generator(this, function (_a) {
549
+ switch (_a.label) {
550
+ case 0:
551
+ if (!(this.store.state.focusedInput !== inputElement)) return [3 /*break*/, 7];
552
+ this.store.state.focusedInput = inputElement;
553
+ _a.label = 1;
554
+ case 1:
555
+ _a.trys.push([1, 6, , 7]);
556
+ _a.label = 2;
557
+ case 2:
558
+ _a.trys.push([2, 4, , 5]);
559
+ return [4 /*yield*/, this.eventManager.fire('focusChange', {
560
+ controller: this,
561
+ })];
562
+ case 3:
563
+ _a.sent();
564
+ return [3 /*break*/, 5];
565
+ case 4:
566
+ err_7 = _a.sent();
567
+ if ((err_7 === null || err_7 === void 0 ? void 0 : err_7.message) == 'cancelled') {
568
+ this.log.warn("'focusChange' middleware cancelled");
569
+ }
570
+ else {
571
+ this.log.error("error in 'focusChange' middleware");
572
+ throw err_7;
573
+ }
574
+ return [3 /*break*/, 5];
575
+ case 5: return [3 /*break*/, 7];
576
+ case 6:
577
+ err_8 = _a.sent();
578
+ if (err_8) {
579
+ console.error(err_8);
580
+ }
581
+ return [3 /*break*/, 7];
582
+ case 7:
583
+ inputElement === null || inputElement === void 0 ? void 0 : inputElement.dispatchEvent(new Event('keyup'));
584
+ return [2 /*return*/];
585
+ }
586
+ });
587
+ });
588
+ };
589
+ AutocompleteController.prototype.reset = function () {
590
+ // reset input values and state
591
+ var inputs = document.querySelectorAll(this.config.selector);
592
+ inputs.forEach(function (input) {
593
+ input.value = '';
594
+ });
595
+ this.store.reset();
596
+ };
597
+ AutocompleteController.prototype.unbind = function () {
598
+ var _this = this;
599
+ var inputs = document.querySelectorAll("input[".concat(INPUT_ATTRIBUTE, "]"));
600
+ inputs === null || inputs === void 0 ? void 0 : inputs.forEach(function (input) {
601
+ var _a;
602
+ input.removeEventListener('keyup', _this.handlers.input.keyUp);
603
+ input.removeEventListener('keyup', _this.handlers.input.enterKey);
604
+ input.removeEventListener('keyup', _this.handlers.input.escKey);
605
+ input.removeEventListener('focus', _this.handlers.input.focus);
606
+ (_a = input.form) === null || _a === void 0 ? void 0 : _a.removeEventListener('submit', _this.handlers.input.formSubmit);
607
+ });
608
+ document.removeEventListener('click', this.handlers.document.click);
609
+ };
610
+ AutocompleteController.prototype.bind = function () {
611
+ var _a, _b, _c;
612
+ return __awaiter(this, void 0, void 0, function () {
613
+ var inputs;
614
+ var _this = this;
615
+ return __generator(this, function (_d) {
616
+ switch (_d.label) {
617
+ case 0:
618
+ if (!!this.initialized) return [3 /*break*/, 2];
619
+ return [4 /*yield*/, this.init()];
620
+ case 1:
621
+ _d.sent();
622
+ _d.label = 2;
623
+ case 2:
624
+ this.unbind();
625
+ inputs = document.querySelectorAll(this.config.selector);
626
+ inputs.forEach(function (input) {
627
+ input.setAttribute('spellcheck', 'false');
628
+ input.setAttribute('autocomplete', 'off');
629
+ input.setAttribute(INPUT_ATTRIBUTE, '');
630
+ input.addEventListener('keyup', _this.handlers.input.keyUp);
631
+ if (_this.config.settings.initializeFromUrl && !input.value && _this.store.state.input) {
632
+ input.value = _this.store.state.input;
633
+ }
634
+ input.addEventListener('focus', _this.handlers.input.focus);
635
+ input.addEventListener('keyup', _this.handlers.input.escKey);
636
+ var form = input.form;
637
+ var formActionUrl = _this.config.action;
638
+ if (!form && _this.config.action) {
639
+ input.addEventListener('keyup', _this.handlers.input.enterKey);
640
+ }
641
+ else if (form) {
642
+ if (_this.config.action) {
643
+ form.action = _this.config.action;
644
+ }
645
+ else {
646
+ formActionUrl = form.action;
647
+ }
648
+ form.addEventListener('submit', _this.handlers.input.formSubmit);
649
+ }
650
+ // set the root URL on urlManager
651
+ if (formActionUrl) {
652
+ _this.store.setService('urlManager', _this.urlManager.withConfig(function (translatorConfig) {
653
+ return __assign(__assign({}, translatorConfig), { urlRoot: formActionUrl });
654
+ }));
655
+ }
656
+ if (document.activeElement === input) {
657
+ _this.setFocused(input);
658
+ }
659
+ });
660
+ if (((_b = (_a = this.config.settings) === null || _a === void 0 ? void 0 : _a.trending) === null || _b === void 0 ? void 0 : _b.limit) > 0 && !((_c = this.store.trending) === null || _c === void 0 ? void 0 : _c.length)) {
661
+ this.searchTrending();
662
+ }
663
+ document.addEventListener('click', this.handlers.document.click);
664
+ return [2 /*return*/];
665
+ }
666
+ });
667
+ });
668
+ };
669
+ return AutocompleteController;
670
+ }(AbstractController_1.AbstractController));
671
+ exports.AutocompleteController = AutocompleteController;
672
+ function addHiddenFormInput(form, name, value) {
673
+ var inputElem = document.createElement('input');
674
+ inputElem.type = 'hidden';
675
+ inputElem.name = name;
676
+ inputElem.value = value;
677
+ form.append(inputElem);
678
+ }
679
+ function timeout(time) {
680
+ return __awaiter(this, void 0, void 0, function () {
681
+ return __generator(this, function (_a) {
682
+ return [2 /*return*/, new Promise(function (resolve) {
683
+ window.setTimeout(resolve, time);
684
+ })];
685
+ });
686
+ });
687
+ }