coveo-search-ui
Version:
Coveo JavaScript Search Framework
519 lines (505 loc) • 28.3 kB
JavaScript
webpackJsonpCoveo__temporary([48],{
/***/ 256:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
__webpack_require__(522);
var _ = __webpack_require__(0);
var OmniboxEvents_1 = __webpack_require__(34);
var GlobalExports_1 = __webpack_require__(3);
var MiscModules_1 = __webpack_require__(67);
var ModelsModules_1 = __webpack_require__(205);
var Dom_1 = __webpack_require__(1);
var UtilsModules_1 = __webpack_require__(74);
var AnalyticsActionListMeta_1 = __webpack_require__(10);
var Component_1 = __webpack_require__(7);
var ComponentOptions_1 = __webpack_require__(8);
var Initialization_1 = __webpack_require__(2);
var FacetValueSuggestionsProvider_1 = __webpack_require__(620);
/**
* This component provides [`Omnibox`]{@link Omnibox} query suggestions scoped to distinct categories based on the values of a
* specific [`field`]{@link FacetValueSuggestions.options.field} whose [Facet](https://docs.coveo.com/en/1982/#facet) option is enabled.
*
* @externaldocs [Providing Facet Value Suggestions](https://docs.coveo.com/en/340/#providing-facet-value-suggestions)
*
* @availablesince [May 2018 Release (v2.4094.8)](https://docs.coveo.com/410/#may-2018-release-v240948)
*/
var FacetValueSuggestions = /** @class */ (function (_super) {
__extends(FacetValueSuggestions, _super);
/**
* Creates a new `FacetValueSuggestions` component.
* @param element The HTMLElement on which to instantiate the component.
* @param options The options for the `FacetValueSuggestions` component.
* @param bindings The bindings that the component requires to function normally. If not set, these will be
* automatically resolved (with a slower execution time).
*/
function FacetValueSuggestions(element, options, bindings) {
var _this = _super.call(this, element, FacetValueSuggestions.ID, bindings) || this;
_this.options = options;
_this.options = ComponentOptions_1.ComponentOptions.initComponentOptions(element, FacetValueSuggestions, options);
_this.facetValueSuggestionsProvider = new FacetValueSuggestionsProvider_1.FacetValueSuggestionsProvider(_this.queryController, {
field: _this.options.field,
expression: _this.options.expression
});
_this.queryStateFieldFacetId = "f:" + _this.options.field;
if (!_this.options.templateHelper) {
_this.options.templateHelper = FacetValueSuggestions.defaultTemplate;
}
Dom_1.$$(_this.root).on(OmniboxEvents_1.OmniboxEvents.populateOmniboxSuggestions, function (e, args) {
args.suggestions.push(_this.getSuggestions(args.omnibox));
});
return _this;
}
FacetValueSuggestions.defaultTemplate = function (row, omnibox) {
var keyword = row.keyword.html;
var facetValue = UtilsModules_1.DomUtils.highlight(row.value, 'coveo-omnibox-hightlight');
var details = this.options.displayEstimateNumberOfResults
? UtilsModules_1.DomUtils.highlight(" (" + MiscModules_1.l('ResultCount', row.numberOfResults.toString(), row.numberOfResults) + ")", 'coveo-omnibox-suggestion-results-count', true)
: '';
return "" + MiscModules_1.l('KeywordInCategory', keyword, facetValue) + details;
};
FacetValueSuggestions.getQuerySuggestionKeywordFromText = function (text) {
return {
text: text,
html: UtilsModules_1.DomUtils.highlight(text, 'coveo-omnibox-hightlight')
};
};
FacetValueSuggestions.prototype.getSuggestions = function (omnibox) {
return __awaiter(this, void 0, void 0, function () {
var text, suggestions;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (this.options.numberOfSuggestions == 0) {
return [2 /*return*/, []];
}
text = omnibox.getText();
return [4 /*yield*/, this.getFacetValueSuggestions(text, omnibox)];
case 1:
suggestions = _a.sent();
return [2 /*return*/, suggestions || []];
}
});
});
};
FacetValueSuggestions.prototype.getQuerySuggestionsKeywords = function (omnibox) {
return __awaiter(this, void 0, void 0, function () {
var suggestions;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(this.options.useQuerySuggestions && omnibox.suggestionAddon)) return [3 /*break*/, 2];
return [4 /*yield*/, omnibox.suggestionAddon.getSuggestion()];
case 1:
suggestions = _a.sent();
return [2 /*return*/, suggestions.map(function (_a) {
var text = _a.text, html = _a.html;
return ({ text: text || '', html: html });
})];
case 2: return [2 /*return*/, []];
}
});
});
};
FacetValueSuggestions.prototype.getFacetValueSuggestions = function (text, omnibox) {
return __awaiter(this, void 0, void 0, function () {
var wordsToQuery, suggestionsKeywords, allKeywordsToQuery;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
wordsToQuery = this.options.useValueFromSearchbox ? [FacetValueSuggestions.getQuerySuggestionKeywordFromText(text)] : [];
return [4 /*yield*/, this.getQuerySuggestionsKeywords(omnibox)];
case 1:
suggestionsKeywords = _a.sent();
allKeywordsToQuery = _.unique(wordsToQuery.concat(suggestionsKeywords).filter(function (keyword) { return keyword.text != ''; }), function (keyword) { return keyword.text; });
if (allKeywordsToQuery.length === 0) {
return [2 /*return*/, []];
}
return [2 /*return*/, this.getSuggestionsForWords(allKeywordsToQuery, omnibox)];
}
});
});
};
FacetValueSuggestions.prototype.getSuggestionsForWords = function (keywordToQuery, omnibox) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
var suggestions, currentSelectedValues_1, filteredSuggestions, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
return [4 /*yield*/, this.facetValueSuggestionsProvider.getSuggestions(keywordToQuery)];
case 1:
suggestions = _a.sent();
this.logger.debug('FacetValue Suggestions Results', suggestions);
currentSelectedValues_1 = this.queryStateModel.get(this.queryStateFieldFacetId) || [];
filteredSuggestions = suggestions.filter(function (suggestion) {
return _this.isSuggestionRowAlreadyCheckedInFacet(suggestion, currentSelectedValues_1);
});
return [2 /*return*/, this.rankSuggestionRows(filteredSuggestions).map(function (result) { return _this.mapFacetValueSuggestion(result, omnibox); })];
case 2:
error_1 = _a.sent();
this.logger.error(error_1);
return [2 /*return*/, []];
case 3: return [2 /*return*/];
}
});
});
};
FacetValueSuggestions.prototype.isSuggestionRowAlreadyCheckedInFacet = function (suggestion, currentlySelectedValues) {
return !currentlySelectedValues.some(function (value) { return value == suggestion.value; });
};
FacetValueSuggestions.prototype.rankSuggestionRows = function (suggestions) {
var rankedResults = suggestions.sort(function (a, b) { return b.score.distanceFromTotalForField - a.score.distanceFromTotalForField; }).slice();
var firstSlice = Math.ceil(this.options.numberOfSuggestions / 2);
var lastSlice = -Math.floor(this.options.numberOfSuggestions / 2);
var firstResultsToReturn = rankedResults.splice(0, firstSlice);
if (lastSlice != 0) {
var lastResultsToReturn = rankedResults.slice(lastSlice);
return firstResultsToReturn.concat(lastResultsToReturn);
}
return firstResultsToReturn;
};
FacetValueSuggestions.prototype.mapFacetValueSuggestion = function (resultToShow, omnibox) {
var _this = this;
var suggestion = {
html: this.buildDisplayNameForRow(resultToShow, omnibox),
text: resultToShow.keyword.text
};
var fieldValues = this.options.isCategoryField
? resultToShow.value.split(this.options.categoryFieldDelimitingCharacter)
: [resultToShow.value];
suggestion.advancedQuery = fieldValues.map(function (value) { return _this.options.field + "==\"" + value + "\""; }).join(' AND ');
suggestion.onSelect = function () { return _this.onSuggestionSelected(suggestion, fieldValues, omnibox); };
return suggestion;
};
FacetValueSuggestions.prototype.buildDisplayNameForRow = function (row, omnibox) {
try {
return this.options.templateHelper.call(this, row, omnibox);
}
catch (ex) {
this.logger.error('Could not apply template from options for the given row. Will use default template.', ex, row, omnibox);
return FacetValueSuggestions.defaultTemplate.call(this, row, omnibox);
}
};
FacetValueSuggestions.prototype.onSuggestionSelected = function (suggestion, fieldValues, omnibox) {
omnibox.setText(suggestion.text);
// Copy the state here, else it will directly modify queryStateModel.defaultAttributes.fv.
var fvState = __assign({}, this.queryStateModel.get(ModelsModules_1.QueryStateModel.attributesEnum.fv));
var existingValues = fvState[this.options.field.toString()] || [];
fvState[this.options.field.toString()] = existingValues.concat(fieldValues);
this.queryStateModel.set(ModelsModules_1.QueryStateModel.attributesEnum.fv, fvState);
omnibox.magicBox.blur();
this.usageAnalytics.logSearchEvent(AnalyticsActionListMeta_1.analyticsActionCauseList.omniboxField, {});
this.queryController.executeQuery();
};
FacetValueSuggestions.ID = 'FacetValueSuggestions';
FacetValueSuggestions.doExport = function () {
GlobalExports_1.exportGlobally({
FacetValueSuggestions: FacetValueSuggestions
});
};
/**
* @componentOptions
*/
FacetValueSuggestions.options = {
/**
* The field on whose values the scoped query suggestions should be based.
*
* @examples @productcategory
*/
field: ComponentOptions_1.ComponentOptions.buildFieldOption({ required: true }),
/**
* The maximum number of suggestions to render in the [`Omnibox`]{@link Omnibox}.
*/
numberOfSuggestions: ComponentOptions_1.ComponentOptions.buildNumberOption({ defaultValue: 5, min: 1 }),
/**
* Whether to get scoped query suggestions from the current Coveo ML query suggestions.
*
* **Notes:**
* - If this option is set to `true`, the [`enableQuerySuggestAddon`]{@link Omnibox.options.enableQuerySuggestAddon} option of the [`Omnibox`]{@link Omnibox} component must be set to `true` as well.
* - If this option is set to `true`, an additional `POST` HTTP request is sent to `https://platform.cloud.coveo.com/rest/search/v2/querySuggest`.
*/
useQuerySuggestions: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: true }),
/**
* Whether to get scoped query suggestions from the current user query entered in the search box.
*
* **Default:** `true` if [`useQuerySuggestions`]{@link FacetValueSuggestions.options.useQuerySuggestions} is `false`; `false` otherwise
*/
useValueFromSearchbox: ComponentOptions_1.ComponentOptions.buildBooleanOption({
postProcessing: function (value, options) {
return value || !options.useQuerySuggestions;
}
}),
/**
* Whether to display an estimate of the number of results for each scoped query suggestions.
*
* **Notes:**
* - Setting this option to `true` has no effect when the [`templateHelper`]{@link FacetValueSuggestions.options.templateHelper} options is set.
* - When displaying scoped query suggestions for a standalone search box whose queries are redirected to a search interface enforcing other filters, the number of results will be inaccurate.
*/
displayEstimateNumberOfResults: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: false }),
/**
* The template helper function to execute when rendering each scoped query suggestion.
*
* If specified, the function must have the following signature: (row: [IFacetValueSuggestionRow]{@link IFacetValueSuggestionRow}, omnibox: Omnibox) => string
*
* If not specified, a default function will be used.
*
* **Note:** You cannot set this option directly in the component markup as an HTML attribute. You must either set it:
* - In the [`init`]{@link init} call of your search interface (see [Passing Component Options in the init Call](https://docs.coveo.com/en/346/#passing-component-options-in-the-init-call)
* - Before the `init` call, using the [`options`](@link options) top-level function (see [Passing Component Options Before the init Call](https://docs.coveo.com/en/346/#passing-component-options-before-the-init-call)).
*
* **Example:**
*
* ```javascript
* Coveo.init(document.getElementById('search'), {
* FacetValueSuggestions: {
* templateHelper: (row, omnibox) => { return `Searching for <strong>${row.keyword}</strong> in category <em>${row.value}</em>`; }
* }
* })
* ```
*/
templateHelper: ComponentOptions_1.ComponentOptions.buildCustomOption(function () {
return null;
}),
/**
* Whether the [`field`]{@link FacetValueSuggestions.options.field} option references a multi-value field.
*
* Setting this option to `true` if appropriate will allow the corresponding [`CategoryFacet`]{@link CategoryFacet} or [`DynamicHierarchicalFacet`]{@link DynamicHierarchicalFacet} component (if present) to properly handle the filter format.
*
* See also the [`categoryFieldDelimitingCharacter`]{@link FacetValueSuggestions.options.categoryFieldDelimitingCharacter} option.
*/
isCategoryField: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: false }),
/**
* The delimiting character used for the multi-value field referenced by the [`field`]{@link FacetValueSuggestions.options.field} option.
*
* @examples ;, #
*/
categoryFieldDelimitingCharacter: ComponentOptions_1.ComponentOptions.buildStringOption({ defaultValue: '|', depend: 'isCategoryField' }),
/**
* An advanced query expression to add when requesting facet value suggestions.
*
* Set this option to ensure that the suggestions are properly scoped when using the component with a standalone search box. For instance, if a certain [tab]{@link Tab} is automatically selected in the search interface the standalone search box is redirecting its queries to, you should set this option to that tab's [`expression`]{@link Tab.options.expression}.
*
* @examples @objecttype==Message
*/
expression: ComponentOptions_1.ComponentOptions.buildQueryExpressionOption()
};
return FacetValueSuggestions;
}(Component_1.Component));
exports.FacetValueSuggestions = FacetValueSuggestions;
Initialization_1.Initialization.registerAutoCreateComponent(FacetValueSuggestions);
/***/ }),
/***/ 522:
/***/ (function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ }),
/***/ 620:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var FacetValueSuggestionsProvider = /** @class */ (function () {
function FacetValueSuggestionsProvider(queryController, options) {
this.queryController = queryController;
this.options = options;
}
FacetValueSuggestionsProvider.prototype.getSuggestions = function (valuesToSearch) {
return __awaiter(this, void 0, void 0, function () {
var fieldsToQuery;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getFieldValuesToQuery(valuesToSearch)];
case 1:
fieldsToQuery = _a.sent();
return [2 /*return*/, this.getAllSuggestionsRows(fieldsToQuery.responses, fieldsToQuery.reference)];
}
});
});
};
FacetValueSuggestionsProvider.prototype.getAllSuggestionsRows = function (fieldResponses, fieldTotalReference) {
var _this = this;
return fieldResponses.reduce(function (allValues, fieldResponse) {
var suggestionRows = fieldResponse.values.map(function (indexFieldValue) {
return {
numberOfResults: indexFieldValue.numberOfResults,
keyword: fieldResponse.keyword,
value: indexFieldValue.value,
score: _this.computeScoreForSuggestionRow(indexFieldValue, fieldTotalReference),
field: _this.options.field
};
});
return allValues.concat(suggestionRows);
}, []);
};
FacetValueSuggestionsProvider.prototype.getFieldValuesToQuery = function (valuesToSearch) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
var referenceValuesRequest, queryParts, suggestionValuesRequests, requests, values, reference, responses;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
referenceValuesRequest = this.buildReferenceFieldValueRequest();
queryParts = this.getQueryToExecuteParts();
if (this.options.expression) {
queryParts.push(this.options.expression);
}
suggestionValuesRequests = valuesToSearch.map(function (keyword) {
var queryToExecute = queryParts.concat([keyword.text]).join(' ');
return _this.buildListFieldValueRequest(queryToExecute);
});
requests = suggestionValuesRequests.concat([referenceValuesRequest]);
return [4 /*yield*/, this.queryController.getEndpoint().listFieldValuesBatch({
batch: requests
})];
case 1:
values = _a.sent();
reference = this.computeReferenceFromBatch(values.pop());
responses = values.map(function (value, i) {
return {
keyword: valuesToSearch[i],
values: value
};
});
return [2 /*return*/, {
responses: responses,
reference: reference
}];
}
});
});
};
FacetValueSuggestionsProvider.prototype.computeScoreForSuggestionRow = function (fieldValue, reference) {
var totalNumberForFieldValue = reference.fieldsTotal[fieldValue.value] || reference.smallestTotal;
var distanceFromTotalForField = (totalNumberForFieldValue - fieldValue.numberOfResults) / totalNumberForFieldValue * 100;
return {
distanceFromTotalForField: distanceFromTotalForField
};
};
FacetValueSuggestionsProvider.prototype.computeReferenceFromBatch = function (batch) {
var fieldsTotal = {};
batch.forEach(function (value) { return (fieldsTotal[value.value] = value.numberOfResults); });
return {
fieldsTotal: fieldsTotal,
smallestTotal: batch[batch.length - 1].numberOfResults
};
};
FacetValueSuggestionsProvider.prototype.buildListFieldValueRequest = function (queryToExecute) {
return {
field: this.options.field,
ignoreAccents: true,
maximumNumberOfValues: 3,
queryOverride: queryToExecute
};
};
FacetValueSuggestionsProvider.prototype.buildReferenceFieldValueRequest = function () {
return {
field: this.options.field
};
};
FacetValueSuggestionsProvider.prototype.getQueryToExecuteParts = function () {
var lastQuery = this.queryController.getLastQuery();
var aqWithoutCurrentField = lastQuery && lastQuery.aq ? this.removeFieldExpressionFromExpression(this.options.field.toString(), lastQuery.aq) : '';
return [aqWithoutCurrentField, lastQuery.cq].filter(function (part) { return !!part; });
};
FacetValueSuggestionsProvider.prototype.removeFieldExpressionFromExpression = function (field, expression) {
var expressionWithParenthesis = '([^)]*)';
var expressionAsSingleValue = '[^ ]*';
return expression
.replace(new RegExp(field + "==" + expressionWithParenthesis, 'gi'), '')
.replace(new RegExp(field + "==" + expressionAsSingleValue, 'gi'), '');
};
return FacetValueSuggestionsProvider;
}());
exports.FacetValueSuggestionsProvider = FacetValueSuggestionsProvider;
/***/ })
});
//# sourceMappingURL=FacetValueSuggestions__65d8de8a9f769489e2ff.js.map