coveo-search-ui
Version:
Coveo JavaScript Search Framework
1,105 lines (1,067 loc) • 135 kB
JavaScript
webpackJsonpCoveo__temporary([11],{
/***/ 133:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Result_1 = __webpack_require__(52);
var Result_2 = __webpack_require__(52);
exports.notWordStart = ' ()[],$@\'"';
exports.notInWord = ' ()[],:';
exports.Basic = {
basicExpressions: ['Word', 'DoubleQuoted'],
grammars: {
DoubleQuoted: '"[NotDoubleQuote]"',
NotDoubleQuote: /[^"]*/,
SingleQuoted: "'[NotSingleQuote]'",
NotSingleQuote: /[^']*/,
Number: /-?(0|[1-9]\d*)(\.\d+)?/,
Word: function (input, end, expression) {
var regex = new RegExp('[^' + exports.notWordStart.replace(/(.)/g, '\\$1') + '][^' + exports.notInWord.replace(/(.)/g, '\\$1') + ']*');
var groups = input.match(regex);
if (groups != null && groups.index != 0) {
groups = null;
}
var result = new Result_1.Result(groups != null ? groups[0] : null, expression, input);
if (result.isSuccess() && end && input.length > result.value.length) {
return new Result_2.EndOfInputResult(result);
}
return result;
}
}
};
/***/ }),
/***/ 139:
/***/ (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 __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
__webpack_require__(566);
var QueryEvents_1 = __webpack_require__(11);
var StandaloneSearchInterfaceEvents_1 = __webpack_require__(100);
var GlobalExports_1 = __webpack_require__(3);
var Grammar_1 = __webpack_require__(176);
var MagicBox_1 = __webpack_require__(222);
var Assert_1 = __webpack_require__(5);
var Model_1 = __webpack_require__(18);
var QueryStateModel_1 = __webpack_require__(13);
var Strings_1 = __webpack_require__(6);
var Dom_1 = __webpack_require__(1);
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 QueryboxOptionsProcessing_1 = __webpack_require__(511);
var QueryboxQueryParameters_1 = __webpack_require__(140);
/**
* The `Querybox` component renders an input which the end user can interact with to enter and submit queries.
*
* When the end user submits a search request, the `Querybox` component triggers a query and logs the corresponding
* usage analytics data.
*
* For technical reasons, it is necessary to instantiate this component on a `div` element rather than on an `input`
* element.
*
* See also the [`Searchbox`]{@link Searchbox} component, which can automatically instantiate a `Querybox` along with an
* optional [`SearchButton`]{@link SearchButton} component.
*/
var Querybox = /** @class */ (function (_super) {
__extends(Querybox, _super);
/**
* Creates a new `Querybox component`. Creates a new `Coveo.Magicbox` instance and wraps the Magicbox methods
* (`onblur`, `onsubmit` etc.). Binds event on `buildingQuery` and before redirection (for standalone box).
* @param element The HTMLElement on which to instantiate the component. This cannot be an HTMLInputElement for
* technical reasons.
* @param options The options for the `Querybox` 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 Querybox(element, options, bindings) {
var _this = _super.call(this, element, Querybox.ID, bindings) || this;
_this.element = element;
_this.options = options;
_this.bindings = bindings;
if (element instanceof HTMLInputElement) {
_this.logger.error('Querybox cannot be used on an HTMLInputElement');
}
_this.options = ComponentOptions_1.ComponentOptions.initComponentOptions(element, Querybox, options);
new QueryboxOptionsProcessing_1.QueryboxOptionsProcessing(_this).postProcess();
Dom_1.$$(_this.element).toggleClass('coveo-query-syntax-disabled', _this.options.enableQuerySyntax == false);
_this.magicBox = MagicBox_1.createMagicBox(element, new Grammar_1.Grammar('Query', {
Query: '[Term*][Spaces?]',
Term: '[Spaces?][Word]',
Spaces: / +/,
Word: /[^ ]+/
}), {
inline: true
});
var input = Dom_1.$$(_this.magicBox.element).find('input');
if (input) {
Dom_1.$$(input).setAttribute('aria-label', _this.options.placeholder || Strings_1.l('Search'));
}
_this.bind.onRootElement(QueryEvents_1.QueryEvents.buildingQuery, function (args) { return _this.handleBuildingQuery(args); });
_this.bind.onRootElement(StandaloneSearchInterfaceEvents_1.StandaloneSearchInterfaceEvents.beforeRedirect, function () { return _this.updateQueryState(); });
_this.bind.onQueryState(Model_1.MODEL_EVENTS.CHANGE_ONE, QueryStateModel_1.QUERY_STATE_ATTRIBUTES.Q, function (args) {
return _this.handleQueryStateChanged(args);
});
if (_this.options.enableSearchAsYouType) {
Dom_1.$$(_this.element).addClass('coveo-search-as-you-type');
_this.magicBox.onchange = function () {
_this.searchAsYouType();
};
}
_this.magicBox.onsubmit = function () {
_this.submit();
};
_this.magicBox.onblur = function () {
_this.updateQueryState();
};
_this.magicBox.onclear = function () {
_this.updateQueryState();
if (_this.options.triggerQueryOnClear) {
_this.usageAnalytics.logSearchEvent(AnalyticsActionListMeta_1.analyticsActionCauseList.searchboxClear, {});
_this.triggerNewQuery(false);
}
};
return _this;
}
/**
* Adds the current content of the input to the query and triggers a query if the current content of the input has
* changed since last submit.
*
* Also logs the `serachboxSubmit` event in the usage analytics.
*/
Querybox.prototype.submit = function () {
this.magicBox.clearSuggestion();
this.updateQueryState();
this.usageAnalytics.logSearchEvent(AnalyticsActionListMeta_1.analyticsActionCauseList.searchboxSubmit, {});
this.triggerNewQuery(false);
};
/**
* Sets the content of the input.
*
* @param text The string to set in the input.
*/
Querybox.prototype.setText = function (text) {
this.magicBox.setText(text);
this.updateQueryState();
};
/**
* Clears the content of the input.
*
* See also the [`triggerQueryOnClear`]{@link Querybox.options.triggerQueryOnClear} option.
*/
Querybox.prototype.clear = function () {
this.magicBox.clear();
};
/**
* Gets the content of the input.
*
* @returns {string} The content of the input.
*/
Querybox.prototype.getText = function () {
return this.magicBox.getText();
};
/**
* Gets the result from the input.
*
* @returns {Result} The result.
*/
Querybox.prototype.getResult = function () {
return this.magicBox.getResult();
};
/**
* Gets the displayed result from the input.
*
* @returns {Result} The displayed result.
*/
Querybox.prototype.getDisplayedResult = function () {
return this.magicBox.getDisplayedResult();
};
/**
* Gets the current cursor position in the input.
*
* @returns {number} The cursor position (index starts at 0).
*/
Querybox.prototype.getCursor = function () {
return this.magicBox.getCursor();
};
/**
* Gets the result at cursor position.
*
* @param match {string | { (result): boolean }} The match condition.
*
* @returns {Result[]} The result.
*/
Querybox.prototype.resultAtCursor = function (match) {
return this.magicBox.resultAtCursor(match);
};
Querybox.prototype.handleBuildingQuery = function (args) {
Assert_1.Assert.exists(args);
Assert_1.Assert.exists(args.queryBuilder);
this.updateQueryState();
this.lastQuery = this.magicBox.getText();
new QueryboxQueryParameters_1.QueryboxQueryParameters(this.options).addParameters(args.queryBuilder, this.lastQuery);
};
Querybox.prototype.triggerNewQuery = function (searchAsYouType) {
clearTimeout(this.searchAsYouTypeTimeout);
var text = this.magicBox.getText();
if (this.lastQuery != text && text != null) {
this.lastQuery = text;
this.queryController.executeQuery({
searchAsYouType: searchAsYouType,
logInActionsHistory: true
});
}
};
Querybox.prototype.updateQueryState = function () {
this.queryStateModel.set(QueryStateModel_1.QueryStateModel.attributesEnum.q, this.magicBox.getText());
};
Querybox.prototype.handleQueryStateChanged = function (args) {
Assert_1.Assert.exists(args);
var q = args.value;
if (q != this.magicBox.getText()) {
this.magicBox.setText(q);
}
};
Querybox.prototype.searchAsYouType = function () {
var _this = this;
clearTimeout(this.searchAsYouTypeTimeout);
this.searchAsYouTypeTimeout = window.setTimeout(function () {
_this.usageAnalytics.logSearchAsYouType(AnalyticsActionListMeta_1.analyticsActionCauseList.searchboxAsYouType, {});
_this.triggerNewQuery(true);
}, this.options.searchAsYouTypeDelay);
};
Querybox.ID = 'Querybox';
Querybox.doExport = function () {
GlobalExports_1.exportGlobally({
Querybox: Querybox,
QueryboxQueryParameters: QueryboxQueryParameters_1.QueryboxQueryParameters
});
};
/**
* The options for the Querybox.
* @componentOptions
*/
Querybox.options = {
/**
* Whether to enable the search-as-you-type feature.
*
* **Note:** Enabling this feature can consume lots of queries per month (QPM), especially if the [`searchAsYouTypeDelay`]{@link Querybox.options.searchAsYouTypeDelay} option is set to a low value.
*
* Default value is `false`.
*/
enableSearchAsYouType: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: false, section: 'Advanced Options' }),
/**
* If the [`enableSearchAsYouType`]{@link Querybox.options.enableSearchAsYouType} option is `true`, specifies how
* long to wait (in milliseconds) between each key press before triggering a new query.
*
* Default value is `50`. Minimum value is `0`
*/
searchAsYouTypeDelay: ComponentOptions_1.ComponentOptions.buildNumberOption({ defaultValue: 50, min: 0, section: 'Advanced Options' }),
/**
* Specifies whether to interpret special query syntax (e.g., `@objecttype=message`) when the end user types
* a query in the `Querybox` (see
* [Coveo Query Syntax Reference](https://docs.coveo.com/en/1552/searching-with-coveo/coveo-cloud-query-syntax)). Setting this
* option to `true` also causes the `Querybox` to highlight any query syntax.
*
* Regardless of the value of this option, the Coveo Cloud REST Search API always interprets expressions surrounded
* by double quotes (`"`) as exact phrase match requests.
*
* See also [`enableLowercaseOperators`]{@link Querybox.options.enableLowercaseOperators}.
*
* **Notes:**
* > * End user preferences can override the value you specify for this option.
* >
* > If the end user selects a value other than **Automatic** for the **Enable query syntax** setting (see
* > the [`enableQuerySyntax`]{@link ResultsPreferences.options.enableQuerySyntax} option of the
* > [`ResultsPreferences`]{@link ResultsPreferences} component), the end user preference takes precedence over this
* > option.
* >
* > * On-premises versions of the Coveo Search API require this option to be set to `true` in order to interpret
* > expressions surrounded by double quotes (`"`) as exact phrase match requests.
*
* Default value is `false`.
*/
enableQuerySyntax: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: false, section: 'Advanced Options' }),
/**
* Specifies whether to expand basic expression keywords containing wildcards characters (`*`) to the possible
* matching keywords in order to broaden the query (see
* [Using Wildcards in Queries](https://docs.coveo.com/en/1580/)).
*
* See also [`enableQuestionMarks`]{@link Querybox.options.enableQuestionMarks}.
*
* **Note:**
* > If you are using an on-premises version of the Coveo Search API, you need to set the
* > [`enableQuerySyntax`]{@link Querybox.options.enableQuerySyntax} option to `true` to be able to set
* > `enableWildcards` to `true`.
*
* Default value is `false`.
*/
enableWildcards: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: false, section: 'Advanced Options' }),
/**
* If [`enableWildcards`]{@link Querybox.options.enableWildcards} is `true`, specifies whether to expand basic
* expression keywords containing question mark characters (`?`) to the possible matching keywords in order to
* broaden the query (see
* [Using Wildcards in Queries](https://docs.coveo.com/en/1580/)).
*
* **Note:**
* > If you are using an on-premises version of the Coveo Search API, you also need to set the
* > [`enableQuerySyntax`]{@link Querybox.options.enableQuerySyntax} option to `true` in order to be able to set
* > `enableQuestionMarks` to `true`.
*
* Default value is `false`.
*/
enableQuestionMarks: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: false, depend: 'enableWildcards' }),
/**
* If the [`enableQuerySyntax`]{@link Querybox.options.enableQuerySyntax} option is `true`, specifies whether to
* interpret the `AND`, `NOT`, `OR`, and `NEAR` keywords in the `Querybox` as query operators in the query, even if
* the end user types those keywords in lowercase.
*
* This option applies to all query operators (see
* [Coveo Query Syntax Reference](https://docs.coveo.com/en/1552/searching-with-coveo/coveo-cloud-query-syntax)).
*
* **Example:**
* > If this option and the `enableQuerySyntax` option are both `true`, the Coveo Platform interprets the `near`
* > keyword in a query such as `service center near me` as the `NEAR` query operator (not as a query term).
*
* > Otherwise, if the `enableQuerySyntax` option is `true` and this option is `false`, the end user has to type the
* > `NEAR` keyword in uppercase for the Coveo Platform to interpret it as a query operator.
*
* Default value is `false`.
*/
enableLowercaseOperators: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: false, depend: 'enableQuerySyntax' }),
/**
* Whether to convert a basic expression containing at least a certain number of keywords (see the
* [`partialMatchKeywords`]{@link Querybox.options.partialMatchKeywords} option) to *partial match expression*, so
* that items containing at least a certain number of those keywords (see the
* [`partialMatchThreshold`]{@link Querybox.options.partialMatchThreshold} option) will match the expression.
*
* **Notes:**
* - Only the basic expression of the query (see [`q`]{@link q}) can be converted to a partial match expression.
* - When the [`enableQuerySyntax`]{@link Querybox.options.enableQuerySyntax} option is set to `true`, this feature has no effect if the basic expression contains advanced query syntax (field expressions, operators, etc.).
*
* @notSupportedIn salesforcefree
*/
enablePartialMatch: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: false }),
/**
* The minimum number of keywords that need to be present in the basic expression to convert it to a partial match expression.
*
* See also the [`partialMatchThreshold`]{@link Querybox.options.partialMatchThreshold} option.
*
* **Notes:**
*
* - Repeated keywords count as a single keyword.
* - Thesaurus expansions count towards the `partialMatchKeywords` count.
* - Stemming expansions **do not** count towards the `partialMatchKeywords` count.
*
* @notSupportedIn salesforcefree
*/
partialMatchKeywords: ComponentOptions_1.ComponentOptions.buildNumberOption({ defaultValue: 5, min: 1, depend: 'enablePartialMatch' }),
/**
* An absolute or relative value indicating the minimum number of partial match expression keywords an item must contain to match the expression.
*
* See also the [`partialMatchKeywords`]{@link Querybox.options.partialMatchKeywords} option.
*
* **Notes:**
* - A keyword and its stemming expansions count as a single keyword when evaluating whether an item meets the `partialMatchThreshold`.
* - When a relative `partialMatchThreshold` does not yield a whole integer, the fractional part is truncated (e.g., `3.6` becomes `3`).
*
* @notSupportedIn salesforcefree
*/
partialMatchThreshold: ComponentOptions_1.ComponentOptions.buildStringOption({ defaultValue: '50%', depend: 'enablePartialMatch' }),
/**
* Whether to trigger a query when clearing the `Querybox`.
*
* Default value is `false`.
*/
triggerQueryOnClear: ComponentOptions_1.ComponentOptions.buildBooleanOption({ defaultValue: false })
};
return Querybox;
}(Component_1.Component));
exports.Querybox = Querybox;
Initialization_1.Initialization.registerAutoCreateComponent(Querybox);
/***/ }),
/***/ 176:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ExpressionRef_1 = __webpack_require__(493);
var ExpressionOptions_1 = __webpack_require__(495);
var ExpressionRegExp_1 = __webpack_require__(497);
var _ = __webpack_require__(0);
var ExpressionFunction_1 = __webpack_require__(498);
var ExpressionConstant_1 = __webpack_require__(219);
var ExpressionList_1 = __webpack_require__(499);
var Grammar = /** @class */ (function () {
function Grammar(start, expressions) {
if (expressions === void 0) { expressions = {}; }
this.expressions = {};
this.start = new ExpressionRef_1.ExpressionRef(start, null, 'start', this);
this.addExpressions(expressions);
}
Grammar.prototype.addExpressions = function (expressions) {
var _this = this;
_.each(expressions, function (basicExpression, id) {
_this.addExpression(id, basicExpression);
});
};
Grammar.prototype.addExpression = function (id, basicExpression) {
if (id in this.expressions) {
throw new Error('Grammar already contain the id:' + id);
}
this.expressions[id] = Grammar.buildExpression(basicExpression, id, this);
};
Grammar.prototype.getExpression = function (id) {
return this.expressions[id];
};
Grammar.prototype.parse = function (value) {
return this.start.parse(value, true);
};
Grammar.buildExpression = function (value, id, grammar) {
var type = typeof value;
if (type == 'undefined') {
throw new Error('Invalid Expression: ' + value);
}
if (_.isString(value)) {
return this.buildStringExpression(value, id, grammar);
}
if (_.isArray(value)) {
return new ExpressionOptions_1.ExpressionOptions(_.map(value, function (v, i) { return new ExpressionRef_1.ExpressionRef(v, null, id + '_' + i, grammar); }), id);
}
if (_.isRegExp(value)) {
return new ExpressionRegExp_1.ExpressionRegExp(value, id, grammar);
}
if (_.isFunction(value)) {
return new ExpressionFunction_1.ExpressionFunction(value, id, grammar);
}
throw new Error('Invalid Expression: ' + value);
};
Grammar.buildStringExpression = function (value, id, grammar) {
var matchs = Grammar.stringMatch(value, Grammar.spliter);
var expressions = _.map(matchs, function (match, i) {
if (match[1]) {
// Ref
var ref = match[1];
var occurrence = match[3] ? Number(match[3]) : match[2] || null;
return new ExpressionRef_1.ExpressionRef(ref, occurrence, id + '_' + i, grammar);
}
else {
// Constant
return new ExpressionConstant_1.ExpressionConstant(match[4], id + '_' + i);
}
});
if (expressions.length == 1) {
var expression = expressions[0];
expression.id = id;
return expression;
}
else {
return new ExpressionList_1.ExpressionList(expressions, id);
}
};
Grammar.stringMatch = function (str, re) {
var groups = [];
var cloneRegExp = new RegExp(re.source, 'g');
var group = cloneRegExp.exec(str);
while (group !== null) {
groups.push(group);
group = cloneRegExp.exec(str);
}
return groups;
};
Grammar.spliter = /\[(\w+)(\*|\+|\?|\{([1-9][0-9]*)\})?\]|(.[^\[]*)/;
return Grammar;
}());
exports.Grammar = Grammar;
/***/ }),
/***/ 218:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExpressionEndOfInput = {
id: 'end of input',
parse: null
};
/***/ }),
/***/ 219:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Result_1 = __webpack_require__(52);
var Result_2 = __webpack_require__(52);
var ExpressionConstant = /** @class */ (function () {
function ExpressionConstant(value, id) {
this.value = value;
this.id = id;
}
ExpressionConstant.prototype.parse = function (input, end) {
// the value must be at the start of the input
var success = input.indexOf(this.value) == 0;
var result = new Result_1.Result(success ? this.value : null, this, input);
// if is successful and we require the end but the length of parsed is
// lower than the input length, return a EndOfInputExpected Result
if (success && end && input.length > this.value.length) {
return new Result_2.EndOfInputResult(result);
}
return result;
};
ExpressionConstant.prototype.toString = function () {
return this.value;
};
return ExpressionConstant;
}());
exports.ExpressionConstant = ExpressionConstant;
/***/ }),
/***/ 220:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Basic_1 = __webpack_require__(133);
var Date_1 = __webpack_require__(501);
exports.Field = {
basicExpressions: ['FieldSimpleQuery', 'FieldQuery', 'Field'],
grammars: {
FieldQuery: '[Field][OptionalSpaces][FieldQueryOperation]',
FieldQueryOperation: ['FieldQueryValue', 'FieldQueryNumeric'],
FieldQueryValue: '[FieldOperator][OptionalSpaces][FieldValue]',
FieldQueryNumeric: '[FieldOperatorNumeric][OptionalSpaces][FieldValueNumeric]',
FieldSimpleQuery: '[FieldName]:[OptionalSpaces][FieldValue]',
Field: '@[FieldName]',
FieldName: /[a-zA-Z][a-zA-Z0-9\.\_]*/,
FieldOperator: /==|=|<>/,
FieldOperatorNumeric: /<=|>=|<|>/,
FieldValue: ['DateRange', 'NumberRange', 'DateRelative', 'Date', 'Number', 'FieldValueList', 'FieldValueString'],
FieldValueNumeric: ['DateRelative', 'Date', 'Number'],
FieldValueString: ['DoubleQuoted', 'FieldValueNotQuoted'],
FieldValueList: '([FieldValueString][FieldValueStringList*])',
FieldValueStringList: '[FieldValueSeparator][FieldValueString]',
FieldValueSeparator: / *, */,
FieldValueNotQuoted: /[^ \(\)\[\],]+/,
NumberRange: '[Number][Spaces?]..[Spaces?][Number]'
},
include: [Date_1.Date, Basic_1.Basic]
};
/***/ }),
/***/ 221:
/***/ (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 underscore_1 = __webpack_require__(0);
var OmniboxEvents_1 = __webpack_require__(34);
var Component_1 = __webpack_require__(7);
var Dom_1 = __webpack_require__(1);
var ResultPreviewsManager_1 = __webpack_require__(564);
var QueryProcessor_1 = __webpack_require__(505);
var QueryUtils_1 = __webpack_require__(21);
var Direction;
(function (Direction) {
Direction["Up"] = "Up";
Direction["Down"] = "Down";
Direction["Left"] = "Left";
Direction["Right"] = "Right";
})(Direction = exports.Direction || (exports.Direction = {}));
var SuggestionsManager = /** @class */ (function () {
function SuggestionsManager(element, magicBoxContainer, inputManager, options) {
var _this = this;
this.element = element;
this.magicBoxContainer = magicBoxContainer;
this.inputManager = inputManager;
this.suggestionListboxID = "coveo-magicbox-suggestions-" + QueryUtils_1.QueryUtils.createGuid();
this.suggestionListboxClassName = "coveo-magicbox-suggestions";
this.root = Component_1.Component.resolveRoot(element);
this.options = underscore_1.defaults(options, {
suggestionClass: 'magic-box-suggestion',
selectedClass: 'magic-box-selected'
});
// Put in a sane default, so as to not reject every suggestions if not set on initialization
if (this.options.timeout == undefined) {
this.options.timeout = 500;
}
Dom_1.$$(this.element).on('mouseover', function (e) {
_this.handleMouseOver(e);
});
Dom_1.$$(this.element).on('mouseout', function (e) {
_this.handleMouseOut(e);
});
this.suggestionsProcessor = new QueryProcessor_1.QueryProcessor({ timeout: this.options.timeout });
this.resultPreviewsManager = new ResultPreviewsManager_1.ResultPreviewsManager(element, {
selectedClass: this.options.selectedClass,
timeout: this.options.timeout
});
this.suggestionsListbox = this.buildSuggestionsContainer();
Dom_1.$$(this.element).append(this.suggestionsListbox.el);
this.addAccessibilityProperties();
this.appendEmptySuggestionOption();
}
Object.defineProperty(SuggestionsManager.prototype, "hasSuggestions", {
get: function () {
return this.currentSuggestions && this.currentSuggestions.length > 0;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SuggestionsManager.prototype, "hasFocus", {
get: function () {
return Dom_1.$$(this.element).findClass(this.options.selectedClass).length > 0;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SuggestionsManager.prototype, "hasPreviews", {
get: function () {
return this.resultPreviewsManager.hasPreviews;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SuggestionsManager.prototype, "focusedSuggestion", {
get: function () {
var _this = this;
return underscore_1.find(this.currentSuggestions, function (suggestion) {
return Dom_1.$$(suggestion.dom).hasClass(_this.options.selectedClass) || Dom_1.$$(suggestion.dom).findClass(_this.options.selectedClass).length > 0;
});
},
enumerable: true,
configurable: true
});
SuggestionsManager.prototype.handleMouseOver = function (e) {
var target = Dom_1.$$(e.target);
var parents = target.parents(this.options.suggestionClass);
if (target.hasClass(this.options.suggestionClass)) {
this.processMouseSelection(target.el);
}
else if (parents.length > 0 && this.element.contains(parents[0])) {
this.processMouseSelection(parents[0]);
}
};
SuggestionsManager.prototype.handleMouseOut = function (e) {
var target = Dom_1.$$(e.target);
var targetParents = target.parents(this.options.suggestionClass);
//e.relatedTarget is not available if moving off the browser window or is an empty object `{}` when moving out of namespace in LockerService.
if (e.relatedTarget && Dom_1.$$(e.relatedTarget).isValid()) {
var relatedTargetParents = Dom_1.$$(e.relatedTarget).parents(this.options.suggestionClass);
if (target.hasClass(this.options.selectedClass) && !Dom_1.$$(e.relatedTarget).hasClass(this.options.suggestionClass)) {
this.removeSelectedStatus(target.el);
}
else if (relatedTargetParents.length == 0 && targetParents.length > 0) {
this.removeSelectedStatus(targetParents[0]);
}
}
else {
if (target.hasClass(this.options.selectedClass)) {
this.removeSelectedStatus(target.el);
}
else if (targetParents.length > 0) {
this.removeSelectedStatus(targetParents[0]);
}
}
Dom_1.$$(this.root).trigger(OmniboxEvents_1.OmniboxEvents.querySuggestLoseFocus);
};
SuggestionsManager.prototype.moveDown = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.move(Direction.Down)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
SuggestionsManager.prototype.moveUp = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.move(Direction.Up)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
SuggestionsManager.prototype.moveLeft = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.move(Direction.Left)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
SuggestionsManager.prototype.moveRight = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.move(Direction.Right)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
SuggestionsManager.prototype.selectAndReturnKeyboardFocusedElement = function () {
var selected = this.keyboardFocusedElement;
if (selected) {
Dom_1.$$(selected).trigger('keyboardSelect');
// By definition, once an element has been "selected" with the keyboard,
// it is not longer "active" since the event has been processed.
this.keyboardFocusedElement = null;
this.inputManager.blur();
}
return selected;
};
SuggestionsManager.prototype.clearKeyboardFocusedElement = function () {
this.keyboardFocusedElement = null;
};
SuggestionsManager.prototype.receiveSuggestions = function (suggestions) {
return __awaiter(this, void 0, void 0, function () {
var _a, results, status;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.suggestionsProcessor.processQueries(suggestions)];
case 1:
_a = _b.sent(), results = _a.results, status = _a.status;
if (status === QueryProcessor_1.ProcessingStatus.Overriden) {
return [2 /*return*/, []];
}
this.updateSuggestions(results);
return [2 /*return*/, results];
}
});
});
};
SuggestionsManager.prototype.clearSuggestions = function () {
this.updateSuggestions([]);
};
SuggestionsManager.prototype.updateSuggestions = function (suggestions) {
var _this = this;
this.suggestionsListbox.empty();
this.inputManager.activeDescendant = null;
this.currentSuggestions = suggestions;
Dom_1.$$(this.element).toggleClass('magic-box-hasSuggestion', this.hasSuggestions);
this.inputManager.expanded = this.hasSuggestions;
this.resultPreviewsManager.displaySearchResultPreviewsForSuggestion(null);
if (!this.hasSuggestions) {
this.appendEmptySuggestionOption();
Dom_1.$$(this.root).trigger(OmniboxEvents_1.OmniboxEvents.querySuggestLoseFocus);
return;
}
suggestions
.sort(function (a, b) { return (b.index || 0) - (a.index || 0); })
.forEach(function (suggestion) {
var dom = suggestion.dom ? _this.modifyDomFromExistingSuggestion(suggestion.dom) : _this.createDomFromSuggestion(suggestion);
dom.setAttribute('id', "magic-box-suggestion-" + underscore_1.indexOf(suggestions, suggestion));
dom.setAttribute('role', 'option');
dom.setAttribute('aria-selected', 'false');
dom.setAttribute('aria-label', dom.text());
dom['suggestion'] = suggestion;
_this.suggestionsListbox.append(dom.el);
});
var numberOfSuggestions = this.suggestionsListbox.findAll("." + this.options.suggestionClass).length;
Dom_1.$$(this.root).trigger(OmniboxEvents_1.OmniboxEvents.querySuggestRendered, { numberOfSuggestions: numberOfSuggestions });
};
Object.defineProperty(SuggestionsManager.prototype, "selectedSuggestion", {
get: function () {
if (this.htmlElementIsSuggestion(this.keyboardFocusedElement)) {
return this.returnMoved(this.keyboardFocusedElement);
}
return null;
},
enumerable: true,
configurable: true
});
SuggestionsManager.prototype.processKeyboardSelection = function (suggestion) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.addSelectedStatus(suggestion);
this.keyboardFocusedElement = suggestion;
return [4 /*yield*/, this.updateSelectedSuggestion(this.focusedSuggestion)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
SuggestionsManager.prototype.processKeyboardPreviewSelection = function (preview) {
this.addSelectedStatus(preview);
this.keyboardFocusedElement = preview;
};
SuggestionsManager.prototype.processMouseSelection = function (suggestion) {
this.addSelectedStatus(suggestion);
this.updateSelectedSuggestion(this.focusedSuggestion);
this.keyboardFocusedElement = null;
};
SuggestionsManager.prototype.buildSuggestionsContainer = function () {
return Dom_1.$$('div', {
className: this.suggestionListboxClassName,
id: this.suggestionListboxID,
role: 'listbox',
ariaLabel: 'Search Suggestions'
});
};
SuggestionsManager.prototype.createDomFromSuggestion = function (suggestion) {
var _this = this;
var dom = Dom_1.$$('div', {
className: "magic-box-suggestion " + this.options.suggestionClass
});
suggestion.dom = dom.el;
dom.on('click', function () {
_this.selectSuggestion(suggestion);
});
dom.on('keyboardSelect', function () {
_this.selectSuggestion(suggestion);
});
if (suggestion.html) {
dom.el.innerHTML = suggestion.html;
return dom;
}
if (suggestion.text) {
dom.text(suggestion.text);
return dom;
}
if (suggestion.separator) {
dom.addClass('magic-box-suggestion-seperator');
var suggestionLabel = Dom_1.$$('div', {
className: 'magic-box-suggestion-seperator-label'
}, suggestion.separator);
dom.append(suggestionLabel.el);
return dom;
}
return dom;
};
SuggestionsManager.prototype.selectSuggestion = function (suggestion) {
suggestion.onSelect();
Dom_1.$$(this.root).trigger(OmniboxEvents_1.OmniboxEvents.querySuggestSelection, { suggestion: suggestion.text });
};
SuggestionsManager.prototype.appendEmptySuggestionOption = function () {
// Accessibility tools reports that a listbox element must always have at least one child with an option
// Even if there is no suggestions to show.
this.suggestionsListbox.append(Dom_1.$$('div', { role: 'option' }).el);
};
SuggestionsManager.prototype.modifyDomFromExistingSuggestion = function (dom) {
// this need to be done if the selection is in cache and the dom is set in the suggestion
this.removeSelectedStatus(dom);
var found = dom.classList.contains(this.options.suggestionClass) ? dom : Dom_1.$$(dom).find('.' + this.options.suggestionClass);
this.removeSelectedStatus(found);
return Dom_1.$$(dom);
};
SuggestionsManager.prototype.move = function (direction) {
return __awaiter(this, void 0, void 0, function () {
var firstPreview;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.resultPreviewsManager.focusedPreviewElement) return [3 /*break*/, 2];
return [4 /*yield*/, this.moveWithinPreview(direction)];
case 1:
_a.sent();
return [2 /*return*/];
case 2:
if (direction === Direction.Right || direction === Direction.Left) {
firstPreview = this.resultPreviewsManager.previewElements[0];
if (firstPreview) {
this.processKeyboardPreviewSelection(firstPreview);
return [2 /*return*/];
}
}
return [4 /*yield*/, this.moveWithinSuggestion(direction)];
case 3:
_a.sent();
return [2 /*return*/];
}
});
});
};
SuggestionsManager.prototype.moveWithinSuggestion = function (direction) {
return __awaiter(this, void 0, void 0, function () {
var currentlySelected, selectables, currentIndex, index;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
currentlySelected = Dom_1.$$(this.element).find("." + this.options.selectedClass);
selectables = Dom_1.$$(this.element).findAll("." + this.options.suggestionClass);
currentIndex = underscore_1.indexOf(selectables, currentlySelected);
index = direction === Direction.Up ? currentIndex - 1 : currentIndex + 1;
index = (index + selectables.length) % selectables.length;
return [4 /*yield*/, this.selectQuerySuggest(selectables[index])];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
SuggestionsManager.prototype.selectQuerySuggest = function (suggestion) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!suggestion) return [3 /*break*/, 2];
return [4 /*yield*/, this.processKeyboardSelection(suggestion)];
case 1:
_a.sent();
return [3 /*break*/, 3];
case 2:
this.keyboardFocusedElement = null;
this.inputManager.input.removeAttribute('aria-activedescendant');
_a.label = 3;
case 3: return [2 /*return*/, suggestion];
}
});
});
};
SuggestionsManager.prototype.moveWithinPreview = function (direction) {
return __awaiter(this, void 0, void 0, function () {
var newFocusedPreview;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
newFocusedPreview = this.resultPreviewsManager.getElementInDirection(direction);
if (!!newFocusedPreview) return [3 /*break*/, 2];
return [4 /*yield*/, this.selectQuerySuggest(this.resultPreviewsManager.previewsOwner.dom)];
case 1:
_a.sent();
return [2 /*return*/];
case 2:
this.processKeyboardPreviewSelection(newFocusedPreview);
return [2 /*return*/];
}
});
});
};
SuggestionsManager.prototype.returnMoved = function (selected) {
if (selected) {
if (selected['suggestion']) {
return selected['suggestion'];
}
if (selected['no-text-suggestion']) {
return null;
}
if (selected instanceof HTMLElement) {
return {
text: Dom_1.$$(selected).text()
};
}
}
return null;
};
SuggestionsManager.prototype.addSelectedStatus = function (element) {
var selected = this.element.getElementsByClassName(this.options.selectedClass);
for (var i = 0; i < selected.length; i++) {
var elem = selected.item(i);
this.removeSelectedStatus(elem);
}
Dom_1.$$(element).addClass(this.options.selectedClass);
this.updateAreaSelectedIfDefined(element, 'true');
};
SuggestionsManager.prototype.updateSelectedSuggestion = function (suggestion) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
Dom_1.$$(this.root).trigger(OmniboxEvents_1.OmniboxEvents.querySuggestGetFocus, {
suggestion: suggestion.text
});
return [4 /*yield*/, this.resultPreviewsManager.displaySearchResultPreviewsForSuggestion(suggestion)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
SuggestionsManager.prototype.removeSelectedStatus = function (suggestion) {
Dom_1.$$(suggestion).removeClass(this.options.selectedClass);
this.updateAreaSelectedIfDefined(suggestion, 'false');
};
SuggestionsManager.prototype.updateAreaSelectedIfDefined = function (element, value) {
if (Dom_1.$$(element).getAttribute('aria-selected')) {
this.inputManager.activeDescendant = element;
Dom_1.$$(element).setAttribute('aria-selected', value);
}
};
SuggestionsManager.prototype.addAccessibilityProperties = function () {
this.addAccessibilityPropertiesForMagicBox();
this.addAccessibilityPropertiesForInput();
};
SuggestionsManager.prototype.addAccessibilityPropertiesForMagicBox = function () {
var magicBox = Dom_1.$$(this.magicBoxContainer);
magicBox.setAttribute('role', 'search');
magicBox.setAttribute('aria-haspopup', 'listbox');
};
SuggestionsManager.prototype.addAccessibilityPropertiesForInput = function () {
var input = Dom_1.$$(this.inputManager.input);
this.inputManager.activeDescendant = null;
this.inputManager.expanded = false;
input.setAttribute('aria-owns', this.suggestionListboxID);
input.setAttribute('aria-controls', this.suggestionListboxID);
};
SuggestionsManager.prototype.htmlElementIsSuggestion = function (selected) {
var omniboxSelectables = Dom_1.$$(this.element).findAll("." + this.options.suggestionClass);
return underscore_1.indexOf(omniboxSelectables, selected) > -1;
};
return SuggestionsManager;
}());
exports.SuggestionsManager = SuggestionsManager;
/***/ }),
/***/ 222:
/***/ (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(fulf