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