@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,993 @@
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 __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
65
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
66
+ if (ar || !(i in from)) {
67
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
68
+ ar[i] = from[i];
69
+ }
70
+ }
71
+ return to.concat(ar || Array.prototype.slice.call(from));
72
+ };
73
+ var __importDefault = (this && this.__importDefault) || function (mod) {
74
+ return (mod && mod.__esModule) ? mod : { "default": mod };
75
+ };
76
+ Object.defineProperty(exports, "__esModule", { value: true });
77
+ exports.SearchController = void 0;
78
+ exports.getStorableRequestParams = getStorableRequestParams;
79
+ exports.generateHrefSelector = generateHrefSelector;
80
+ var deepmerge_1 = __importDefault(require("deepmerge"));
81
+ var css_escape_1 = __importDefault(require("css.escape"));
82
+ var AbstractController_1 = require("../Abstract/AbstractController");
83
+ var snap_store_mobx_1 = require("@athoscommerce/snap-store-mobx");
84
+ var getParams_1 = require("../utils/getParams");
85
+ var types_1 = require("../types");
86
+ var isClickWithinProductLink_1 = require("../utils/isClickWithinProductLink");
87
+ var isClickWithinBannerLink_1 = require("../utils/isClickWithinBannerLink");
88
+ var BACKGROUND_FILTER_FIELD_MATCHES = ['collection', 'category', 'categories', 'hierarchy', 'brand', 'manufacturer'];
89
+ var BACKGROUND_FILTERS_VALUE_FLAGS = [1, 0, '1', '0', 'true', 'false', true, false];
90
+ var defaultConfig = {
91
+ id: 'search',
92
+ globals: {},
93
+ beacon: {
94
+ enabled: true,
95
+ },
96
+ settings: {
97
+ redirects: {
98
+ merchandising: true,
99
+ singleResult: true,
100
+ },
101
+ facets: {
102
+ trim: true,
103
+ pinFiltered: true,
104
+ storeRange: true,
105
+ autoOpenActive: true,
106
+ },
107
+ },
108
+ };
109
+ var SearchController = /** @class */ (function (_super) {
110
+ __extends(SearchController, _super);
111
+ function SearchController(config, _a, context) {
112
+ var client = _a.client, store = _a.store, urlManager = _a.urlManager, eventManager = _a.eventManager, profiler = _a.profiler, logger = _a.logger, tracker = _a.tracker;
113
+ var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
114
+ var _this = _super.call(this, config, { client: client, store: store, urlManager: urlManager, eventManager: eventManager, profiler: profiler, logger: logger, tracker: tracker }, context) || this;
115
+ _this.type = types_1.ControllerTypes.search;
116
+ _this.previousResults = [];
117
+ _this.page = {
118
+ type: 'search',
119
+ };
120
+ _this.events = {};
121
+ _this.track = {
122
+ banner: {
123
+ impression: function (_a) {
124
+ var _b, _c, _d, _e;
125
+ var uid = _a.uid, responseId = _a.responseId;
126
+ if (!uid) {
127
+ _this.log.warn('No banner provided to track.banner.impression');
128
+ return;
129
+ }
130
+ if (!_this.events[responseId]) {
131
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
132
+ return;
133
+ }
134
+ else if ((_c = (_b = _this.events[responseId]) === null || _b === void 0 ? void 0 : _b.banner[uid]) === null || _c === void 0 ? void 0 : _c.impression) {
135
+ return;
136
+ }
137
+ var banner = { uid: uid };
138
+ var data = {
139
+ responseId: responseId,
140
+ banners: [banner],
141
+ results: [],
142
+ };
143
+ _this.eventManager.fire('track.banner.impression', { controller: _this, product: { uid: uid }, trackEvent: data });
144
+ ((_d = _this.config.beacon) === null || _d === void 0 ? void 0 : _d.enabled) && _this.tracker.events[_this.page.type].impression({ data: data, siteId: (_e = _this.config.globals) === null || _e === void 0 ? void 0 : _e.siteId });
145
+ _this.events[responseId].banner[uid] = _this.events[responseId].banner[uid] || {};
146
+ _this.events[responseId].banner[uid].impression = true;
147
+ },
148
+ click: function (e, banner) {
149
+ var _a, _b, _c;
150
+ if (!banner) {
151
+ _this.log.warn('No banner provided to track.banner.click');
152
+ return;
153
+ }
154
+ var responseId = banner.responseId, uid = banner.uid;
155
+ if (!_this.events[responseId]) {
156
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
157
+ return;
158
+ }
159
+ if ((0, isClickWithinBannerLink_1.isClickWithinBannerLink)(e)) {
160
+ 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) {
161
+ return;
162
+ }
163
+ _this.track.banner.clickThrough(e, banner);
164
+ _this.events[responseId].banner[uid] = _this.events[responseId].banner[uid] || {};
165
+ _this.events[responseId].banner[uid].clickThrough = true;
166
+ setTimeout(function () {
167
+ _this.events[responseId].banner[uid].clickThrough = false;
168
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
169
+ }
170
+ },
171
+ clickThrough: function (e, _a) {
172
+ var _b, _c;
173
+ var uid = _a.uid, responseId = _a.responseId;
174
+ if (!uid) {
175
+ _this.log.warn('No banner provided to track.banner.clickThrough');
176
+ return;
177
+ }
178
+ if (!_this.events[responseId]) {
179
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
180
+ return;
181
+ }
182
+ var banner = { uid: uid };
183
+ var data = {
184
+ responseId: responseId,
185
+ banners: [banner],
186
+ };
187
+ _this.eventManager.fire('track.banner.clickThrough', { controller: _this, event: e, product: { uid: uid }, trackEvent: data });
188
+ ((_b = _this.config.beacon) === null || _b === void 0 ? void 0 : _b.enabled) && _this.tracker.events[_this.page.type].clickThrough({ data: data, siteId: (_c = _this.config.globals) === null || _c === void 0 ? void 0 : _c.siteId });
189
+ _this.events[responseId].banner[uid] = _this.events[responseId].banner[uid] || {};
190
+ _this.events[responseId].banner[uid].clickThrough = true;
191
+ setTimeout(function () {
192
+ _this.events[responseId].banner[uid].clickThrough = false;
193
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
194
+ },
195
+ },
196
+ product: {
197
+ clickThrough: function (e, result) {
198
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
199
+ if (!result) {
200
+ _this.log.warn('No result provided to track.product.clickThrough');
201
+ return;
202
+ }
203
+ var responseId = result.responseId;
204
+ if (!_this.events[responseId]) {
205
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
206
+ return;
207
+ }
208
+ var target = e.target;
209
+ var resultHref = ((_b = (_a = result.display) === null || _a === void 0 ? void 0 : _a.mappings.core) === null || _b === void 0 ? void 0 : _b.url) || ((_c = result.mappings.core) === null || _c === void 0 ? void 0 : _c.url) || '';
210
+ var elemHref = target === null || target === void 0 ? void 0 : target.getAttribute('href');
211
+ // the href that should be used for restoration - if the elemHref contains the resultHref - use resultHref
212
+ var storedHref = (elemHref === null || elemHref === void 0 ? void 0 : elemHref.indexOf(resultHref)) != -1 ? resultHref : elemHref || resultHref;
213
+ var scrollMap = {};
214
+ // generate the selector using element class and parent classes
215
+ var selector = generateHrefSelector(target, storedHref);
216
+ var domRect = selector ? (_d = document === null || document === void 0 ? void 0 : document.querySelector(selector)) === null || _d === void 0 ? void 0 : _d.getBoundingClientRect() : undefined;
217
+ // store element position data to scrollMap
218
+ if (selector || storedHref || domRect) {
219
+ try {
220
+ var lastRequest = _this.storage.get('lastStringyParams');
221
+ if (lastRequest) {
222
+ var storableRequestParams = getStorableRequestParams(JSON.parse(lastRequest));
223
+ var storableStringyParams = JSON.stringify(storableRequestParams);
224
+ scrollMap[storableStringyParams] = { domRect: domRect, href: storedHref, selector: selector };
225
+ }
226
+ }
227
+ catch (err) {
228
+ // failed to get lastStringParams
229
+ _this.log.warn('Failed to save srcollMap!', err);
230
+ }
231
+ }
232
+ // store position data or empty object
233
+ _this.storage.set('scrollMap', scrollMap);
234
+ var type = (['product', 'banner'].includes(result.type) ? result.type : 'product');
235
+ var item = __assign({ type: type, uid: result.id ? '' + result.id : '' }, (type === 'product'
236
+ ? {
237
+ parentId: ((_e = result.mappings.core) === null || _e === void 0 ? void 0 : _e.parentId) ? '' + ((_f = result.mappings.core) === null || _f === void 0 ? void 0 : _f.parentId) : '',
238
+ sku: ((_g = result.mappings.core) === null || _g === void 0 ? void 0 : _g.sku) ? '' + ((_h = result.mappings.core) === null || _h === void 0 ? void 0 : _h.sku) : undefined,
239
+ }
240
+ : {}));
241
+ var data = {
242
+ responseId: responseId,
243
+ results: [item],
244
+ };
245
+ _this.eventManager.fire('track.product.clickThrough', { controller: _this, event: e, product: result, trackEvent: data });
246
+ ((_j = _this.config.beacon) === null || _j === void 0 ? void 0 : _j.enabled) && _this.tracker.events[_this.page.type].clickThrough({ data: data, siteId: (_k = _this.config.globals) === null || _k === void 0 ? void 0 : _k.siteId });
247
+ },
248
+ click: function (e, result) {
249
+ var _a, _b, _c, _d, _e, _f;
250
+ if (!result) {
251
+ _this.log.warn('No result provided to track.product.click');
252
+ return;
253
+ }
254
+ var responseId = result.responseId;
255
+ if (!_this.events[responseId]) {
256
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
257
+ return;
258
+ }
259
+ if (result.type === 'banner' && (0, isClickWithinBannerLink_1.isClickWithinBannerLink)(e)) {
260
+ 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) {
261
+ return;
262
+ }
263
+ _this.track.product.clickThrough(e, result);
264
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
265
+ _this.events[responseId].product[result.id].inlineBannerClickThrough = true;
266
+ setTimeout(function () {
267
+ _this.events[responseId].product[result.id].inlineBannerClickThrough = false;
268
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
269
+ }
270
+ else if ((0, isClickWithinProductLink_1.isClickWithinProductLink)(e, result)) {
271
+ 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) {
272
+ return;
273
+ }
274
+ _this.track.product.clickThrough(e, result);
275
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
276
+ _this.events[responseId].product[result.id].productClickThrough = true;
277
+ setTimeout(function () {
278
+ _this.events[responseId].product[result.id].productClickThrough = false;
279
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
280
+ }
281
+ },
282
+ impression: function (result) {
283
+ var _a, _b, _c, _d, _e, _f, _g, _h;
284
+ if (!result) {
285
+ _this.log.warn('No result provided to track.product.impression');
286
+ return;
287
+ }
288
+ var responseId = result.responseId;
289
+ if (!_this.events[responseId]) {
290
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
291
+ return;
292
+ }
293
+ else if ((_b = (_a = _this.events[responseId]) === null || _a === void 0 ? void 0 : _a.product[result.id]) === null || _b === void 0 ? void 0 : _b.impression) {
294
+ return;
295
+ }
296
+ var type = (['product', 'banner'].includes(result.type) ? result.type : 'product');
297
+ var item = __assign({ type: type, uid: result.id ? '' + result.id : '' }, (type === 'product'
298
+ ? {
299
+ parentId: ((_c = result.mappings.core) === null || _c === void 0 ? void 0 : _c.parentId) ? '' + ((_d = result.mappings.core) === null || _d === void 0 ? void 0 : _d.parentId) : '',
300
+ sku: ((_e = result.mappings.core) === null || _e === void 0 ? void 0 : _e.sku) ? '' + ((_f = result.mappings.core) === null || _f === void 0 ? void 0 : _f.sku) : undefined,
301
+ }
302
+ : {}));
303
+ var data = {
304
+ responseId: responseId,
305
+ results: [item],
306
+ banners: [],
307
+ };
308
+ _this.eventManager.fire('track.product.impression', { controller: _this, product: result, trackEvent: data });
309
+ ((_g = _this.config.beacon) === null || _g === void 0 ? void 0 : _g.enabled) && _this.tracker.events[_this.page.type].impression({ data: data, siteId: (_h = _this.config.globals) === null || _h === void 0 ? void 0 : _h.siteId });
310
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
311
+ _this.events[responseId].product[result.id].impression = true;
312
+ },
313
+ addToCart: function (result) {
314
+ var _a, _b, _c, _d, _e, _f;
315
+ if (!result) {
316
+ _this.log.warn('No result provided to track.product.addToCart');
317
+ return;
318
+ }
319
+ var responseId = result.responseId;
320
+ if (!_this.events[responseId]) {
321
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
322
+ return;
323
+ }
324
+ var product = {
325
+ 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) : '',
326
+ uid: result.id,
327
+ sku: (_c = result.mappings.core) === null || _c === void 0 ? void 0 : _c.sku,
328
+ qty: result.quantity || 1,
329
+ price: Number((_d = result.mappings.core) === null || _d === void 0 ? void 0 : _d.price),
330
+ };
331
+ var data = {
332
+ responseId: responseId,
333
+ results: [product],
334
+ };
335
+ _this.eventManager.fire('track.product.addToCart', { controller: _this, product: result, trackEvent: data });
336
+ ((_e = _this.config.beacon) === null || _e === void 0 ? void 0 : _e.enabled) && _this.tracker.events[_this.page.type].addToCart({ data: data, siteId: (_f = _this.config.globals) === null || _f === void 0 ? void 0 : _f.siteId });
337
+ },
338
+ },
339
+ redirect: function (_a) {
340
+ var _b, _c;
341
+ var redirectURL = _a.redirectURL, responseId = _a.responseId;
342
+ if (!redirectURL) {
343
+ _this.log.warn('No redirectURL provided to track.redirect');
344
+ return;
345
+ }
346
+ var data = {
347
+ responseId: responseId,
348
+ redirect: redirectURL,
349
+ };
350
+ _this.eventManager.fire('track.redirect', { controller: _this, redirectURL: redirectURL, trackEvent: data });
351
+ ((_b = _this.config.beacon) === null || _b === void 0 ? void 0 : _b.enabled) && _this.tracker.events.search.redirect({ data: data, siteId: (_c = _this.config.globals) === null || _c === void 0 ? void 0 : _c.siteId });
352
+ },
353
+ };
354
+ _this.search = function () { return __awaiter(_this, void 0, void 0, function () {
355
+ var params_1, err_1, stringyParams, prevStringyParams, searchProfile, meta, search, preventBackfill, dontBackfill, backfillRequestsParams_1, backfillRequests, backfillResponses, backfillResults, infiniteResponse, responseId, searchResponse, responseId, response, afterSearchProfile, err_2, data, afterStoreProfile, err_3, err_4;
356
+ var _this = this;
357
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
358
+ return __generator(this, function (_p) {
359
+ switch (_p.label) {
360
+ case 0:
361
+ _p.trys.push([0, 22, 23, 24]);
362
+ if (!!this.initialized) return [3 /*break*/, 2];
363
+ return [4 /*yield*/, this.init()];
364
+ case 1:
365
+ _p.sent();
366
+ _p.label = 2;
367
+ case 2:
368
+ params_1 = this.params;
369
+ if (((_b = (_a = params_1.search) === null || _a === void 0 ? void 0 : _a.query) === null || _b === void 0 ? void 0 : _b.string) && ((_d = (_c = params_1.search) === null || _c === void 0 ? void 0 : _c.query) === null || _d === void 0 ? void 0 : _d.string.length)) {
370
+ // save it to the history store
371
+ this.store.history.save(params_1.search.query.string);
372
+ }
373
+ this.store.loading = true;
374
+ _p.label = 3;
375
+ case 3:
376
+ _p.trys.push([3, 5, , 6]);
377
+ return [4 /*yield*/, this.eventManager.fire('beforeSearch', {
378
+ controller: this,
379
+ request: params_1,
380
+ })];
381
+ case 4:
382
+ _p.sent();
383
+ return [3 /*break*/, 6];
384
+ case 5:
385
+ err_1 = _p.sent();
386
+ if ((err_1 === null || err_1 === void 0 ? void 0 : err_1.message) == 'cancelled') {
387
+ this.log.warn("'beforeSearch' middleware cancelled");
388
+ return [2 /*return*/];
389
+ }
390
+ else {
391
+ this.log.error("error in 'beforeSearch' middleware");
392
+ throw err_1;
393
+ }
394
+ return [3 /*break*/, 6];
395
+ case 6:
396
+ stringyParams = JSON.stringify(getStorableRequestParams(params_1));
397
+ prevStringyParams = this.storage.get('lastStringyParams');
398
+ if (this.store.loaded && stringyParams === prevStringyParams) {
399
+ // no param change - not searching
400
+ return [2 /*return*/];
401
+ }
402
+ searchProfile = this.profiler.create({ type: 'event', name: 'search', context: params_1 }).start();
403
+ meta = {};
404
+ search = void 0;
405
+ if (!(((_f = (_e = this.config.settings) === null || _e === void 0 ? void 0 : _e.infinite) === null || _f === void 0 ? void 0 : _f.enabled) && ((_g = params_1.pagination) === null || _g === void 0 ? void 0 : _g.page) && params_1.pagination.page > 1)) return [3 /*break*/, 11];
406
+ preventBackfill = ((_h = this.config.settings.infinite) === null || _h === void 0 ? void 0 : _h.backfill) && !this.store.results.length && params_1.pagination.page > this.config.settings.infinite.backfill;
407
+ dontBackfill = !((_j = this.config.settings.infinite) === null || _j === void 0 ? void 0 : _j.backfill) && !this.store.results.length;
408
+ // if the page is higher than the backfill setting redirect back to page 1
409
+ if (preventBackfill || dontBackfill) {
410
+ this.storage.set('scrollMap', {});
411
+ this.urlManager.set('page', 1).go();
412
+ return [2 /*return*/];
413
+ }
414
+ if (!(((_k = this.config.settings) === null || _k === void 0 ? void 0 : _k.infinite.backfill) && !this.store.loaded)) return [3 /*break*/, 8];
415
+ backfillRequestsParams_1 = [];
416
+ backfillRequests = Array(params_1.pagination.page)
417
+ .fill('backfill')
418
+ .map(function (v, i) {
419
+ var _a, _b, _c, _d;
420
+ var backfillParams = (0, deepmerge_1.default)(__assign({}, params_1), { pagination: { page: i + 1 }, search: { redirectResponse: 'full' } });
421
+ // don't include page parameter if on page 1
422
+ if (i + 1 == 1) {
423
+ (_a = backfillParams === null || backfillParams === void 0 ? void 0 : backfillParams.pagination) === null || _a === void 0 ? true : delete _a.page;
424
+ if ((_c = (_b = _this.config.settings) === null || _b === void 0 ? void 0 : _b.redirects) === null || _c === void 0 ? void 0 : _c.merchandising) {
425
+ // redirect setting
426
+ // DUPLICATED LOGIC can be found in params getter
427
+ (_d = backfillParams === null || backfillParams === void 0 ? void 0 : backfillParams.search) === null || _d === void 0 ? true : delete _d.redirectResponse;
428
+ }
429
+ }
430
+ backfillRequestsParams_1.push(backfillParams);
431
+ return _this.client[_this.page.type](backfillParams);
432
+ });
433
+ return [4 /*yield*/, Promise.all(backfillRequests)];
434
+ case 7:
435
+ backfillResponses = _p.sent();
436
+ // backfillResponses are [{ meta: MetaResponseModel, search: SearchResponseModel }]
437
+ // set the meta and response to the first page of backfillResponses
438
+ meta = backfillResponses[0].meta;
439
+ search = backfillResponses[0].search;
440
+ backfillResults = backfillResponses.reduce(function (results, response) {
441
+ var responseId = response.search.tracking.responseId;
442
+ _this.events[responseId] = _this.events[responseId] || { product: {}, banner: {} };
443
+ return results.concat.apply(results, response.search.results);
444
+ }, []);
445
+ // overwrite pagination params to expected state
446
+ search.pagination.totalPages = Math.ceil(search.pagination.totalResults / search.pagination.pageSize);
447
+ search.pagination.page = (_l = params_1.pagination) === null || _l === void 0 ? void 0 : _l.page;
448
+ // set the response results with results from backfill responses
449
+ search.results = backfillResults;
450
+ return [3 /*break*/, 10];
451
+ case 8: return [4 /*yield*/, this.client[this.page.type](params_1)];
452
+ case 9:
453
+ infiniteResponse = _p.sent();
454
+ meta = infiniteResponse.meta;
455
+ search = infiniteResponse.search;
456
+ responseId = search.tracking.responseId;
457
+ this.events[responseId] = this.events[responseId] || { product: {}, banner: {} };
458
+ // append new results to previous results
459
+ search.results = __spreadArray(__spreadArray([], this.previousResults, true), (search.results || []), true);
460
+ _p.label = 10;
461
+ case 10: return [3 /*break*/, 13];
462
+ case 11:
463
+ // normal request
464
+ // clear previousResults to prevent infinite scroll from using them
465
+ this.previousResults = [];
466
+ return [4 /*yield*/, this.client[this.page.type](params_1)];
467
+ case 12:
468
+ searchResponse = _p.sent();
469
+ meta = searchResponse.meta;
470
+ search = searchResponse.search;
471
+ responseId = search.tracking.responseId;
472
+ this.events[responseId] = { product: {}, banner: {} };
473
+ _p.label = 13;
474
+ case 13:
475
+ response = { meta: meta, search: search };
476
+ searchProfile.stop();
477
+ this.log.profile(searchProfile);
478
+ afterSearchProfile = this.profiler.create({ type: 'event', name: 'afterSearch', context: params_1 }).start();
479
+ _p.label = 14;
480
+ case 14:
481
+ _p.trys.push([14, 16, , 17]);
482
+ return [4 /*yield*/, this.eventManager.fire('afterSearch', {
483
+ controller: this,
484
+ request: params_1,
485
+ response: response,
486
+ })];
487
+ case 15:
488
+ _p.sent();
489
+ return [3 /*break*/, 17];
490
+ case 16:
491
+ err_2 = _p.sent();
492
+ if ((err_2 === null || err_2 === void 0 ? void 0 : err_2.message) == 'cancelled') {
493
+ this.log.warn("'afterSearch' middleware cancelled");
494
+ afterSearchProfile.stop();
495
+ return [2 /*return*/];
496
+ }
497
+ else {
498
+ this.log.error("error in 'afterSearch' middleware");
499
+ throw err_2;
500
+ }
501
+ return [3 /*break*/, 17];
502
+ case 17:
503
+ afterSearchProfile.stop();
504
+ this.log.profile(afterSearchProfile);
505
+ // store previous results for infinite usage (need to alsways store in case switch to infinite after pagination)
506
+ this.previousResults = JSON.parse(JSON.stringify(response.search.results));
507
+ // update the store
508
+ this.store.update(response);
509
+ data = { responseId: response.search.tracking.responseId };
510
+ ((_m = this.config.beacon) === null || _m === void 0 ? void 0 : _m.enabled) && this.tracker.events[this.page.type].render({ data: data, siteId: (_o = this.config.globals) === null || _o === void 0 ? void 0 : _o.siteId });
511
+ afterStoreProfile = this.profiler.create({ type: 'event', name: 'afterStore', context: params_1 }).start();
512
+ _p.label = 18;
513
+ case 18:
514
+ _p.trys.push([18, 20, , 21]);
515
+ return [4 /*yield*/, this.eventManager.fire('afterStore', {
516
+ controller: this,
517
+ request: params_1,
518
+ response: response,
519
+ })];
520
+ case 19:
521
+ _p.sent();
522
+ return [3 /*break*/, 21];
523
+ case 20:
524
+ err_3 = _p.sent();
525
+ if ((err_3 === null || err_3 === void 0 ? void 0 : err_3.message) == 'cancelled') {
526
+ this.log.warn("'afterStore' middleware cancelled");
527
+ afterStoreProfile.stop();
528
+ return [2 /*return*/];
529
+ }
530
+ else {
531
+ this.log.error("error in 'afterStore' middleware");
532
+ throw err_3;
533
+ }
534
+ return [3 /*break*/, 21];
535
+ case 21:
536
+ afterStoreProfile.stop();
537
+ this.log.profile(afterStoreProfile);
538
+ return [3 /*break*/, 24];
539
+ case 22:
540
+ err_4 = _p.sent();
541
+ if (err_4) {
542
+ if (err_4.err && err_4.fetchDetails) {
543
+ switch (err_4.fetchDetails.status) {
544
+ case 429: {
545
+ this.store.error = {
546
+ code: 429,
547
+ type: snap_store_mobx_1.ErrorType.WARNING,
548
+ message: 'Too many requests try again later',
549
+ };
550
+ break;
551
+ }
552
+ case 500: {
553
+ this.store.error = {
554
+ code: 500,
555
+ type: snap_store_mobx_1.ErrorType.ERROR,
556
+ message: 'Invalid Search Request or Service Unavailable',
557
+ };
558
+ break;
559
+ }
560
+ default: {
561
+ this.store.error = {
562
+ type: snap_store_mobx_1.ErrorType.ERROR,
563
+ message: err_4.err.message,
564
+ };
565
+ break;
566
+ }
567
+ }
568
+ this.log.error(this.store.error);
569
+ this.handleError(err_4.err, err_4.fetchDetails);
570
+ }
571
+ else {
572
+ this.store.error = {
573
+ type: snap_store_mobx_1.ErrorType.ERROR,
574
+ message: "Something went wrong... - ".concat(err_4),
575
+ };
576
+ this.log.error(err_4);
577
+ this.handleError(err_4);
578
+ }
579
+ }
580
+ return [3 /*break*/, 24];
581
+ case 23:
582
+ this.store.loading = false;
583
+ return [7 /*endfinally*/];
584
+ case 24: return [2 /*return*/];
585
+ }
586
+ });
587
+ }); };
588
+ _this.addToCart = function (_products) { return __awaiter(_this, void 0, void 0, function () {
589
+ var products;
590
+ var _this = this;
591
+ return __generator(this, function (_a) {
592
+ products = typeof (_products === null || _products === void 0 ? void 0 : _products.slice) == 'function' ? _products.slice() : [_products];
593
+ if (!_products || products.length === 0) {
594
+ this.log.warn('No products provided to search controller.addToCart');
595
+ return [2 /*return*/];
596
+ }
597
+ products.forEach(function (product) {
598
+ _this.track.product.addToCart(product);
599
+ });
600
+ if (products.length > 0) {
601
+ this.eventManager.fire('addToCart', { controller: this, products: products });
602
+ }
603
+ return [2 /*return*/];
604
+ });
605
+ }); };
606
+ // deep merge config with defaults
607
+ _this.config = (0, deepmerge_1.default)(defaultConfig, _this.config);
608
+ if (((_b = _this.config.settings) === null || _b === void 0 ? void 0 : _b.infinite) &&
609
+ typeof ((_c = _this.config.settings) === null || _c === void 0 ? void 0 : _c.infinite) == 'object' &&
610
+ (Object.keys((_d = _this.config.settings) === null || _d === void 0 ? void 0 : _d.infinite).length == 0 || typeof ((_f = (_e = _this.config.settings) === null || _e === void 0 ? void 0 : _e.infinite) === null || _f === void 0 ? void 0 : _f.backfill) != 'undefined')) {
611
+ // infinite is enabled by setting config.infinite={} (old method)
612
+ // set config.infinite.enabled=true
613
+ _this.config.settings = __assign(__assign({}, _this.config.settings), { infinite: __assign({ enabled: true }, _this.config.settings.infinite) });
614
+ }
615
+ // set restorePosition to be enabled by default when using infinite (if not provided)
616
+ if (((_h = (_g = _this.config.settings) === null || _g === void 0 ? void 0 : _g.infinite) === null || _h === void 0 ? void 0 : _h.enabled) && typeof _this.config.settings.restorePosition == 'undefined') {
617
+ _this.config.settings.restorePosition = { enabled: true };
618
+ }
619
+ _this.store.setConfig(_this.config);
620
+ _this.storage = new snap_store_mobx_1.StorageStore({
621
+ type: 'session',
622
+ key: "athos-controller-".concat(_this.config.id),
623
+ });
624
+ if (typeof ((_j = _this.context) === null || _j === void 0 ? void 0 : _j.page) === 'object' && ['search', 'category'].includes(_this.context.page.type)) {
625
+ _this.page = (0, deepmerge_1.default)(_this.page, _this.context.page);
626
+ }
627
+ _this.eventManager.on('beforeSearch', function (_a, next_1) { return __awaiter(_this, [_a, next_1], void 0, function (_b, next) {
628
+ var req, query, hasCategoryBackgroundFilters;
629
+ var _c, _d;
630
+ var request = _b.request;
631
+ return __generator(this, function (_e) {
632
+ switch (_e.label) {
633
+ case 0:
634
+ // wait for other middleware to resolve
635
+ return [4 /*yield*/, next()];
636
+ case 1:
637
+ // wait for other middleware to resolve
638
+ _e.sent();
639
+ req = request;
640
+ query = (_c = req.search) === null || _c === void 0 ? void 0 : _c.query;
641
+ if (!query) {
642
+ hasCategoryBackgroundFilters = (_d = req.filters) === null || _d === void 0 ? void 0 : _d.filter(function (filter) { return filter.background; }).filter(function (filter) {
643
+ return BACKGROUND_FILTER_FIELD_MATCHES.find(function (bgFilter) {
644
+ var _a;
645
+ return (_a = filter.field) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(bgFilter);
646
+ });
647
+ }).filter(function (filter) {
648
+ return BACKGROUND_FILTERS_VALUE_FLAGS.every(function (flag) {
649
+ switch (filter.type) {
650
+ case 'range':
651
+ var rangeFilter = filter;
652
+ return rangeFilter.value !== flag;
653
+ case 'value':
654
+ default:
655
+ var valueFilter = filter;
656
+ return valueFilter.value !== flag;
657
+ }
658
+ });
659
+ });
660
+ if (hasCategoryBackgroundFilters === null || hasCategoryBackgroundFilters === void 0 ? void 0 : hasCategoryBackgroundFilters.length) {
661
+ this.page = (0, deepmerge_1.default)(this.page, { type: 'category' });
662
+ }
663
+ }
664
+ return [2 /*return*/];
665
+ }
666
+ });
667
+ }); });
668
+ // add 'afterSearch' middleware
669
+ _this.eventManager.on('afterSearch', function (search, next) { return __awaiter(_this, void 0, void 0, function () {
670
+ var config, redirectURL, searchStore;
671
+ var _a, _b, _c, _d, _e, _f, _g, _h;
672
+ return __generator(this, function (_j) {
673
+ switch (_j.label) {
674
+ case 0:
675
+ config = search.controller.config;
676
+ redirectURL = (_c = (_b = (_a = search.response) === null || _a === void 0 ? void 0 : _a.search) === null || _b === void 0 ? void 0 : _b.merchandising) === null || _c === void 0 ? void 0 : _c.redirect;
677
+ searchStore = search.controller.store;
678
+ if (redirectURL && ((_e = (_d = config === null || config === void 0 ? void 0 : config.settings) === null || _d === void 0 ? void 0 : _d.redirects) === null || _e === void 0 ? void 0 : _e.merchandising) && !((_h = (_g = (_f = search === null || search === void 0 ? void 0 : search.response) === null || _f === void 0 ? void 0 : _f.search) === null || _g === void 0 ? void 0 : _g.filters) === null || _h === void 0 ? void 0 : _h.length) && !searchStore.loaded) {
679
+ // set loaded to true to prevent infinite search/reloading from happening
680
+ searchStore.loaded = true;
681
+ this.track.redirect({ redirectURL: redirectURL, responseId: search.response.search.tracking.responseId });
682
+ window.location.replace(redirectURL);
683
+ return [2 /*return*/, false];
684
+ }
685
+ return [4 /*yield*/, next()];
686
+ case 1:
687
+ _j.sent();
688
+ return [2 /*return*/];
689
+ }
690
+ });
691
+ }); });
692
+ _this.eventManager.on('afterStore', function (search, next) { return __awaiter(_this, void 0, void 0, function () {
693
+ var storableRequestParams, stringyParams, scrollMap, elementPosition;
694
+ return __generator(this, function (_a) {
695
+ switch (_a.label) {
696
+ case 0: return [4 /*yield*/, next()];
697
+ case 1:
698
+ _a.sent();
699
+ storableRequestParams = getStorableRequestParams(search.request);
700
+ stringyParams = JSON.stringify(storableRequestParams);
701
+ this.storage.set('lastStringyParams', stringyParams);
702
+ scrollMap = this.storage.get('scrollMap') || {};
703
+ elementPosition = scrollMap[stringyParams];
704
+ if (!elementPosition) {
705
+ // search params have changed - empty the scrollMap
706
+ this.storage.set('scrollMap', {});
707
+ }
708
+ // not awaiting this event as it relies on render, and render is blocked by afterStore event
709
+ this.eventManager.fire('restorePosition', { controller: this, element: elementPosition });
710
+ return [2 /*return*/];
711
+ }
712
+ });
713
+ }); });
714
+ _this.eventManager.on('afterSearch', function (search, next) { return __awaiter(_this, void 0, void 0, function () {
715
+ var facets;
716
+ var _this = this;
717
+ return __generator(this, function (_a) {
718
+ switch (_a.label) {
719
+ case 0: return [4 /*yield*/, next()];
720
+ case 1:
721
+ _a.sent();
722
+ facets = search.response.search.facets;
723
+ if (facets) {
724
+ facets.forEach(function (facet) {
725
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
726
+ if (((_a = search.response.meta) === null || _a === void 0 ? void 0 : _a.facets) && facet.field) {
727
+ var field = facet.field || '';
728
+ var metaFacet = search.response.meta.facets[field];
729
+ var dataDelimiter = (metaFacet === null || metaFacet === void 0 ? void 0 : metaFacet.hierarchyDelimiter) || ' / ';
730
+ var filterSettings = ((_d = (_c = (_b = _this.config) === null || _b === void 0 ? void 0 : _b.settings) === null || _c === void 0 ? void 0 : _c.filters) === null || _d === void 0 ? void 0 : _d.fields)
731
+ ? (_g = (_f = (_e = _this.config) === null || _e === void 0 ? void 0 : _e.settings) === null || _f === void 0 ? void 0 : _f.filters) === null || _g === void 0 ? void 0 : _g.fields[field]
732
+ : (_j = (_h = _this.config) === null || _h === void 0 ? void 0 : _h.settings) === null || _j === void 0 ? void 0 : _j.filters;
733
+ var displayDelimiter = (_l = (_k = filterSettings === null || filterSettings === void 0 ? void 0 : filterSettings.hierarchy) === null || _k === void 0 ? void 0 : _k.displayDelimiter) !== null && _l !== void 0 ? _l : ' / '; // choose delimiter for label
734
+ var showFullPath = (_o = (_m = filterSettings === null || filterSettings === void 0 ? void 0 : filterSettings.hierarchy) === null || _m === void 0 ? void 0 : _m.showFullPath) !== null && _o !== void 0 ? _o : false; // display full hierarchy path or just the current level
735
+ if (((_p = filterSettings === null || filterSettings === void 0 ? void 0 : filterSettings.hierarchy) === null || _p === void 0 ? void 0 : _p.enabled) &&
736
+ metaFacet &&
737
+ metaFacet.display === 'hierarchy' &&
738
+ facet.filtered &&
739
+ ((_q = facet.values) === null || _q === void 0 ? void 0 : _q.length) > 0) {
740
+ var filteredValues = (_r = facet.values) === null || _r === void 0 ? void 0 : _r.filter(function (val) { return (val === null || val === void 0 ? void 0 : val.filtered) === true; });
741
+ if (filteredValues && filteredValues.length) {
742
+ var filterToAdd = {
743
+ field: facet.field,
744
+ //escape special charactors used in regex
745
+ label: showFullPath
746
+ ? ((_t = (_s = filteredValues[0].value) !== null && _s !== void 0 ? _s : filteredValues[0].label) !== null && _t !== void 0 ? _t : '').replace(new RegExp(dataDelimiter.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), displayDelimiter)
747
+ : filteredValues[0].label,
748
+ type: 'value',
749
+ };
750
+ if (search.response.search.filters) {
751
+ search.response.search.filters.push(filterToAdd);
752
+ }
753
+ else {
754
+ search.response.search.filters = [filterToAdd];
755
+ }
756
+ }
757
+ }
758
+ }
759
+ });
760
+ }
761
+ return [2 /*return*/];
762
+ }
763
+ });
764
+ }); });
765
+ _this.eventManager.on('afterStore', function (search, next) { return __awaiter(_this, void 0, void 0, function () {
766
+ var controller, response, config_1, nonBackgroundFilters, singleResultUrl;
767
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
768
+ return __generator(this, function (_k) {
769
+ switch (_k.label) {
770
+ case 0: return [4 /*yield*/, next()];
771
+ case 1:
772
+ _k.sent();
773
+ controller = search.controller;
774
+ response = search.response.search;
775
+ if (controller.store.loaded && !controller.store.error) {
776
+ config_1 = search.controller.config;
777
+ nonBackgroundFilters = (_b = (_a = search === null || search === void 0 ? void 0 : search.request) === null || _a === void 0 ? void 0 : _a.filters) === null || _b === void 0 ? void 0 : _b.filter(function (filter) { return !filter.background; });
778
+ singleResultUrl = ((_c = response === null || response === void 0 ? void 0 : response.results) === null || _c === void 0 ? void 0 : _c.length) && ((_e = (_d = response === null || response === void 0 ? void 0 : response.results[0].mappings) === null || _d === void 0 ? void 0 : _d.core) === null || _e === void 0 ? void 0 : _e.url);
779
+ if (((_g = (_f = config_1 === null || config_1 === void 0 ? void 0 : config_1.settings) === null || _f === void 0 ? void 0 : _f.redirects) === null || _g === void 0 ? void 0 : _g.singleResult) &&
780
+ ((_h = response.search) === null || _h === void 0 ? void 0 : _h.query) &&
781
+ ((_j = response.pagination) === null || _j === void 0 ? void 0 : _j.totalResults) === 1 &&
782
+ !(nonBackgroundFilters === null || nonBackgroundFilters === void 0 ? void 0 : nonBackgroundFilters.length) &&
783
+ singleResultUrl) {
784
+ window.location.replace(singleResultUrl);
785
+ return [2 /*return*/, false];
786
+ }
787
+ }
788
+ return [2 /*return*/];
789
+ }
790
+ });
791
+ }); });
792
+ // restore position
793
+ if ((_l = (_k = _this.config.settings) === null || _k === void 0 ? void 0 : _k.restorePosition) === null || _l === void 0 ? void 0 : _l.enabled) {
794
+ _this.eventManager.on('restorePosition', function (_a, next_1) { return __awaiter(_this, [_a, next_1], void 0, function (_b, next) {
795
+ var lastRequest, storableRequestParams, stringyParams, scrollMap, scrollToPosition;
796
+ var _this = this;
797
+ var controller = _b.controller, element = _b.element;
798
+ return __generator(this, function (_c) {
799
+ switch (_c.label) {
800
+ case 0:
801
+ // attempt to grab the element from storage if it is not provided
802
+ if (!(element === null || element === void 0 ? void 0 : element.selector)) {
803
+ lastRequest = this.storage.get('lastStringyParams');
804
+ if (lastRequest) {
805
+ storableRequestParams = getStorableRequestParams(JSON.parse(lastRequest));
806
+ stringyParams = JSON.stringify(storableRequestParams);
807
+ scrollMap = this.storage.get('scrollMap') || {};
808
+ element = scrollMap[stringyParams];
809
+ }
810
+ }
811
+ scrollToPosition = function () {
812
+ return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
813
+ var maxCheckTime, checkTime, maxScrolls, maxCheckCount, scrollBackCount, checkCount, scrolledElem, checkAndScroll;
814
+ return __generator(this, function (_a) {
815
+ switch (_a.label) {
816
+ case 0:
817
+ maxCheckTime = 600;
818
+ checkTime = 60;
819
+ maxScrolls = Math.ceil(maxCheckTime / checkTime);
820
+ maxCheckCount = maxScrolls + 2;
821
+ scrollBackCount = 0;
822
+ checkCount = 0;
823
+ scrolledElem = undefined;
824
+ checkAndScroll = function () {
825
+ var _a;
826
+ var offset = ((_a = element === null || element === void 0 ? void 0 : element.domRect) === null || _a === void 0 ? void 0 : _a.top) || 0;
827
+ var elem = document.querySelector(element === null || element === void 0 ? void 0 : element.selector);
828
+ // for case where the element clicked on has no height
829
+ while (elem && !elem.getBoundingClientRect().height) {
830
+ elem = elem.parentElement;
831
+ // original offset no longer applies since using different element
832
+ offset = 0;
833
+ }
834
+ if (elem) {
835
+ var y = elem.getBoundingClientRect().y;
836
+ scrollBackCount++;
837
+ // if the offset is off, we need to scroll into position (can be caused by lazy loaded images)
838
+ if (y > offset + 1 || y < offset - 1) {
839
+ window.scrollBy(0, y - offset);
840
+ }
841
+ else {
842
+ // don't need to scroll - it is right where we want it
843
+ scrolledElem = elem;
844
+ }
845
+ }
846
+ else {
847
+ checkCount++;
848
+ }
849
+ return true;
850
+ };
851
+ _a.label = 1;
852
+ case 1:
853
+ if (!(checkAndScroll() && scrollBackCount <= maxScrolls && checkCount <= maxCheckCount)) return [3 /*break*/, 3];
854
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, checkTime); })];
855
+ case 2:
856
+ _a.sent();
857
+ return [3 /*break*/, 1];
858
+ case 3:
859
+ if (scrolledElem) {
860
+ controller.log.debug('restored position to: ', scrolledElem);
861
+ }
862
+ else {
863
+ controller.log.debug('attempted to scroll back to element with selector: ', element === null || element === void 0 ? void 0 : element.selector);
864
+ }
865
+ resolve();
866
+ return [2 /*return*/];
867
+ }
868
+ });
869
+ }); });
870
+ };
871
+ if (!element) return [3 /*break*/, 2];
872
+ return [4 /*yield*/, scrollToPosition()];
873
+ case 1:
874
+ _c.sent();
875
+ _c.label = 2;
876
+ case 2: return [4 /*yield*/, next()];
877
+ case 3:
878
+ _c.sent();
879
+ return [2 /*return*/];
880
+ }
881
+ });
882
+ }); });
883
+ // fire restorePosition event on 'pageshow' when setting is enabled
884
+ if ((_o = (_m = _this.config.settings) === null || _m === void 0 ? void 0 : _m.restorePosition) === null || _o === void 0 ? void 0 : _o.onPageShow) {
885
+ window.addEventListener('pageshow', function (e) {
886
+ if (e.persisted && _this.store.loaded) {
887
+ _this.eventManager.fire('restorePosition', { controller: _this, element: {} });
888
+ }
889
+ });
890
+ }
891
+ }
892
+ // attach config plugins and event middleware
893
+ _this.use(_this.config);
894
+ return _this;
895
+ }
896
+ Object.defineProperty(SearchController.prototype, "params", {
897
+ get: function () {
898
+ var _a, _b, _c, _d;
899
+ var params = (0, deepmerge_1.default)(__assign({}, (0, getParams_1.getSearchParams)(this.urlManager.state)), this.config.globals || {});
900
+ // redirect setting
901
+ // DUPLICATED LOGIC can be found in infinite backfill (change both if updating)
902
+ if (!((_b = (_a = this.config.settings) === null || _a === void 0 ? void 0 : _a.redirects) === null || _b === void 0 ? void 0 : _b.merchandising) || this.store.loaded) {
903
+ params.search = params.search || {};
904
+ params.search.redirectResponse = 'full';
905
+ }
906
+ params.tracking = params.tracking || {};
907
+ params.tracking.domain = window.location.href;
908
+ var _e = this.tracker.getContext(), userId = _e.userId, sessionId = _e.sessionId, pageLoadId = _e.pageLoadId, shopperId = _e.shopperId;
909
+ if (userId) {
910
+ params.tracking.userId = userId;
911
+ }
912
+ if (sessionId) {
913
+ params.tracking.sessionId = sessionId;
914
+ }
915
+ if (pageLoadId) {
916
+ params.tracking.pageLoadId = pageLoadId;
917
+ }
918
+ if (!((_d = (_c = this.config.globals) === null || _c === void 0 ? void 0 : _c.personalization) === null || _d === void 0 ? void 0 : _d.disabled)) {
919
+ var cartItems = this.tracker.cookies.cart.get();
920
+ if (cartItems.length) {
921
+ params.personalization = params.personalization || {};
922
+ params.personalization.cart = cartItems.join(',');
923
+ }
924
+ var lastViewedItems = this.tracker.cookies.viewed.get();
925
+ if (lastViewedItems.length) {
926
+ params.personalization = params.personalization || {};
927
+ params.personalization.lastViewed = lastViewedItems.join(',');
928
+ }
929
+ if (shopperId) {
930
+ params.personalization = params.personalization || {};
931
+ params.personalization.shopper = shopperId;
932
+ }
933
+ }
934
+ return params;
935
+ },
936
+ enumerable: false,
937
+ configurable: true
938
+ });
939
+ return SearchController;
940
+ }(AbstractController_1.AbstractController));
941
+ exports.SearchController = SearchController;
942
+ function getStorableRequestParams(request) {
943
+ var _a, _b, _c, _d;
944
+ return {
945
+ siteId: request.siteId,
946
+ sorts: request.sorts,
947
+ search: {
948
+ query: {
949
+ string: ((_b = (_a = request === null || request === void 0 ? void 0 : request.search) === null || _a === void 0 ? void 0 : _a.query) === null || _b === void 0 ? void 0 : _b.string) || '',
950
+ },
951
+ subQuery: ((_c = request === null || request === void 0 ? void 0 : request.search) === null || _c === void 0 ? void 0 : _c.subQuery) || '',
952
+ },
953
+ filters: request.filters,
954
+ pagination: request.pagination,
955
+ facets: request.facets,
956
+ merchandising: {
957
+ landingPage: ((_d = request.merchandising) === null || _d === void 0 ? void 0 : _d.landingPage) || '',
958
+ },
959
+ };
960
+ }
961
+ function generateHrefSelector(element, href, levels) {
962
+ if (levels === void 0) { levels = 7; }
963
+ var level = 0;
964
+ var elem = element;
965
+ while (elem && level <= levels) {
966
+ var innerHrefElem = null;
967
+ try {
968
+ innerHrefElem = elem.querySelector("[href*=\"".concat(href, "\"]"));
969
+ }
970
+ catch (e) {
971
+ try {
972
+ innerHrefElem = elem.querySelector((0, css_escape_1.default)("[href*=\"".concat(href, "\"]")));
973
+ }
974
+ catch (_a) { }
975
+ }
976
+ if (innerHrefElem) {
977
+ // innerHrefElem was found! now get selectors up to elem that contained it
978
+ var selector = '';
979
+ var parentElem = innerHrefElem;
980
+ while (parentElem && parentElem != elem.parentElement) {
981
+ var classNames = parentElem.classList.value.trim().split(' ');
982
+ // document.querySelector does not appreciate special characters - must escape them
983
+ var escapedClassSelector = classNames.reduce(function (classes, classname) { return (classname.trim() ? "".concat(classes, ".").concat((0, css_escape_1.default)(classname.trim())) : classes); }, '');
984
+ selector = "".concat(parentElem.tagName).concat(escapedClassSelector).concat(selector ? " ".concat(selector) : '');
985
+ parentElem = parentElem.parentElement;
986
+ }
987
+ return "".concat(selector, "[href*=\"").concat(href, "\"]");
988
+ }
989
+ elem = elem.parentElement;
990
+ level++;
991
+ }
992
+ return;
993
+ }