@athoscommerce/snap-controller 1.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/dist/cjs/Abstract/AbstractController.d.ts +42 -0
  4. package/dist/cjs/Abstract/AbstractController.d.ts.map +1 -0
  5. package/dist/cjs/Abstract/AbstractController.js +305 -0
  6. package/dist/cjs/Autocomplete/AutocompleteController.d.ts +59 -0
  7. package/dist/cjs/Autocomplete/AutocompleteController.d.ts.map +1 -0
  8. package/dist/cjs/Autocomplete/AutocompleteController.js +1091 -0
  9. package/dist/cjs/Finder/FinderController.d.ts +15 -0
  10. package/dist/cjs/Finder/FinderController.d.ts.map +1 -0
  11. package/dist/cjs/Finder/FinderController.js +336 -0
  12. package/dist/cjs/Recommendation/RecommendationController.d.ts +27 -0
  13. package/dist/cjs/Recommendation/RecommendationController.d.ts.map +1 -0
  14. package/dist/cjs/Recommendation/RecommendationController.js +447 -0
  15. package/dist/cjs/Search/SearchController.d.ts +41 -0
  16. package/dist/cjs/Search/SearchController.d.ts.map +1 -0
  17. package/dist/cjs/Search/SearchController.js +993 -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 +29 -0
  21. package/dist/cjs/types.d.ts +87 -0
  22. package/dist/cjs/types.d.ts.map +1 -0
  23. package/dist/cjs/types.js +10 -0
  24. package/dist/cjs/utils/getParams.d.ts +3 -0
  25. package/dist/cjs/utils/getParams.d.ts.map +1 -0
  26. package/dist/cjs/utils/getParams.js +70 -0
  27. package/dist/cjs/utils/isClickWithinBannerLink.d.ts +2 -0
  28. package/dist/cjs/utils/isClickWithinBannerLink.d.ts.map +1 -0
  29. package/dist/cjs/utils/isClickWithinBannerLink.js +21 -0
  30. package/dist/cjs/utils/isClickWithinProductLink.d.ts +5 -0
  31. package/dist/cjs/utils/isClickWithinProductLink.d.ts.map +1 -0
  32. package/dist/cjs/utils/isClickWithinProductLink.js +25 -0
  33. package/dist/esm/Abstract/AbstractController.d.ts +42 -0
  34. package/dist/esm/Abstract/AbstractController.d.ts.map +1 -0
  35. package/dist/esm/Abstract/AbstractController.js +208 -0
  36. package/dist/esm/Autocomplete/AutocompleteController.d.ts +59 -0
  37. package/dist/esm/Autocomplete/AutocompleteController.d.ts.map +1 -0
  38. package/dist/esm/Autocomplete/AutocompleteController.js +882 -0
  39. package/dist/esm/Finder/FinderController.d.ts +15 -0
  40. package/dist/esm/Finder/FinderController.d.ts.map +1 -0
  41. package/dist/esm/Finder/FinderController.js +218 -0
  42. package/dist/esm/Recommendation/RecommendationController.d.ts +27 -0
  43. package/dist/esm/Recommendation/RecommendationController.d.ts.map +1 -0
  44. package/dist/esm/Recommendation/RecommendationController.js +342 -0
  45. package/dist/esm/Search/SearchController.d.ts +41 -0
  46. package/dist/esm/Search/SearchController.d.ts.map +1 -0
  47. package/dist/esm/Search/SearchController.js +795 -0
  48. package/dist/esm/index.d.ts +7 -0
  49. package/dist/esm/index.d.ts.map +1 -0
  50. package/dist/esm/index.js +6 -0
  51. package/dist/esm/types.d.ts +87 -0
  52. package/dist/esm/types.d.ts.map +1 -0
  53. package/dist/esm/types.js +7 -0
  54. package/dist/esm/utils/getParams.d.ts +3 -0
  55. package/dist/esm/utils/getParams.d.ts.map +1 -0
  56. package/dist/esm/utils/getParams.js +67 -0
  57. package/dist/esm/utils/isClickWithinBannerLink.d.ts +2 -0
  58. package/dist/esm/utils/isClickWithinBannerLink.d.ts.map +1 -0
  59. package/dist/esm/utils/isClickWithinBannerLink.js +17 -0
  60. package/dist/esm/utils/isClickWithinProductLink.d.ts +5 -0
  61. package/dist/esm/utils/isClickWithinProductLink.d.ts.map +1 -0
  62. package/dist/esm/utils/isClickWithinProductLink.js +19 -0
  63. package/package.json +41 -0
