UNPKG

coveo-search-ui

Version:

Coveo JavaScript Search Framework

540 lines (526 loc) • 24.3 kB
webpackJsonpCoveo__temporary([41],{ /***/ 196: /***/ (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__(580); var GlobalExports_1 = __webpack_require__(3); var QueryEvents_1 = __webpack_require__(11); var Assert_1 = __webpack_require__(5); var Model_1 = __webpack_require__(18); var QueryStateModel_1 = __webpack_require__(13); var Dom_1 = __webpack_require__(1); var SVGDom_1 = __webpack_require__(16); var SVGIcons_1 = __webpack_require__(12); var Utils_1 = __webpack_require__(4); var SharedAnalyticsCalls_1 = __webpack_require__(126); var Component_1 = __webpack_require__(7); var ComponentOptions_1 = __webpack_require__(8); var Initialization_1 = __webpack_require__(2); var SortCriteria_1 = __webpack_require__(507); var AccessibleButton_1 = __webpack_require__(15); var Strings_1 = __webpack_require__(6); var underscore_1 = __webpack_require__(0); /** * The `Sort` component renders a widget that the end user can interact with to select the criterion to use when sorting query results. * * To improve accessibility, it's recommended to group `Sort` components in a container with `role="radiogroup"`. */ var Sort = /** @class */ (function (_super) { __extends(Sort, _super); /** * Creates a new `Sort` component instance. * @param element The HTMLElement on which to instantiate the component. * @param options The options for this component instance. * @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 Sort(element, options, bindings) { var _this = _super.call(this, element, Sort.ID, bindings) || this; _this.element = element; _this.options = options; _this.options = ComponentOptions_1.ComponentOptions.initComponentOptions(element, Sort, options); Assert_1.Assert.isLargerOrEqualsThan(1, _this.options.sortCriteria.length); _this.bind.onQueryState(Model_1.MODEL_EVENTS.CHANGE_ONE, QueryStateModel_1.QUERY_STATE_ATTRIBUTES.SORT, function () { return _this.handleQueryStateChanged(); }); _this.bind.onRootElement(QueryEvents_1.QueryEvents.querySuccess, function (args) { return _this.handleQuerySuccess(args); }); _this.bind.onRootElement(QueryEvents_1.QueryEvents.buildingQuery, function (args) { return _this.handleBuildingQuery(args); }); _this.bind.onRootElement(QueryEvents_1.QueryEvents.queryError, function (args) { return _this.handleQueryError(args); }); _this.ensureDom(); return _this; } Sort.prototype.createDom = function () { var _this = this; var el = Dom_1.$$(this.element); el.on('click', function () { return _this.selectAndExecuteQuery(); }); var innerText = el.text(); el.empty(); this.findOrCreateRadioGroup(); this.createSortButton(innerText); if (this.isToggle()) { this.createDirectionButton(); } this.update(); }; /** * Selects this `Sort` component. * * Updates the state model if selecting this component toggles its current [`sortCriteria`]{@link Sort.options.sortCriteria}. * * @param direction The sort direction. Can be one of: `ascending`, `descending`. */ Sort.prototype.select = function (direction) { if (direction) { this.currentCriteria = underscore_1.find(this.options.sortCriteria, function (criteria) { return criteria.direction == direction; }); this.updateQueryStateModel(); } else if (Utils_1.Utils.exists(this.currentCriteria)) { this.selectNextCriteria(); } else { this.selectFirstCriteria(); } }; /** * Selects this `Sort` component, then triggers a query if selecting this component toggles its current [`sortCriteria`]{@link Sort.options.sortCriteria}. * * Also logs an event in the usage analytics with the new current sort criteria. */ Sort.prototype.selectAndExecuteQuery = function () { var oldCriteria = this.currentCriteria; this.select(); if (oldCriteria != this.currentCriteria) { this.executeSearchQuery(); } }; Sort.prototype.enable = function () { Dom_1.$$(this.element).removeClass('coveo-tab-disabled'); this.update(); _super.prototype.enable.call(this); }; Sort.prototype.disable = function () { Dom_1.$$(this.element).addClass('coveo-tab-disabled'); _super.prototype.disable.call(this); }; /** * Gets the current [`sortCriteria`]{@link Sort.options.sortCriteria} of this `Sort` component. * @returns {SortCriteria} */ Sort.prototype.getCurrentCriteria = function () { return this.currentCriteria; }; /** * Indicates whether the name of any of the available [`sortCriteria`]{@link Sort.options.sortCriteria} of this `Sort` component matches the argument. * @param sortId The sort criteria name to look for (e.g., `date descending`). */ Sort.prototype.match = function (sortId) { return underscore_1.any(this.options.sortCriteria, function (sortCriteria) { return sortId == sortCriteria.toString(); }); }; Sort.prototype.findOrCreateRadioGroup = function () { this.radioGroup = this.findRadioGroup(); if (!this.radioGroup) { this.element.setAttribute('role', 'radiogroup'); this.radioGroup = this.element; } }; Sort.prototype.createSortButton = function (innerText) { var _this = this; this.sortButton = Dom_1.$$('span').el; this.sortButton.innerText = this.options.caption || innerText; new AccessibleButton_1.AccessibleButton() .withElement(this.sortButton) .withEnterKeyboardAction(function () { return _this.selectAndExecuteQuery(); }) .withArrowsAction(function (direction, e) { return _this.onArrowPressed(direction, e); }) .withLabel(this.isToggle() ? this.getDirectionalLabel(this.initialDirection) : this.getOmnidirectionalLabel()) .withRole('radio') .build(); this.element.appendChild(this.sortButton); }; Sort.prototype.createDirectionButton = function () { var _this = this; this.directionButton = Dom_1.$$.apply(void 0, ['span', { className: 'coveo-icon' }].concat(this.createIcons())).el; new AccessibleButton_1.AccessibleButton() .withElement(this.directionButton) .withSelectAction(function (e) { e.stopPropagation(); _this.selectNextCriteriaAndExecuteQuery(); }) .withArrowsAction(function (direction, e) { return _this.onArrowPressed(direction, e); }) .withLabel(this.getDirectionalLabel(this.initialDirection === SortCriteria_1.VALID_DIRECTION.DESCENDING ? SortCriteria_1.VALID_DIRECTION.ASCENDING : SortCriteria_1.VALID_DIRECTION.DESCENDING)) .withRole('radio') .build(); this.element.appendChild(this.directionButton); }; Sort.prototype.onArrowPressed = function (direction, e) { this.selectNextRadioButton(direction === AccessibleButton_1.ArrowDirection.RIGHT || direction === AccessibleButton_1.ArrowDirection.DOWN ? 1 : -1); e.stopPropagation(); }; Sort.prototype.createIcons = function () { var iconAscending = Dom_1.$$('span', { className: 'coveo-sort-icon-ascending' }, SVGIcons_1.SVGIcons.icons.arrowUp); SVGDom_1.SVGDom.addClassToSVGInContainer(iconAscending.el, 'coveo-sort-icon-ascending-svg'); var iconDescending = Dom_1.$$('span', { className: 'coveo-sort-icon-descending' }, SVGIcons_1.SVGIcons.icons.arrowDown); SVGDom_1.SVGDom.addClassToSVGInContainer(iconDescending.el, 'coveo-sort-icon-descending-svg'); return [iconAscending, iconDescending]; }; Sort.prototype.findRadioGroup = function (element) { if (element === void 0) { element = this.element; } if (!element || element === document.body) { return null; } if (element.getAttribute('role') === 'radiogroup') { return element; } return this.findRadioGroup(element.parentElement); }; Sort.prototype.selectNextRadioButton = function (direction) { if (direction === void 0) { direction = 1; } var radioButtons = Dom_1.$$(this.radioGroup).findAll('[role="radio"]'); var currentIndex = underscore_1.findIndex(radioButtons, function (radio) { return radio.getAttribute('aria-checked') === 'true'; }); var indexToSelect; var isAnythingSelected = currentIndex !== -1; if (isAnythingSelected) { indexToSelect = (currentIndex + direction + radioButtons.length) % radioButtons.length; } else { if (direction >= 0) { indexToSelect = 0; } else { indexToSelect = radioButtons.length - 1; } } var radioToSelect = radioButtons[indexToSelect]; radioToSelect.focus(); radioToSelect.click(); }; Sort.prototype.executeSearchQuery = function () { var _this = this; this.queryController.deferExecuteQuery({ beforeExecuteQuery: function () { return SharedAnalyticsCalls_1.logSortEvent(_this.usageAnalytics, _this.currentCriteria.sort + _this.currentCriteria.direction); } }); }; Sort.prototype.selectFirstCriteria = function () { this.currentCriteria = this.options.sortCriteria[0]; this.updateQueryStateModel(); }; Sort.prototype.selectNextCriteria = function () { var indexOfCurrentCriteria = this.currentCriteria ? this.options.sortCriteria.indexOf(this.currentCriteria) : 0; this.currentCriteria = this.options.sortCriteria[(indexOfCurrentCriteria + 1) % this.options.sortCriteria.length]; this.updateQueryStateModel(); }; Sort.prototype.selectNextCriteriaAndExecuteQuery = function () { var oldCriteria = this.currentCriteria; this.selectNextCriteria(); if (oldCriteria != this.currentCriteria) { this.executeSearchQuery(); } }; Sort.prototype.handleQueryStateChanged = function () { this.update(); }; Sort.prototype.update = function () { // Basically, if the criteria in the model fits with one of ours, it'll become our active criteria var sortCriteria = this.queryStateModel.get(QueryStateModel_1.QueryStateModel.attributesEnum.sort); if (Utils_1.Utils.isNonEmptyString(sortCriteria)) { var criteriaFromModel = SortCriteria_1.SortCriteria.parse(sortCriteria); this.currentCriteria = underscore_1.find(this.options.sortCriteria, function (criteria) { return criteriaFromModel.equals(criteria); }); } else { this.currentCriteria = null; } this.updateAppearance(); this.updateAccessibilityProperties(); }; Object.defineProperty(Sort.prototype, "captionIsDefined", { get: function () { return Utils_1.Utils.isNonEmptyString(this.options.caption); }, enumerable: true, configurable: true }); Object.defineProperty(Sort.prototype, "currentDirection", { get: function () { return this.currentCriteria ? this.currentCriteria.direction : this.initialDirection; }, enumerable: true, configurable: true }); Object.defineProperty(Sort.prototype, "initialDirection", { get: function () { return this.options.sortCriteria[0].direction; }, enumerable: true, configurable: true }); Object.defineProperty(Sort.prototype, "displayedSortText", { get: function () { return this.captionIsDefined ? this.options.caption : this.element.textContent; }, enumerable: true, configurable: true }); Sort.prototype.handleBuildingQuery = function (data) { Assert_1.Assert.exists(data); var sort = this.queryStateModel.get(QueryStateModel_1.QueryStateModel.attributesEnum.sort); if (sort == QueryStateModel_1.QueryStateModel.defaultAttributes.sort || this.isSelected()) { if (this.currentCriteria) { this.currentCriteria.putInQueryBuilder(data.queryBuilder); } } }; Sort.prototype.handleQuerySuccess = function (data) { if (data.results.results.length == 0) { Dom_1.$$(this.element).addClass('coveo-sort-hidden'); } else { Dom_1.$$(this.element).removeClass('coveo-sort-hidden'); } }; Sort.prototype.handleQueryError = function (data) { Dom_1.$$(this.element).addClass('coveo-sort-hidden'); }; Sort.prototype.isToggle = function () { return this.options.sortCriteria.length > 1; }; Sort.prototype.isSelected = function () { return Utils_1.Utils.exists(this.currentCriteria); }; Sort.prototype.updateAppearance = function () { Dom_1.$$(this.element).toggleClass('coveo-selected', this.isSelected()); if (this.isToggle()) { Dom_1.$$(this.element).removeClass('coveo-ascending'); Dom_1.$$(this.element).removeClass('coveo-descending'); if (this.isSelected()) { Dom_1.$$(this.element).addClass(this.currentDirection === 'ascending' ? 'coveo-ascending' : 'coveo-descending'); } } }; Sort.prototype.updateAccessibilityProperties = function () { this.sortButton.setAttribute('aria-controls', this.resultListsIds); var directionIsInitial = this.currentDirection === this.initialDirection; this.sortButton.setAttribute('aria-checked', "" + (this.isSelected() && directionIsInitial)); if (this.isToggle()) { this.directionButton.setAttribute('aria-controls', this.resultListsIds); this.directionButton.setAttribute('aria-checked', "" + (this.isSelected() && !directionIsInitial)); } }; Object.defineProperty(Sort.prototype, "resultListsIds", { get: function () { var resultLists = this.searchInterface.getComponents('ResultList'); return resultLists.map(function (resultList) { return resultList.element.id; }).join(' '); }, enumerable: true, configurable: true }); Sort.prototype.getDirectionalLabel = function (direction) { var localizedCaption = Strings_1.l(this.displayedSortText); return direction === SortCriteria_1.VALID_DIRECTION.DESCENDING ? Strings_1.l('SortResultsByDescending', localizedCaption) : Strings_1.l('SortResultsByAscending', localizedCaption); }; Sort.prototype.getOmnidirectionalLabel = function () { var localizedCaption = Strings_1.l(this.displayedSortText); return Strings_1.l('SortResultsBy', localizedCaption); }; Sort.prototype.updateQueryStateModel = function () { this.queryStateModel.set(QueryStateModel_1.QueryStateModel.attributesEnum.sort, this.currentCriteria.toString()); }; Sort.ID = 'Sort'; Sort.doExport = function () { GlobalExports_1.exportGlobally({ Sort: Sort, SortCriteria: SortCriteria_1.SortCriteria }); }; /** * Options for the component * @componentOptions */ Sort.options = { /** * The sort criterion/criteria the end user can select/toggle between when interacting with this component instance. * * The available sort criteria are: * - `relevancy` * - `date ascending`/`date descending` * - `qre` * - `@field ascending`/`@field descending`, where you must replace `field` with the name of a sortable field in your index (e.g., `data-sort-criteria="@size ascending"`). * * You can specify a comma separated list of sort criteria to toggle between when interacting with this component instance (e.g., `data-sort-criteria="date descending,date ascending"`). * * You can specify multiple sort criteria to be used in the same request by separating them with a semicolon (e.g., `data-sort-criteria="@size ascending;date ascending"` ). * * Interacting with this component instance will cycle through those criteria in the order they are listed in. * Typically, you should only specify a list of sort criteria when you want the end user to be able to to toggle the direction of a `date` or `@field` sort criteria. * Otherwise, you should configure a distinct `Sort` component instance for each sort criterion you want to make available in your search page. * * You must specify a valid value for this option in order for this component instance to work correctly. * * Examples: * * - `data-sort-criteria="date ascending"` createes a Sort component that allows to sort on `date ascending`, without being able to toggle the order. * - `data-sort-criteria="date ascending, date descending"` creates a Sort component that allows end users to toggle between `date ascending` and `date descending` on click. * - `data-sort-criteria="@size ascending; date descending"` creates a Sort component that only allows end users to sort on `@size ascending`. The index then applies a second sort on `date descending` when two items are of equal value. * - `data-sort-criteria="@size ascending; date descending, @size descending; date descending"` creates a Sort component that allows end users to toggle between `@size ascending` and `@size descending`. For each value, the index applies a second sort on `date descending` when two items are of equal value. */ sortCriteria: ComponentOptions_1.ComponentOptions.buildCustomListOption(function (values) { return values.map(function (criteria) { // 'any' because Underscore won't accept the union type as an argument. if (typeof criteria === 'string') { return new SortCriteria_1.SortCriteria(criteria); } else { return criteria; } }); }, { required: true }), /** * The caption to display on this component instance. * * By default, the component uses the text content of the element it is instanciated on. */ caption: ComponentOptions_1.ComponentOptions.buildLocalizedStringOption({ required: true }) }; return Sort; }(Component_1.Component)); exports.Sort = Sort; Initialization_1.Initialization.registerAutoCreateComponent(Sort); /***/ }), /***/ 507: /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var underscore_1 = __webpack_require__(0); var Assert_1 = __webpack_require__(5); var VALID_SORT; (function (VALID_SORT) { VALID_SORT["RELEVANCY"] = "relevancy"; VALID_SORT["DATE"] = "date"; VALID_SORT["QRE"] = "qre"; })(VALID_SORT = exports.VALID_SORT || (exports.VALID_SORT = {})); var VALID_DIRECTION; (function (VALID_DIRECTION) { VALID_DIRECTION["ASCENDING"] = "ascending"; VALID_DIRECTION["DESCENDING"] = "descending"; })(VALID_DIRECTION = exports.VALID_DIRECTION || (exports.VALID_DIRECTION = {})); var SortCriterion = /** @class */ (function () { /** * Create a new SortCriteria * @param sort The sort criteria (e.g.: relevancy, date) * @param direction The direction by which to sort (e.g.: ascending, descending) */ function SortCriterion(sort, direction) { if (direction === void 0) { direction = ''; } this.sort = sort; this.direction = direction; if (!SortCriterion.sortIsField(sort)) { Assert_1.Assert.check(this.isValidSort(sort), sort + " is not a valid sort criteria. Valid values are " + underscore_1.values(VALID_SORT) + " or a valid index sortable index field."); } if (SortCriterion.sortNeedsDirection(sort)) { Assert_1.Assert.check(this.isValidDirection(direction), direction + " is not a valid sort criteria direction. Valid values are " + underscore_1.values(VALID_DIRECTION)); } else { Assert_1.Assert.check(direction == ''); } } SortCriterion.prototype.isValidDirection = function (direction) { return underscore_1.chain(VALID_DIRECTION) .values() .contains(direction) .value(); }; SortCriterion.prototype.isValidSort = function (sort) { return underscore_1.chain(VALID_SORT) .values() .contains(sort) .value(); }; SortCriterion.sortIsField = function (criteria) { return criteria.charAt(0) == '@'; }; SortCriterion.sortNeedsDirection = function (sort) { return underscore_1.contains(SortCriterion.sortsNeedingDirection, sort) || SortCriterion.sortIsField(sort); }; SortCriterion.sortsNeedingDirection = [VALID_SORT.DATE]; return SortCriterion; }()); exports.SortCriterion = SortCriterion; var SortCriteria = /** @class */ (function () { function SortCriteria(rawCriteriaString) { var _this = this; this.criteria = []; var criteria = rawCriteriaString.split(';'); criteria.forEach(function (criterion) { var split = criterion.match(/\S+/g); _this.criteria.push(new SortCriterion(split[0], split[1])); }); } Object.defineProperty(SortCriteria.prototype, "direction", { get: function () { return underscore_1.first(this.criteria).direction; }, enumerable: true, configurable: true }); Object.defineProperty(SortCriteria.prototype, "sort", { get: function () { return underscore_1.first(this.criteria).sort; }, enumerable: true, configurable: true }); /** * Return a new SortCriteria from a string * @param criteria The string from which to create the SortCriteria */ SortCriteria.parse = function (criteria) { return new SortCriteria(criteria); }; /** * Put the sort criteria in the passed queryBuilder * @param queryBuilder The queryBuilder in which to put the sort criteria. */ SortCriteria.prototype.putInQueryBuilder = function (queryBuilder) { Assert_1.Assert.exists(queryBuilder); queryBuilder.sortCriteria = this.toString() .split(';') .join(','); }; /** * Returns a string representation of the sort criteria (e.g.: 'date ascending'). */ SortCriteria.prototype.toString = function () { return this.criteria .map(function (criterion) { return criterion.direction ? criterion.sort + " " + criterion.direction : "" + criterion.sort; }) .join(';'); }; /** * Checks if the SortCriteria is equal to another. * @param criteria The SortCriteria to compare with */ SortCriteria.prototype.equals = function (criteria) { return criteria.toString() == this.toString(); }; return SortCriteria; }()); exports.SortCriteria = SortCriteria; /***/ }), /***/ 580: /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }) }); //# sourceMappingURL=Sort__65d8de8a9f769489e2ff.js.map