@@ -0,0 +1,1091 @@
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 = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
39
+ return g.next = verb(0), g["throw"] = verb(1), g["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 (g && (g = 0, op[0] && (_ = 0)), _) 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 = exports.INPUT_DELAY = void 0;
69
+ var deepmerge_1 = __importDefault(require("deepmerge"));
70
+ var snap_store_mobx_1 = require("@athoscommerce/snap-store-mobx");
71
+ var AbstractController_1 = require("../Abstract/AbstractController");
72
+ var getParams_1 = require("../utils/getParams");
73
+ var types_1 = require("../types");
74
+ var isClickWithinProductLink_1 = require("../utils/isClickWithinProductLink");
75
+ var isClickWithinBannerLink_1 = require("../utils/isClickWithinBannerLink");
76
+ var INPUT_ATTRIBUTE = 'ss-autocomplete-input';
77
+ exports.INPUT_DELAY = 200;
78
+ var KEY_ENTER = 13;
79
+ var KEY_ESCAPE = 27;
80
+ var PARAM_FALLBACK_QUERY = 'fallbackQuery';
81
+ var defaultConfig = {
82
+ id: 'autocomplete',
83
+ selector: '',
84
+ action: '',
85
+ globals: {},
86
+ beacon: {
87
+ enabled: true,
88
+ },
89
+ settings: {
90
+ initializeFromUrl: true,
91
+ syncInputs: true,
92
+ serializeForm: false,
93
+ facets: {
94
+ trim: true,
95
+ pinFiltered: true,
96
+ },
97
+ redirects: {
98
+ merchandising: true,
99
+ singleResult: false,
100
+ },
101
+ bind: {
102
+ input: true,
103
+ submit: true,
104
+ },
105
+ },
106
+ };
107
+ var AutocompleteController = /** @class */ (function (_super) {
108
+ __extends(AutocompleteController, _super);
109
+ function AutocompleteController(config, _a, context) {
110
+ var client = _a.client, store = _a.store, urlManager = _a.urlManager, eventManager = _a.eventManager, profiler = _a.profiler, logger = _a.logger, tracker = _a.tracker;
111
+ var _b, _c, _d, _e, _f, _g, _h, _j;
112
+ var _this = _super.call(this, config, { client: client, store: store, urlManager: urlManager, eventManager: eventManager, profiler: profiler, logger: logger, tracker: tracker }, context) || this;
113
+ _this.type = types_1.ControllerTypes.autocomplete;
114
+ _this.events = {};
115
+ _this.track = {
116
+ banner: {
117
+ impression: function (_banner) {
118
+ var _a, _b, _c, _d, _e, _f;
119
+ if (!_banner) {
120
+ _this.log.warn('No banner provided to track.banner.impression');
121
+ return;
122
+ }
123
+ var responseId = _banner.responseId, uid = _banner.uid;
124
+ if (!_this.events[responseId]) {
125
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
126
+ return;
127
+ }
128
+ else if ((_d = (_c = (_b = (_a = _this.events) === null || _a === void 0 ? void 0 : _a[responseId]) === null || _b === void 0 ? void 0 : _b.banner) === null || _c === void 0 ? void 0 : _c[uid]) === null || _d === void 0 ? void 0 : _d.impression) {
129
+ return;
130
+ }
131
+ var banner = { uid: uid };
132
+ var data = {
133
+ responseId: responseId,
134
+ banners: [banner],
135
+ results: [],
136
+ };
137
+ _this.eventManager.fire('track.banner.impression', { controller: _this, product: { uid: uid }, trackEvent: data });
138
+ ((_e = _this.config.beacon) === null || _e === void 0 ? void 0 : _e.enabled) && _this.tracker.events.autocomplete.impression({ data: data, siteId: (_f = _this.config.globals) === null || _f === void 0 ? void 0 : _f.siteId });
139
+ _this.events[responseId].banner[uid] = _this.events[responseId].banner[uid] || {};
140
+ _this.events[responseId].banner[uid].impression = true;
141
+ },
142
+ click: function (e, banner) {
143
+ var _a, _b, _c;
144
+ if (!banner) {
145
+ _this.log.warn('No banner provided to track.banner.click');
146
+ return;
147
+ }
148
+ var responseId = banner.responseId, uid = banner.uid;
149
+ if (!_this.events[responseId]) {
150
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
151
+ return;
152
+ }
153
+ if ((0, isClickWithinBannerLink_1.isClickWithinBannerLink)(e)) {
154
+ if ((_c = (_b = (_a = _this.events) === null || _a === void 0 ? void 0 : _a[responseId]) === null || _b === void 0 ? void 0 : _b.banner[uid]) === null || _c === void 0 ? void 0 : _c.clickThrough) {
155
+ return;
156
+ }
157
+ _this.track.banner.clickThrough(e, banner);
158
+ _this.events[responseId].banner[uid] = _this.events[responseId].banner[uid] || {};
159
+ _this.events[responseId].banner[uid].clickThrough = true;
160
+ setTimeout(function () {
161
+ _this.events[responseId].banner[uid].clickThrough = false;
162
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
163
+ }
164
+ },
165
+ clickThrough: function (e, _a) {
166
+ var _b, _c;
167
+ var uid = _a.uid, responseId = _a.responseId;
168
+ if (!uid) {
169
+ _this.log.warn('No banner uid provided to track.banner.clickThrough');
170
+ return;
171
+ }
172
+ if (!_this.events[responseId]) {
173
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
174
+ return;
175
+ }
176
+ var banner = { uid: uid };
177
+ var data = {
178
+ responseId: responseId,
179
+ banners: [banner],
180
+ };
181
+ _this.eventManager.fire('track.banner.clickThrough', { controller: _this, event: e, product: { uid: uid }, trackEvent: data });
182
+ ((_b = _this.config.beacon) === null || _b === void 0 ? void 0 : _b.enabled) && _this.tracker.events.autocomplete.clickThrough({ data: data, siteId: (_c = _this.config.globals) === null || _c === void 0 ? void 0 : _c.siteId });
183
+ _this.events[responseId].banner[uid] = _this.events[responseId].banner[uid] || {};
184
+ _this.events[responseId].banner[uid].clickThrough = true;
185
+ setTimeout(function () {
186
+ _this.events[responseId].banner[uid].clickThrough = false;
187
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
188
+ },
189
+ },
190
+ product: {
191
+ clickThrough: function (e, result) {
192
+ var _a, _b, _c, _d, _e, _f;
193
+ if (!result) {
194
+ _this.log.warn('No result provided to track.product.clickThrough');
195
+ return;
196
+ }
197
+ var responseId = result.responseId;
198
+ if (!_this.events[responseId]) {
199
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
200
+ return;
201
+ }
202
+ var type = (['product', 'banner'].includes(result.type) ? result.type : 'product');
203
+ var item = __assign({ type: type, uid: result.id ? '' + result.id : '' }, (type === 'product'
204
+ ? {
205
+ parentId: ((_a = result.mappings.core) === null || _a === void 0 ? void 0 : _a.parentId) ? '' + ((_b = result.mappings.core) === null || _b === void 0 ? void 0 : _b.parentId) : '',
206
+ sku: ((_c = result.mappings.core) === null || _c === void 0 ? void 0 : _c.sku) ? '' + ((_d = result.mappings.core) === null || _d === void 0 ? void 0 : _d.sku) : undefined,
207
+ }
208
+ : {}));
209
+ var data = {
210
+ responseId: responseId,
211
+ results: [item],
212
+ };
213
+ _this.eventManager.fire('track.product.clickThrough', { controller: _this, event: e, product: result, trackEvent: data });
214
+ ((_e = _this.config.beacon) === null || _e === void 0 ? void 0 : _e.enabled) && _this.tracker.events.autocomplete.clickThrough({ data: data, siteId: (_f = _this.config.globals) === null || _f === void 0 ? void 0 : _f.siteId });
215
+ },
216
+ click: function (e, result) {
217
+ var _a, _b, _c, _d, _e, _f;
218
+ if (!result) {
219
+ _this.log.warn('No result provided to track.product.click');
220
+ return;
221
+ }
222
+ var responseId = result.responseId;
223
+ if (!_this.events[responseId]) {
224
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
225
+ return;
226
+ }
227
+ if (result.type === 'banner' && (0, isClickWithinBannerLink_1.isClickWithinBannerLink)(e)) {
228
+ if ((_c = (_b = (_a = _this.events) === null || _a === void 0 ? void 0 : _a[responseId]) === null || _b === void 0 ? void 0 : _b.product[result.id]) === null || _c === void 0 ? void 0 : _c.inlineBannerClickThrough) {
229
+ return;
230
+ }
231
+ _this.track.product.clickThrough(e, result);
232
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
233
+ _this.events[responseId].product[result.id].inlineBannerClickThrough = true;
234
+ setTimeout(function () {
235
+ _this.events[responseId].product[result.id].inlineBannerClickThrough = false;
236
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
237
+ }
238
+ else if ((0, isClickWithinProductLink_1.isClickWithinProductLink)(e, result)) {
239
+ if ((_f = (_e = (_d = _this.events) === null || _d === void 0 ? void 0 : _d[responseId]) === null || _e === void 0 ? void 0 : _e.product[result.id]) === null || _f === void 0 ? void 0 : _f.productClickThrough) {
240
+ return;
241
+ }
242
+ _this.track.product.clickThrough(e, result);
243
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
244
+ _this.events[responseId].product[result.id].productClickThrough = true;
245
+ setTimeout(function () {
246
+ _this.events[responseId].product[result.id].productClickThrough = false;
247
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
248
+ }
249
+ },
250
+ impression: function (result) {
251
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
252
+ if (!result) {
253
+ _this.log.warn('No result provided to track.product.impression');
254
+ return;
255
+ }
256
+ var responseId = result.responseId;
257
+ if (!_this.events[responseId]) {
258
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
259
+ return;
260
+ }
261
+ else if ((_c = (_b = (_a = _this.events) === null || _a === void 0 ? void 0 : _a[responseId]) === null || _b === void 0 ? void 0 : _b.product[result.id]) === null || _c === void 0 ? void 0 : _c.impression) {
262
+ return;
263
+ }
264
+ var type = (['product', 'banner'].includes(result.type) ? result.type : 'product');
265
+ var item = __assign({ type: type, uid: result.id ? '' + result.id : '' }, (type === 'product'
266
+ ? {
267
+ parentId: ((_d = result.mappings.core) === null || _d === void 0 ? void 0 : _d.parentId) ? '' + ((_e = result.mappings.core) === null || _e === void 0 ? void 0 : _e.parentId) : '',
268
+ sku: ((_f = result.mappings.core) === null || _f === void 0 ? void 0 : _f.sku) ? '' + ((_g = result.mappings.core) === null || _g === void 0 ? void 0 : _g.sku) : undefined,
269
+ }
270
+ : {}));
271
+ var data = {
272
+ responseId: responseId,
273
+ results: [item],
274
+ banners: [],
275
+ };
276
+ _this.eventManager.fire('track.product.impression', { controller: _this, product: result, trackEvent: data });
277
+ ((_h = _this.config.beacon) === null || _h === void 0 ? void 0 : _h.enabled) && _this.tracker.events.autocomplete.impression({ data: data, siteId: (_j = _this.config.globals) === null || _j === void 0 ? void 0 : _j.siteId });
278
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
279
+ _this.events[responseId].product[result.id].impression = true;
280
+ },
281
+ addToCart: function (result) {
282
+ var _a, _b, _c, _d;
283
+ if (!result) {
284
+ _this.log.warn('No result provided to track.product.addToCart');
285
+ return;
286
+ }
287
+ var responseId = result.responseId;
288
+ if (!_this.events[responseId]) {
289
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
290
+ return;
291
+ }
292
+ var product = {
293
+ parentId: result.id,
294
+ uid: result.id,
295
+ sku: (_a = result.mappings.core) === null || _a === void 0 ? void 0 : _a.sku,
296
+ qty: result.quantity || 1,
297
+ price: Number((_b = result.mappings.core) === null || _b === void 0 ? void 0 : _b.price),
298
+ };
299
+ var data = {
300
+ responseId: responseId,
301
+ results: [product],
302
+ };
303
+ _this.eventManager.fire('track.product.addToCart', { controller: _this, product: result, trackEvent: data });
304
+ ((_c = _this.config.beacon) === null || _c === void 0 ? void 0 : _c.enabled) && _this.tracker.events.autocomplete.addToCart({ data: data, siteId: (_d = _this.config.globals) === null || _d === void 0 ? void 0 : _d.siteId });
305
+ },
306
+ },
307
+ redirect: function (_a) {
308
+ var _b, _c;
309
+ var redirectURL = _a.redirectURL, responseId = _a.responseId;
310
+ if (!redirectURL) {
311
+ _this.log.warn('No redirectURL provided to track.redirect');
312
+ return;
313
+ }
314
+ var data = {
315
+ responseId: responseId,
316
+ redirect: redirectURL,
317
+ };
318
+ _this.eventManager.fire('track.redirect', { controller: _this, redirectURL: redirectURL, trackEvent: data });
319
+ ((_b = _this.config.beacon) === null || _b === void 0 ? void 0 : _b.enabled) && _this.tracker.events.autocomplete.redirect({ data: data, siteId: (_c = _this.config.globals) === null || _c === void 0 ? void 0 : _c.siteId });
320
+ },
321
+ };
322
+ _this.handlers = {
323
+ input: {
324
+ enterKey: function (e) { return __awaiter(_this, void 0, void 0, function () {
325
+ var input, actionUrl, err_1;
326
+ return __generator(this, function (_a) {
327
+ switch (_a.label) {
328
+ case 0:
329
+ if (!(e.keyCode == KEY_ENTER)) return [3 /*break*/, 9];
330
+ input = e.target;
331
+ actionUrl = this.store.services.urlManager;
332
+ e.preventDefault();
333
+ _a.label = 1;
334
+ case 1:
335
+ if (!this.store.loading) return [3 /*break*/, 3];
336
+ return [4 /*yield*/, timeout(exports.INPUT_DELAY)];
337
+ case 2:
338
+ _a.sent();
339
+ return [3 /*break*/, 1];
340
+ case 3:
341
+ // set fallbackQuery to the correctedQuery
342
+ if (this.store.search.correctedQuery) {
343
+ actionUrl = actionUrl === null || actionUrl === void 0 ? void 0 : actionUrl.set(PARAM_FALLBACK_QUERY, this.store.search.correctedQuery.string);
344
+ }
345
+ actionUrl = actionUrl === null || actionUrl === void 0 ? void 0 : actionUrl.set('query', input.value);
346
+ // wait for input delay
347
+ return [4 /*yield*/, timeout(exports.INPUT_DELAY + 1)];
348
+ case 4:
349
+ // wait for input delay
350
+ _a.sent();
351
+ _a.label = 5;
352
+ case 5:
353
+ _a.trys.push([5, 7, , 8]);
354
+ return [4 /*yield*/, this.eventManager.fire('beforeSubmit', {
355
+ controller: this,
356
+ input: input,
357
+ })];
358
+ case 6:
359
+ _a.sent();
360
+ return [3 /*break*/, 8];
361
+ case 7:
362
+ err_1 = _a.sent();
363
+ if ((err_1 === null || err_1 === void 0 ? void 0 : err_1.message) == 'cancelled') {
364
+ this.log.warn("'beforeSubmit' middleware cancelled");
365
+ return [2 /*return*/];
366
+ }
367
+ else {
368
+ this.log.error("error in 'beforeSubmit' middleware");
369
+ console.error(err_1);
370
+ }
371
+ return [3 /*break*/, 8];
372
+ case 8:
373
+ window.location.href = (actionUrl === null || actionUrl === void 0 ? void 0 : actionUrl.href) || '';
374
+ _a.label = 9;
375
+ case 9: return [2 /*return*/];
376
+ }
377
+ });
378
+ }); },
379
+ escKey: function (e) {
380
+ if (e.keyCode == KEY_ESCAPE) {
381
+ e.target.blur();
382
+ _this.setFocused();
383
+ }
384
+ },
385
+ focus: function (e) {
386
+ e.stopPropagation();
387
+ // timeout to ensure focus happens AFTER click
388
+ setTimeout(function () {
389
+ _this.setFocused(e.target);
390
+ });
391
+ },
392
+ formSubmit: function (e) { return __awaiter(_this, void 0, void 0, function () {
393
+ var form, input, err_2;
394
+ return __generator(this, function (_a) {
395
+ switch (_a.label) {
396
+ case 0:
397
+ form = e.target;
398
+ input = form.querySelector("input[".concat(INPUT_ATTRIBUTE, "]"));
399
+ e.preventDefault();
400
+ _a.label = 1;
401
+ case 1:
402
+ if (!this.store.loading) return [3 /*break*/, 3];
403
+ return [4 /*yield*/, timeout(exports.INPUT_DELAY)];
404
+ case 2:
405
+ _a.sent();
406
+ return [3 /*break*/, 1];
407
+ case 3:
408
+ // set fallbackQuery to the correctedQuery
409
+ if (this.store.search.correctedQuery) {
410
+ addHiddenFormInput(form, PARAM_FALLBACK_QUERY, this.store.search.correctedQuery.string);
411
+ }
412
+ // wait for input delay
413
+ return [4 /*yield*/, timeout(exports.INPUT_DELAY + 1)];
414
+ case 4:
415
+ // wait for input delay
416
+ _a.sent();
417
+ _a.label = 5;
418
+ case 5:
419
+ _a.trys.push([5, 7, , 8]);
420
+ return [4 /*yield*/, this.eventManager.fire('beforeSubmit', {
421
+ controller: this,
422
+ input: input,
423
+ })];
424
+ case 6:
425
+ _a.sent();
426
+ return [3 /*break*/, 8];
427
+ case 7:
428
+ err_2 = _a.sent();
429
+ if ((err_2 === null || err_2 === void 0 ? void 0 : err_2.message) == 'cancelled') {
430
+ this.log.warn("'beforeSubmit' middleware cancelled");
431
+ return [2 /*return*/];
432
+ }
433
+ else {
434
+ this.log.error("error in 'beforeSubmit' middleware");
435
+ console.error(err_2);
436
+ }
437
+ return [3 /*break*/, 8];
438
+ case 8:
439
+ form.submit();
440
+ return [2 /*return*/];
441
+ }
442
+ });
443
+ }); },
444
+ formElementChange: function (e) {
445
+ var _a, _b, _c, _d, _e, _f, _g;
446
+ var input = e.target;
447
+ var form = input === null || input === void 0 ? void 0 : input.form;
448
+ var searchInput = form === null || form === void 0 ? void 0 : form.querySelector("input[".concat(INPUT_ATTRIBUTE, "]"));
449
+ if (form && searchInput && ((_a = _this.config.settings) === null || _a === void 0 ? void 0 : _a.serializeForm)) {
450
+ // get other form parameters (except the input)
451
+ var formParameters = getFormParameters(form, function (elem) {
452
+ return elem != searchInput;
453
+ });
454
+ // set parameters as globals
455
+ _this.store.setService('urlManager', _this.store.services.urlManager.reset().withGlobals(formParameters));
456
+ _this.store.reset();
457
+ // rebuild trending terms with new UrlManager settings
458
+ if (((_c = (_b = _this.config.settings) === null || _b === void 0 ? void 0 : _b.trending) === null || _c === void 0 ? void 0 : _c.enabled) && ((_e = (_d = _this.config.settings) === null || _d === void 0 ? void 0 : _d.trending) === null || _e === void 0 ? void 0 : _e.limit) && ((_g = (_f = _this.config.settings) === null || _f === void 0 ? void 0 : _f.trending) === null || _g === void 0 ? void 0 : _g.limit) > 0) {
459
+ _this.searchTrending();
460
+ }
461
+ }
462
+ },
463
+ input: function (e) {
464
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
465
+ // return focus on input if it was lost
466
+ if (e.isTrusted && _this.store.state.focusedInput !== e.target) {
467
+ _this.setFocused(e.target);
468
+ }
469
+ var value = e.target.value;
470
+ // prevent search when value is unchanged or empty
471
+ if (((!_this.store.state.input && !value) || _this.store.state.input == value) && _this.store.loaded) {
472
+ return;
473
+ }
474
+ _this.store.state.source = 'input';
475
+ _this.store.state.input = value;
476
+ // remove merch redirect to prevent race condition
477
+ _this.store.merchandising.redirect = '';
478
+ if ((_b = (_a = _this.config) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.syncInputs) {
479
+ var inputs = document.querySelectorAll(_this.config.selector);
480
+ inputs.forEach(function (input) {
481
+ input.value = value;
482
+ });
483
+ }
484
+ // TODO cancel any current requests?
485
+ clearTimeout(_this.handlers.input.timeoutDelay);
486
+ var trendingResultsEnabled = ((_c = _this.store.trending) === null || _c === void 0 ? void 0 : _c.length) && ((_e = (_d = _this.config.settings) === null || _d === void 0 ? void 0 : _d.trending) === null || _e === void 0 ? void 0 : _e.enabled) && ((_g = (_f = _this.config.settings) === null || _f === void 0 ? void 0 : _f.trending) === null || _g === void 0 ? void 0 : _g.showResults);
487
+ var historyResultsEnabled = ((_h = _this.store.history) === null || _h === void 0 ? void 0 : _h.length) && ((_k = (_j = _this.config.settings) === null || _j === void 0 ? void 0 : _j.history) === null || _k === void 0 ? void 0 : _k.enabled) && ((_m = (_l = _this.config.settings) === null || _l === void 0 ? void 0 : _l.history) === null || _m === void 0 ? void 0 : _m.showResults);
488
+ _this.handlers.input.timeoutDelay = setTimeout(function () {
489
+ if (!value) {
490
+ // there is no input value - reset state of store
491
+ _this.store.reset();
492
+ // show results for trending or history (if configured) - trending has priority
493
+ if (trendingResultsEnabled) {
494
+ _this.store.trending[0].preview();
495
+ }
496
+ else if (historyResultsEnabled) {
497
+ _this.store.history[0].preview();
498
+ }
499
+ else {
500
+ // no input - need to reset URL
501
+ _this.urlManager.reset().go();
502
+ }
503
+ }
504
+ else {
505
+ // new query in the input - trigger a new search via UrlManager
506
+ _this.store.state.locks.terms.unlock();
507
+ _this.store.state.locks.facets.unlock();
508
+ _this.urlManager.set({ query: _this.store.state.input }).go();
509
+ }
510
+ }, exports.INPUT_DELAY);
511
+ },
512
+ timeoutDelay: undefined,
513
+ },
514
+ document: {
515
+ click: function (e) {
516
+ var _a;
517
+ var inputs = document.querySelectorAll(_this.config.selector);
518
+ // if the click is on an input or a form with inputs, stop propagation
519
+ if (Array.from(inputs).includes(e.target) ||
520
+ (((_a = e.target) === null || _a === void 0 ? void 0 : _a.nodeName) == 'FORM' && e.target.querySelectorAll(_this.config.selector).length)) {
521
+ e.stopPropagation();
522
+ }
523
+ else {
524
+ _this.setFocused();
525
+ }
526
+ },
527
+ },
528
+ };
529
+ _this.searchTrending = function (options) { return __awaiter(_this, void 0, void 0, function () {
530
+ var trending, storedTerms, trendingParams, trendingProfile;
531
+ var _a, _b, _c;
532
+ return __generator(this, function (_d) {
533
+ switch (_d.label) {
534
+ case 0:
535
+ storedTerms = this.storage.get('terms');
536
+ if (!(storedTerms && !(options === null || options === void 0 ? void 0 : options.limit))) return [3 /*break*/, 1];
537
+ // terms exist in storage, update store
538
+ trending = JSON.parse(storedTerms);
539
+ return [3 /*break*/, 3];
540
+ case 1:
541
+ trendingParams = {
542
+ limit: (options === null || options === void 0 ? void 0 : options.limit) || ((_b = (_a = this.config.settings) === null || _a === void 0 ? void 0 : _a.trending) === null || _b === void 0 ? void 0 : _b.limit) || 5,
543
+ };
544
+ trendingProfile = this.profiler.create({ type: 'event', name: 'trending', context: trendingParams }).start();
545
+ return [4 /*yield*/, this.client.trending(trendingParams)];
546
+ case 2:
547
+ trending = _d.sent();
548
+ trendingProfile.stop();
549
+ this.log.profile(trendingProfile);
550
+ if ((_c = trending === null || trending === void 0 ? void 0 : trending.trending.queries) === null || _c === void 0 ? void 0 : _c.length) {
551
+ this.storage.set('terms', JSON.stringify(trending));
552
+ }
553
+ _d.label = 3;
554
+ case 3:
555
+ this.store.updateTrendingTerms(trending);
556
+ return [2 /*return*/];
557
+ }
558
+ });
559
+ }); };
560
+ _this.search = function () { return __awaiter(_this, void 0, void 0, function () {
561
+ var params, err_3, searchProfile, _a, meta, search, responseId_1, previousResponseId, impressedResultIds, afterSearchProfile, err_4, data, afterStoreProfile, err_5, err_6;
562
+ var _this = this;
563
+ var _b, _c, _d, _e, _f;
564
+ return __generator(this, function (_g) {
565
+ switch (_g.label) {
566
+ case 0:
567
+ _g.trys.push([0, 16, 17, 18]);
568
+ if (!!this.initialized) return [3 /*break*/, 2];
569
+ return [4 /*yield*/, this.init()];
570
+ case 1:
571
+ _g.sent();
572
+ _g.label = 2;
573
+ case 2:
574
+ // if urlManager has no query, there will be no need to get params and no query
575
+ if (!this.urlManager.state.query) {
576
+ return [2 /*return*/];
577
+ }
578
+ params = this.params;
579
+ // if params have no query do not search
580
+ 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)) {
581
+ return [2 /*return*/];
582
+ }
583
+ this.store.loading = true;
584
+ // clear the redirect URL until proper abort functionality is implemented
585
+ this.store.merchandising.redirect = '';
586
+ _g.label = 3;
587
+ case 3:
588
+ _g.trys.push([3, 5, , 6]);
589
+ return [4 /*yield*/, this.eventManager.fire('beforeSearch', {
590
+ controller: this,
591
+ request: params,
592
+ })];
593
+ case 4:
594
+ _g.sent();
595
+ return [3 /*break*/, 6];
596
+ case 5:
597
+ err_3 = _g.sent();
598
+ if ((err_3 === null || err_3 === void 0 ? void 0 : err_3.message) == 'cancelled') {
599
+ this.log.warn("'beforeSearch' middleware cancelled");
600
+ return [2 /*return*/];
601
+ }
602
+ else {
603
+ this.log.error("error in 'beforeSearch' middleware");
604
+ throw err_3;
605
+ }
606
+ return [3 /*break*/, 6];
607
+ case 6:
608
+ searchProfile = this.profiler.create({ type: 'event', name: 'search', context: params }).start();
609
+ return [4 /*yield*/, this.client.autocomplete(params)];
610
+ case 7:
611
+ _a = _g.sent(), meta = _a.meta, search = _a.search;
612
+ searchProfile.stop();
613
+ this.log.profile(searchProfile);
614
+ responseId_1 = search.tracking.responseId;
615
+ this.events[responseId_1] = this.events[responseId_1] || { product: {}, banner: {} };
616
+ previousResponseId = (_d = this.store.results[0]) === null || _d === void 0 ? void 0 : _d.responseId;
617
+ if (previousResponseId && previousResponseId === responseId_1) {
618
+ impressedResultIds = Object.keys(this.events[responseId_1].product || {}).filter(function (resultId) { var _a, _b; return (_b = (_a = _this.events[responseId_1].product) === null || _a === void 0 ? void 0 : _a[resultId]) === null || _b === void 0 ? void 0 : _b.impression; });
619
+ this.events[responseId_1] = {
620
+ product: impressedResultIds.reduce(function (acc, resultId) {
621
+ acc[resultId] = { impression: true };
622
+ return acc;
623
+ }, {}),
624
+ banner: this.events[responseId_1].banner,
625
+ };
626
+ }
627
+ else {
628
+ this.events[responseId_1] = { product: {}, banner: {} };
629
+ }
630
+ afterSearchProfile = this.profiler.create({ type: 'event', name: 'afterSearch', context: params }).start();
631
+ _g.label = 8;
632
+ case 8:
633
+ _g.trys.push([8, 10, , 11]);
634
+ return [4 /*yield*/, this.eventManager.fire('afterSearch', {
635
+ controller: this,
636
+ request: params,
637
+ response: {
638
+ meta: meta,
639
+ search: search,
640
+ },
641
+ })];
642
+ case 9:
643
+ _g.sent();
644
+ return [3 /*break*/, 11];
645
+ case 10:
646
+ err_4 = _g.sent();
647
+ if ((err_4 === null || err_4 === void 0 ? void 0 : err_4.message) == 'cancelled') {
648
+ this.log.warn("'afterSearch' middleware cancelled");
649
+ afterSearchProfile.stop();
650
+ return [2 /*return*/];
651
+ }
652
+ else {
653
+ this.log.error("error in 'afterSearch' middleware");
654
+ throw err_4;
655
+ }
656
+ return [3 /*break*/, 11];
657
+ case 11:
658
+ afterSearchProfile.stop();
659
+ this.log.profile(afterSearchProfile);
660
+ // update the store
661
+ this.store.update({ meta: meta, search: search });
662
+ data = { responseId: responseId_1 };
663
+ ((_e = this.config.beacon) === null || _e === void 0 ? void 0 : _e.enabled) && this.tracker.events.autocomplete.render({ data: data, siteId: (_f = this.config.globals) === null || _f === void 0 ? void 0 : _f.siteId });
664
+ afterStoreProfile = this.profiler.create({ type: 'event', name: 'afterStore', context: params }).start();
665
+ _g.label = 12;
666
+ case 12:
667
+ _g.trys.push([12, 14, , 15]);
668
+ return [4 /*yield*/, this.eventManager.fire('afterStore', {
669
+ controller: this,
670
+ request: params,
671
+ response: {
672
+ meta: meta,
673
+ search: search,
674
+ },
675
+ })];
676
+ case 13:
677
+ _g.sent();
678
+ return [3 /*break*/, 15];
679
+ case 14:
680
+ err_5 = _g.sent();
681
+ if ((err_5 === null || err_5 === void 0 ? void 0 : err_5.message) == 'cancelled') {
682
+ this.log.warn("'afterStore' middleware cancelled");
683
+ afterStoreProfile.stop();
684
+ return [2 /*return*/];
685
+ }
686
+ else {
687
+ this.log.error("error in 'afterStore' middleware");
688
+ throw err_5;
689
+ }
690
+ return [3 /*break*/, 15];
691
+ case 15:
692
+ afterStoreProfile.stop();
693
+ this.log.profile(afterStoreProfile);
694
+ return [3 /*break*/, 18];
695
+ case 16:
696
+ err_6 = _g.sent();
697
+ if (err_6) {
698
+ if (err_6.err && err_6.fetchDetails) {
699
+ switch (err_6.fetchDetails.status) {
700
+ case 429: {
701
+ this.store.error = {
702
+ code: 429,
703
+ type: snap_store_mobx_1.ErrorType.WARNING,
704
+ message: 'Too many requests try again later',
705
+ };
706
+ break;
707
+ }
708
+ case 500: {
709
+ this.store.error = {
710
+ code: 500,
711
+ type: snap_store_mobx_1.ErrorType.ERROR,
712
+ message: 'Invalid Search Request or Service Unavailable',
713
+ };
714
+ break;
715
+ }
716
+ default: {
717
+ this.store.error = {
718
+ type: snap_store_mobx_1.ErrorType.ERROR,
719
+ message: err_6.err.message,
720
+ };
721
+ break;
722
+ }
723
+ }
724
+ this.log.error(this.store.error);
725
+ this.handleError(err_6.err, err_6.fetchDetails);
726
+ }
727
+ else {
728
+ this.store.error = {
729
+ type: snap_store_mobx_1.ErrorType.ERROR,
730
+ message: "Something went wrong... - ".concat(err_6),
731
+ };
732
+ this.log.error(err_6);
733
+ this.handleError(err_6);
734
+ }
735
+ }
736
+ return [3 /*break*/, 18];
737
+ case 17:
738
+ this.store.loading = false;
739
+ return [7 /*endfinally*/];
740
+ case 18: return [2 /*return*/];
741
+ }
742
+ });
743
+ }); };
744
+ _this.addToCart = function (_products) { return __awaiter(_this, void 0, void 0, function () {
745
+ var products;
746
+ var _this = this;
747
+ return __generator(this, function (_a) {
748
+ products = typeof (_products === null || _products === void 0 ? void 0 : _products.slice) == 'function' ? _products.slice() : [_products];
749
+ if (!_products || products.length === 0) {
750
+ this.log.warn('No products provided to autocomplete controller.addToCart');
751
+ return [2 /*return*/];
752
+ }
753
+ products.forEach(function (product) {
754
+ _this.track.product.addToCart(product);
755
+ });
756
+ if (products.length > 0) {
757
+ this.eventManager.fire('addToCart', { controller: this, products: products });
758
+ }
759
+ return [2 /*return*/];
760
+ });
761
+ }); };
762
+ // deep merge config with defaults
763
+ _this.config = (0, deepmerge_1.default)(defaultConfig, _this.config);
764
+ // normalize trending config (old method requires only a limit to be set)
765
+ if (((_c = (_b = _this.config.settings) === null || _b === void 0 ? void 0 : _b.trending) === null || _c === void 0 ? void 0 : _c.limit) && typeof ((_e = (_d = _this.config.settings) === null || _d === void 0 ? void 0 : _d.trending) === null || _e === void 0 ? void 0 : _e.enabled) === 'undefined') {
766
+ _this.config.settings = __assign(__assign({}, _this.config.settings), { trending: __assign({ enabled: true }, _this.config.settings.trending) });
767
+ }
768
+ // normalize history config (old method requires only a limit to be set)
769
+ if (((_g = (_f = _this.config.settings) === null || _f === void 0 ? void 0 : _f.history) === null || _g === void 0 ? void 0 : _g.limit) && typeof ((_j = (_h = _this.config.settings) === null || _h === void 0 ? void 0 : _h.history) === null || _j === void 0 ? void 0 : _j.enabled) === 'undefined') {
770
+ _this.config.settings = __assign(__assign({}, _this.config.settings), { history: __assign({ enabled: true }, _this.config.settings.history) });
771
+ }
772
+ _this.store.setConfig(_this.config);
773
+ // get current search from url before detaching
774
+ if (_this.config.settings.initializeFromUrl) {
775
+ _this.store.state.input = _this.urlManager.state.query;
776
+ // reset to force search on focus
777
+ // TODO: make a config setting for this
778
+ _this.urlManager.reset().go();
779
+ }
780
+ // persist trending terms in local storage
781
+ _this.storage = new snap_store_mobx_1.StorageStore({
782
+ type: 'session',
783
+ key: "athos-controller-".concat(_this.config.id),
784
+ });
785
+ // add 'afterSearch' middleware
786
+ _this.eventManager.on('afterSearch', function (ac, next) { return __awaiter(_this, void 0, void 0, function () {
787
+ var _a;
788
+ return __generator(this, function (_b) {
789
+ switch (_b.label) {
790
+ case 0: return [4 /*yield*/, next()];
791
+ case 1:
792
+ _b.sent();
793
+ // cancel search if no input or query doesn't match current urlState
794
+ if (((_a = ac.response.search.autocomplete) === null || _a === void 0 ? void 0 : _a.query) != ac.controller.urlManager.state.query) {
795
+ return [2 /*return*/, false];
796
+ }
797
+ return [2 /*return*/];
798
+ }
799
+ });
800
+ }); });
801
+ _this.eventManager.on('beforeSubmit', function (ac, next) { return __awaiter(_this, void 0, void 0, function () {
802
+ var loading, inputState, redirectURL, results, filteredResults, singleResultUrl;
803
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
804
+ return __generator(this, function (_k) {
805
+ switch (_k.label) {
806
+ case 0: return [4 /*yield*/, next()];
807
+ case 1:
808
+ _k.sent();
809
+ loading = ac.controller.store.loading;
810
+ if (loading)
811
+ return [2 /*return*/];
812
+ inputState = ac.controller.store.state.input;
813
+ redirectURL = (_a = ac.controller.store.merchandising) === null || _a === void 0 ? void 0 : _a.redirect;
814
+ if (((_d = (_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.settings) === null || _c === void 0 ? void 0 : _c.redirects) === null || _d === void 0 ? void 0 : _d.merchandising) && inputState && redirectURL) {
815
+ this.track.redirect({ redirectURL: redirectURL, responseId: (_e = ac.controller.store.merchandising) === null || _e === void 0 ? void 0 : _e.responseId });
816
+ window.location.href = redirectURL;
817
+ return [2 /*return*/, false];
818
+ }
819
+ if ((_h = (_g = (_f = this.config) === null || _f === void 0 ? void 0 : _f.settings) === null || _g === void 0 ? void 0 : _g.redirects) === null || _h === void 0 ? void 0 : _h.singleResult) {
820
+ results = ac.controller.store.results;
821
+ filteredResults = results.filter(function (result) { return result.type == 'product'; });
822
+ singleResultUrl = filteredResults.length === 1 && ((_j = filteredResults[0].mappings.core) === null || _j === void 0 ? void 0 : _j.url);
823
+ if (singleResultUrl) {
824
+ window.location.href = singleResultUrl;
825
+ return [2 /*return*/, false];
826
+ }
827
+ }
828
+ return [2 /*return*/];
829
+ }
830
+ });
831
+ }); });
832
+ // attach config plugins and event middleware
833
+ _this.use(_this.config);
834
+ return _this;
835
+ }
836
+ Object.defineProperty(AutocompleteController.prototype, "params", {
837
+ get: function () {
838
+ var _a, _b;
839
+ var urlState = this.urlManager.state;
840
+ var params = (0, deepmerge_1.default)(__assign({}, (0, getParams_1.getSearchParams)(urlState)), this.config.globals || {});
841
+ var _c = this.tracker.getContext(), userId = _c.userId, sessionId = _c.sessionId, pageLoadId = _c.pageLoadId, shopperId = _c.shopperId;
842
+ params.tracking = params.tracking || {};
843
+ params.tracking.domain = window.location.href;
844
+ if (userId) {
845
+ params.tracking.userId = userId;
846
+ }
847
+ if (sessionId) {
848
+ params.tracking.sessionId = sessionId;
849
+ }
850
+ if (pageLoadId) {
851
+ params.tracking.pageLoadId = pageLoadId;
852
+ }
853
+ if (this.store.state.input) {
854
+ params.search = params.search || {};
855
+ params.search.input = this.store.state.input;
856
+ }
857
+ if (this.store.state.source) {
858
+ params.search = params.search || {};
859
+ params.search.source = this.store.state.source;
860
+ }
861
+ if (!((_b = (_a = this.config.globals) === null || _a === void 0 ? void 0 : _a.personalization) === null || _b === void 0 ? void 0 : _b.disabled)) {
862
+ var cartItems = this.tracker.cookies.cart.get();
863
+ if (cartItems.length) {
864
+ params.personalization = params.personalization || {};
865
+ params.personalization.cart = cartItems.join(',');
866
+ }
867
+ var lastViewedItems = this.tracker.cookies.viewed.get();
868
+ if (lastViewedItems.length) {
869
+ params.personalization = params.personalization || {};
870
+ params.personalization.lastViewed = lastViewedItems.join(',');
871
+ }
872
+ if (shopperId) {
873
+ params.personalization = params.personalization || {};
874
+ params.personalization.shopper = shopperId;
875
+ }
876
+ }
877
+ return params;
878
+ },
879
+ enumerable: false,
880
+ configurable: true
881
+ });
882
+ AutocompleteController.prototype.setFocused = function (inputElement) {
883
+ return __awaiter(this, void 0, void 0, function () {
884
+ var err_7, err_8;
885
+ return __generator(this, function (_a) {
886
+ switch (_a.label) {
887
+ case 0:
888
+ if (!(this.store.state.focusedInput !== inputElement)) return [3 /*break*/, 7];
889
+ this.store.state.focusedInput = inputElement;
890
+ _a.label = 1;
891
+ case 1:
892
+ _a.trys.push([1, 6, , 7]);
893
+ _a.label = 2;
894
+ case 2:
895
+ _a.trys.push([2, 4, , 5]);
896
+ return [4 /*yield*/, this.eventManager.fire('focusChange', {
897
+ controller: this,
898
+ })];
899
+ case 3:
900
+ _a.sent();
901
+ return [3 /*break*/, 5];
902
+ case 4:
903
+ err_7 = _a.sent();
904
+ if ((err_7 === null || err_7 === void 0 ? void 0 : err_7.message) == 'cancelled') {
905
+ this.log.warn("'focusChange' middleware cancelled");
906
+ }
907
+ else {
908
+ this.log.error("error in 'focusChange' middleware");
909
+ throw err_7;
910
+ }
911
+ return [3 /*break*/, 5];
912
+ case 5: return [3 /*break*/, 7];
913
+ case 6:
914
+ err_8 = _a.sent();
915
+ if (err_8) {
916
+ console.error(err_8);
917
+ }
918
+ return [3 /*break*/, 7];
919
+ case 7:
920
+ inputElement === null || inputElement === void 0 ? void 0 : inputElement.dispatchEvent(new Event('input'));
921
+ return [2 /*return*/];
922
+ }
923
+ });
924
+ });
925
+ };
926
+ AutocompleteController.prototype.reset = function () {
927
+ // reset input values and state
928
+ var inputs = document.querySelectorAll(this.config.selector);
929
+ inputs.forEach(function (input) {
930
+ input.value = '';
931
+ });
932
+ this.store.reset();
933
+ };
934
+ AutocompleteController.prototype.unbind = function () {
935
+ var _this = this;
936
+ var inputs = document.querySelectorAll("input[".concat(INPUT_ATTRIBUTE, "]"));
937
+ inputs === null || inputs === void 0 ? void 0 : inputs.forEach(function (input) {
938
+ input.removeEventListener('input', _this.handlers.input.input);
939
+ input.removeEventListener('keydown', _this.handlers.input.enterKey);
940
+ input.removeEventListener('keydown', _this.handlers.input.escKey);
941
+ input.removeEventListener('focus', _this.handlers.input.focus);
942
+ if (input.form) {
943
+ input.form.removeEventListener('submit', _this.handlers.input.formSubmit);
944
+ unbindFormParameters(input.form, _this.handlers.input.formElementChange);
945
+ }
946
+ });
947
+ document.removeEventListener('click', this.handlers.document.click);
948
+ };
949
+ AutocompleteController.prototype.bind = function () {
950
+ return __awaiter(this, void 0, void 0, function () {
951
+ var inputs;
952
+ var _this = this;
953
+ var _a, _b, _c, _d, _e, _f, _g, _h;
954
+ return __generator(this, function (_j) {
955
+ switch (_j.label) {
956
+ case 0:
957
+ if (!!this.initialized) return [3 /*break*/, 2];
958
+ return [4 /*yield*/, this.init()];
959
+ case 1:
960
+ _j.sent();
961
+ _j.label = 2;
962
+ case 2:
963
+ this.unbind();
964
+ inputs = document.querySelectorAll(this.config.selector);
965
+ inputs.forEach(function (input) {
966
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
967
+ input.setAttribute('spellcheck', 'false');
968
+ input.setAttribute('autocomplete', 'off');
969
+ input.setAttribute('autocorrect', 'off');
970
+ input.setAttribute('autocapitalize', 'none');
971
+ input.setAttribute(INPUT_ATTRIBUTE, '');
972
+ ((_b = (_a = _this.config.settings) === null || _a === void 0 ? void 0 : _a.bind) === null || _b === void 0 ? void 0 : _b.input) && input.addEventListener('input', _this.handlers.input.input);
973
+ if (((_d = (_c = _this.config) === null || _c === void 0 ? void 0 : _c.settings) === null || _d === void 0 ? void 0 : _d.initializeFromUrl) && !input.value && _this.store.state.input) {
974
+ input.value = _this.store.state.input;
975
+ }
976
+ input.addEventListener('focus', _this.handlers.input.focus);
977
+ input.addEventListener('keydown', _this.handlers.input.escKey);
978
+ var form = input.form;
979
+ var formActionUrl;
980
+ if (_this.config.action) {
981
+ ((_f = (_e = _this.config.settings) === null || _e === void 0 ? void 0 : _e.bind) === null || _f === void 0 ? void 0 : _f.submit) && input.addEventListener('keydown', _this.handlers.input.enterKey);
982
+ formActionUrl = _this.config.action;
983
+ }
984
+ else if (form) {
985
+ ((_h = (_g = _this.config.settings) === null || _g === void 0 ? void 0 : _g.bind) === null || _h === void 0 ? void 0 : _h.submit) && form.addEventListener('submit', _this.handlers.input.formSubmit);
986
+ formActionUrl = form.action || '';
987
+ // serializeForm will include additional form element in our urlManager as globals
988
+ if ((_j = _this.config.settings) === null || _j === void 0 ? void 0 : _j.serializeForm) {
989
+ bindFormParameters(form, _this.handlers.input.formElementChange, function (elem) {
990
+ return elem != input;
991
+ });
992
+ var formParameters = getFormParameters(form, function (elem) {
993
+ return elem != input;
994
+ });
995
+ // set parameters as globals
996
+ _this.store.setService('urlManager', _this.urlManager.reset().withGlobals(formParameters));
997
+ }
998
+ }
999
+ // set the root URL on urlManager
1000
+ if (formActionUrl) {
1001
+ _this.store.setService('urlManager', _this.store.services.urlManager.withConfig(function (translatorConfig) {
1002
+ return __assign(__assign({}, translatorConfig), { urlRoot: formActionUrl });
1003
+ }));
1004
+ }
1005
+ // if the input is currently focused, trigger setFocues which will eventually trigger input - but not if loading
1006
+ if (document.activeElement === input && !_this.store.loading) {
1007
+ _this.setFocused(input);
1008
+ }
1009
+ });
1010
+ // get trending terms - this is at the bottom because urlManager changes need to be in place before creating the store
1011
+ if (((_b = (_a = this.config.settings) === null || _a === void 0 ? void 0 : _a.trending) === null || _b === void 0 ? void 0 : _b.enabled) &&
1012
+ ((_d = (_c = this.config.settings) === null || _c === void 0 ? void 0 : _c.trending) === null || _d === void 0 ? void 0 : _d.limit) &&
1013
+ ((_f = (_e = this.config.settings) === null || _e === void 0 ? void 0 : _e.trending) === null || _f === void 0 ? void 0 : _f.limit) > 0 &&
1014
+ !((_g = this.store.trending) === null || _g === void 0 ? void 0 : _g.length)) {
1015
+ this.searchTrending();
1016
+ }
1017
+ // if we are not preventing via `disableClickOutside` setting
1018
+ if (!((_h = this.config.settings) === null || _h === void 0 ? void 0 : _h.disableClickOutside)) {
1019
+ document.addEventListener('click', this.handlers.document.click);
1020
+ }
1021
+ return [2 /*return*/];
1022
+ }
1023
+ });
1024
+ });
1025
+ };
1026
+ return AutocompleteController;
1027
+ }(AbstractController_1.AbstractController));
1028
+ exports.AutocompleteController = AutocompleteController;
1029
+ function addHiddenFormInput(form, name, value) {
1030
+ var _a;
1031
+ var inputElem = document.createElement('input');
1032
+ inputElem.type = 'hidden';
1033
+ inputElem.name = name;
1034
+ inputElem.value = value;
1035
+ // remove existing form element if it exists (prevent duplicates)
1036
+ (_a = form.querySelector("[type=\"hidden\"][name=\"".concat(name, "\"]"))) === null || _a === void 0 ? void 0 : _a.remove();
1037
+ // append form element
1038
+ form.append(inputElem);
1039
+ }
1040
+ function timeout(time) {
1041
+ return __awaiter(this, void 0, void 0, function () {
1042
+ return __generator(this, function (_a) {
1043
+ return [2 /*return*/, new Promise(function (resolve) {
1044
+ window.setTimeout(resolve, time);
1045
+ })];
1046
+ });
1047
+ });
1048
+ }
1049
+ // for grabbing other parameters from the form and using them in UrlManager
1050
+ var INPUT_TYPE_BLOCKLIST = ['file', 'reset', 'submit', 'button', 'image', 'password'];
1051
+ function getFormParameters(form, filterFn) {
1052
+ var parameters = {};
1053
+ if (typeof form == 'object' && form.nodeName == 'FORM') {
1054
+ for (var i = form.elements.length - 1; i >= 0; i--) {
1055
+ var elem = form.elements[i];
1056
+ if (typeof filterFn == 'function' && !filterFn(elem)) {
1057
+ continue;
1058
+ }
1059
+ if (elem.name && !INPUT_TYPE_BLOCKLIST.includes(elem.type)) {
1060
+ if ((elem.type != 'checkbox' && elem.type != 'radio') || elem.checked) {
1061
+ parameters[elem.name] = elem.value;
1062
+ }
1063
+ }
1064
+ }
1065
+ }
1066
+ return parameters;
1067
+ }
1068
+ // this picks up changes to the form
1069
+ function bindFormParameters(form, fn, filterFn) {
1070
+ if (typeof form == 'object' && form.nodeName == 'FORM') {
1071
+ for (var i = form.elements.length - 1; i >= 0; i--) {
1072
+ var elem = form.elements[i];
1073
+ if (typeof filterFn == 'function' && !filterFn(elem)) {
1074
+ continue;
1075
+ }
1076
+ if (elem.name && !INPUT_TYPE_BLOCKLIST.includes(elem.type)) {
1077
+ elem.addEventListener('change', fn);
1078
+ }
1079
+ }
1080
+ }
1081
+ }
1082
+ function unbindFormParameters(form, fn) {
1083
+ if (typeof form == 'object' && form.nodeName == 'FORM') {
1084
+ for (var i = form.elements.length - 1; i >= 0; i--) {
1085
+ var elem = form.elements[i];
1086
+ if (elem.name && !INPUT_TYPE_BLOCKLIST.includes(elem.type)) {
1087
+ elem.removeEventListener('change', fn);
1088
+ }
1089
+ }
1090
+ }
1091
+ }