Files
rancher-docs/assets/js/1a4e3797.4d0973e9.js

6787 lines
230 KiB
JavaScript

(self["webpackChunkrancher_docs"] = self["webpackChunkrancher_docs"] || []).push([[97920],{
/***/ 17331:
/***/ ((module) => {
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
// EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
args = Array.prototype.slice.call(arguments, 1);
handler.apply(this, args);
}
} else if (isObject(handler)) {
args = Array.prototype.slice.call(arguments, 1);
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.prototype.listenerCount = function(type) {
if (this._events) {
var evlistener = this._events[type];
if (isFunction(evlistener))
return 1;
else if (evlistener)
return evlistener.length;
}
return 0;
};
EventEmitter.listenerCount = function(emitter, type) {
return emitter.listenerCount(type);
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
/***/ }),
/***/ 8131:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
var AlgoliaSearchHelper = __webpack_require__(49374);
var SearchParameters = __webpack_require__(17775);
var SearchResults = __webpack_require__(23076);
/**
* The algoliasearchHelper module is the function that will let its
* contains everything needed to use the Algoliasearch
* Helper. It is a also a function that instanciate the helper.
* To use the helper, you also need the Algolia JS client v3.
* @example
* //using the UMD build
* var client = algoliasearch('latency', '6be0576ff61c053d5f9a3225e2a90f76');
* var helper = algoliasearchHelper(client, 'bestbuy', {
* facets: ['shipping'],
* disjunctiveFacets: ['category']
* });
* helper.on('result', function(event) {
* console.log(event.results);
* });
* helper
* .toggleFacetRefinement('category', 'Movies & TV Shows')
* .toggleFacetRefinement('shipping', 'Free shipping')
* .search();
* @example
* // The helper is an event emitter using the node API
* helper.on('result', updateTheResults);
* helper.once('result', updateTheResults);
* helper.removeListener('result', updateTheResults);
* helper.removeAllListeners('result');
* @module algoliasearchHelper
* @param {AlgoliaSearch} client an AlgoliaSearch client
* @param {string} index the name of the index to query
* @param {SearchParameters|object} opts an object defining the initial config of the search. It doesn't have to be a {SearchParameters}, just an object containing the properties you need from it.
* @return {AlgoliaSearchHelper} The helper instance
*/
function algoliasearchHelper(client, index, opts) {
return new AlgoliaSearchHelper(client, index, opts);
}
/**
* The version currently used
* @member module:algoliasearchHelper.version
* @type {number}
*/
algoliasearchHelper.version = __webpack_require__(24336);
/**
* Constructor for the Helper.
* @member module:algoliasearchHelper.AlgoliaSearchHelper
* @type {AlgoliaSearchHelper}
*/
algoliasearchHelper.AlgoliaSearchHelper = AlgoliaSearchHelper;
/**
* Constructor for the object containing all the parameters of the search.
* @member module:algoliasearchHelper.SearchParameters
* @type {SearchParameters}
*/
algoliasearchHelper.SearchParameters = SearchParameters;
/**
* Constructor for the object containing the results of the search.
* @member module:algoliasearchHelper.SearchResults
* @type {SearchResults}
*/
algoliasearchHelper.SearchResults = SearchResults;
module.exports = algoliasearchHelper;
/***/ }),
/***/ 68078:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
var EventEmitter = __webpack_require__(17331);
var inherits = __webpack_require__(14853);
/**
* A DerivedHelper is a way to create sub requests to
* Algolia from a main helper.
* @class
* @classdesc The DerivedHelper provides an event based interface for search callbacks:
* - search: when a search is triggered using the `search()` method.
* - result: when the response is retrieved from Algolia and is processed.
* This event contains a {@link SearchResults} object and the
* {@link SearchParameters} corresponding to this answer.
* @param {AlgoliaSearchHelper} mainHelper the main helper
* @param {function} fn the function to create the derived state
*/
function DerivedHelper(mainHelper, fn) {
this.main = mainHelper;
this.fn = fn;
this.lastResults = null;
}
inherits(DerivedHelper, EventEmitter);
/**
* Detach this helper from the main helper
* @return {undefined}
* @throws Error if the derived helper is already detached
*/
DerivedHelper.prototype.detach = function () {
this.removeAllListeners();
this.main.detachDerivedHelper(this);
};
DerivedHelper.prototype.getModifiedState = function (parameters) {
return this.fn(parameters);
};
module.exports = DerivedHelper;
/***/ }),
/***/ 82437:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/**
* Functions to manipulate refinement lists
*
* The RefinementList is not formally defined through a prototype but is based
* on a specific structure.
*
* @module SearchParameters.refinementList
*
* @typedef {string[]} SearchParameters.refinementList.Refinements
* @typedef {Object.<string, SearchParameters.refinementList.Refinements>} SearchParameters.refinementList.RefinementList
*/
var defaultsPure = __webpack_require__(52344);
var objectHasKeys = __webpack_require__(90116);
var omit = __webpack_require__(49803);
var lib = {
/**
* Adds a refinement to a RefinementList
* @param {RefinementList} refinementList the initial list
* @param {string} attribute the attribute to refine
* @param {string} value the value of the refinement, if the value is not a string it will be converted
* @return {RefinementList} a new and updated refinement list
*/
addRefinement: function addRefinement(refinementList, attribute, value) {
if (lib.isRefined(refinementList, attribute, value)) {
return refinementList;
}
var valueAsString = '' + value;
var facetRefinement = !refinementList[attribute]
? [valueAsString]
: refinementList[attribute].concat(valueAsString);
var mod = {};
mod[attribute] = facetRefinement;
return defaultsPure({}, mod, refinementList);
},
/**
* Removes refinement(s) for an attribute:
* - if the value is specified removes the refinement for the value on the attribute
* - if no value is specified removes all the refinements for this attribute
* @param {RefinementList} refinementList the initial list
* @param {string} attribute the attribute to refine
* @param {string} [value] the value of the refinement
* @return {RefinementList} a new and updated refinement lst
*/
removeRefinement: function removeRefinement(
refinementList,
attribute,
value
) {
if (value === undefined) {
// we use the "filter" form of clearRefinement, since it leaves empty values as-is
// the form with a string will remove the attribute completely
return lib.clearRefinement(refinementList, function (v, f) {
return attribute === f;
});
}
var valueAsString = '' + value;
return lib.clearRefinement(refinementList, function (v, f) {
return attribute === f && valueAsString === v;
});
},
/**
* Toggles the refinement value for an attribute.
* @param {RefinementList} refinementList the initial list
* @param {string} attribute the attribute to refine
* @param {string} value the value of the refinement
* @return {RefinementList} a new and updated list
*/
toggleRefinement: function toggleRefinement(
refinementList,
attribute,
value
) {
if (value === undefined)
throw new Error('toggleRefinement should be used with a value');
if (lib.isRefined(refinementList, attribute, value)) {
return lib.removeRefinement(refinementList, attribute, value);
}
return lib.addRefinement(refinementList, attribute, value);
},
/**
* Clear all or parts of a RefinementList. Depending on the arguments, three
* kinds of behavior can happen:
* - if no attribute is provided: clears the whole list
* - if an attribute is provided as a string: clears the list for the specific attribute
* - if an attribute is provided as a function: discards the elements for which the function returns true
* @param {RefinementList} refinementList the initial list
* @param {string} [attribute] the attribute or function to discard
* @param {string} [refinementType] optional parameter to give more context to the attribute function
* @return {RefinementList} a new and updated refinement list
*/
clearRefinement: function clearRefinement(
refinementList,
attribute,
refinementType
) {
if (attribute === undefined) {
// return the same object if the list is already empty
// this is mainly for tests, as it doesn't have much impact on performance
if (!objectHasKeys(refinementList)) {
return refinementList;
}
return {};
} else if (typeof attribute === 'string') {
return omit(refinementList, [attribute]);
} else if (typeof attribute === 'function') {
var hasChanged = false;
var newRefinementList = Object.keys(refinementList).reduce(function (
memo,
key
) {
var values = refinementList[key] || [];
var facetList = values.filter(function (value) {
return !attribute(value, key, refinementType);
});
if (facetList.length !== values.length) {
hasChanged = true;
}
memo[key] = facetList;
return memo;
},
{});
if (hasChanged) return newRefinementList;
return refinementList;
}
// We return nothing if the attribute is not undefined, a string or a function,
// as it is not a valid value for a refinement
return undefined;
},
/**
* Test if the refinement value is used for the attribute. If no refinement value
* is provided, test if the refinementList contains any refinement for the
* given attribute.
* @param {RefinementList} refinementList the list of refinement
* @param {string} attribute name of the attribute
* @param {string} [refinementValue] value of the filter/refinement
* @return {boolean} true if the attribute is refined, false otherwise
*/
isRefined: function isRefined(refinementList, attribute, refinementValue) {
var containsRefinements =
Boolean(refinementList[attribute]) &&
refinementList[attribute].length > 0;
if (refinementValue === undefined || !containsRefinements) {
return containsRefinements;
}
var refinementValueAsString = '' + refinementValue;
return refinementList[attribute].indexOf(refinementValueAsString) !== -1;
},
};
module.exports = lib;
/***/ }),
/***/ 17775:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
var defaultsPure = __webpack_require__(52344);
var find = __webpack_require__(7888);
var intersection = __webpack_require__(22686);
var merge = __webpack_require__(60185);
var objectHasKeys = __webpack_require__(90116);
var omit = __webpack_require__(49803);
var valToNumber = __webpack_require__(28023);
var isValidUserToken = __webpack_require__(46801);
var RefinementList = __webpack_require__(82437);
/**
* isEqual, but only for numeric refinement values, possible values:
* - 5
* - [5]
* - [[5]]
* - [[5,5],[4]]
* @param {any} a numeric refinement value
* @param {any} b numeric refinement value
* @return {boolean} true if the values are equal
*/
function isEqualNumericRefinement(a, b) {
if (Array.isArray(a) && Array.isArray(b)) {
return (
a.length === b.length &&
a.every(function (el, i) {
return isEqualNumericRefinement(b[i], el);
})
);
}
return a === b;
}
/**
* like _.find but using deep equality to be able to use it
* to find arrays.
* @private
* @param {any[]} array array to search into (elements are base or array of base)
* @param {any} searchedValue the value we're looking for (base or array of base)
* @return {any} the searched value or undefined
*/
function findArray(array, searchedValue) {
return find(array, function (currentValue) {
return isEqualNumericRefinement(currentValue, searchedValue);
});
}
/**
* The facet list is the structure used to store the list of values used to
* filter a single attribute.
* @typedef {string[]} SearchParameters.FacetList
*/
/**
* Structure to store numeric filters with the operator as the key. The supported operators
* are `=`, `>`, `<`, `>=`, `<=` and `!=`.
* @typedef {Object.<string, Array.<number|number[]>>} SearchParameters.OperatorList
*/
/**
* SearchParameters is the data structure that contains all the information
* usable for making a search to Algolia API. It doesn't do the search itself,
* nor does it contains logic about the parameters.
* It is an immutable object, therefore it has been created in a way that each
* changes does not change the object itself but returns a copy with the
* modification.
* This object should probably not be instantiated outside of the helper. It will
* be provided when needed. This object is documented for reference as you'll
* get it from events generated by the {@link AlgoliaSearchHelper}.
* If need be, instantiate the Helper from the factory function {@link SearchParameters.make}
* @constructor
* @classdesc contains all the parameters of a search
* @param {object|SearchParameters} newParameters existing parameters or partial object
* for the properties of a new SearchParameters
* @see SearchParameters.make
* @example <caption>SearchParameters of the first query in
* <a href="http://demos.algolia.com/instant-search-demo/">the instant search demo</a></caption>
{
"query": "",
"disjunctiveFacets": [
"customerReviewCount",
"category",
"salePrice_range",
"manufacturer"
],
"maxValuesPerFacet": 30,
"page": 0,
"hitsPerPage": 10,
"facets": [
"type",
"shipping"
]
}
*/
function SearchParameters(newParameters) {
var params = newParameters
? SearchParameters._parseNumbers(newParameters)
: {};
if (params.userToken !== undefined && !isValidUserToken(params.userToken)) {
// eslint-disable-next-line no-console
console.warn(
'[algoliasearch-helper] The `userToken` parameter is invalid. This can lead to wrong analytics.\n - Format: [a-zA-Z0-9_-]{1,64}'
);
}
/**
* This attribute contains the list of all the conjunctive facets
* used. This list will be added to requested facets in the
* [facets attribute](https://www.algolia.com/doc/rest-api/search#param-facets) sent to algolia.
* @member {string[]}
*/
this.facets = params.facets || [];
/**
* This attribute contains the list of all the disjunctive facets
* used. This list will be added to requested facets in the
* [facets attribute](https://www.algolia.com/doc/rest-api/search#param-facets) sent to algolia.
* @member {string[]}
*/
this.disjunctiveFacets = params.disjunctiveFacets || [];
/**
* This attribute contains the list of all the hierarchical facets
* used. This list will be added to requested facets in the
* [facets attribute](https://www.algolia.com/doc/rest-api/search#param-facets) sent to algolia.
* Hierarchical facets are a sub type of disjunctive facets that
* let you filter faceted attributes hierarchically.
* @member {string[]|object[]}
*/
this.hierarchicalFacets = params.hierarchicalFacets || [];
// Refinements
/**
* This attribute contains all the filters that need to be
* applied on the conjunctive facets. Each facet must be properly
* defined in the `facets` attribute.
*
* The key is the name of the facet, and the `FacetList` contains all
* filters selected for the associated facet name.
*
* When querying algolia, the values stored in this attribute will
* be translated into the `facetFilters` attribute.
* @member {Object.<string, SearchParameters.FacetList>}
*/
this.facetsRefinements = params.facetsRefinements || {};
/**
* This attribute contains all the filters that need to be
* excluded from the conjunctive facets. Each facet must be properly
* defined in the `facets` attribute.
*
* The key is the name of the facet, and the `FacetList` contains all
* filters excluded for the associated facet name.
*
* When querying algolia, the values stored in this attribute will
* be translated into the `facetFilters` attribute.
* @member {Object.<string, SearchParameters.FacetList>}
*/
this.facetsExcludes = params.facetsExcludes || {};
/**
* This attribute contains all the filters that need to be
* applied on the disjunctive facets. Each facet must be properly
* defined in the `disjunctiveFacets` attribute.
*
* The key is the name of the facet, and the `FacetList` contains all
* filters selected for the associated facet name.
*
* When querying algolia, the values stored in this attribute will
* be translated into the `facetFilters` attribute.
* @member {Object.<string, SearchParameters.FacetList>}
*/
this.disjunctiveFacetsRefinements = params.disjunctiveFacetsRefinements || {};
/**
* This attribute contains all the filters that need to be
* applied on the numeric attributes.
*
* The key is the name of the attribute, and the value is the
* filters to apply to this attribute.
*
* When querying algolia, the values stored in this attribute will
* be translated into the `numericFilters` attribute.
* @member {Object.<string, SearchParameters.OperatorList>}
*/
this.numericRefinements = params.numericRefinements || {};
/**
* This attribute contains all the tags used to refine the query.
*
* When querying algolia, the values stored in this attribute will
* be translated into the `tagFilters` attribute.
* @member {string[]}
*/
this.tagRefinements = params.tagRefinements || [];
/**
* This attribute contains all the filters that need to be
* applied on the hierarchical facets. Each facet must be properly
* defined in the `hierarchicalFacets` attribute.
*
* The key is the name of the facet, and the `FacetList` contains all
* filters selected for the associated facet name. The FacetList values
* are structured as a string that contain the values for each level
* separated by the configured separator.
*
* When querying algolia, the values stored in this attribute will
* be translated into the `facetFilters` attribute.
* @member {Object.<string, SearchParameters.FacetList>}
*/
this.hierarchicalFacetsRefinements =
params.hierarchicalFacetsRefinements || {};
// eslint-disable-next-line consistent-this
var self = this;
Object.keys(params).forEach(function (paramName) {
var isKeyKnown = SearchParameters.PARAMETERS.indexOf(paramName) !== -1;
var isValueDefined = params[paramName] !== undefined;
if (!isKeyKnown && isValueDefined) {
self[paramName] = params[paramName];
}
});
}
/**
* List all the properties in SearchParameters and therefore all the known Algolia properties
* This doesn't contain any beta/hidden features.
* @private
*/
SearchParameters.PARAMETERS = Object.keys(new SearchParameters());
/**
* @private
* @param {object} partialState full or part of a state
* @return {object} a new object with the number keys as number
*/
SearchParameters._parseNumbers = function (partialState) {
// Do not parse numbers again in SearchParameters, they ought to be parsed already
if (partialState instanceof SearchParameters) return partialState;
var numbers = {};
var numberKeys = [
'aroundPrecision',
'aroundRadius',
'getRankingInfo',
'minWordSizefor2Typos',
'minWordSizefor1Typo',
'page',
'maxValuesPerFacet',
'distinct',
'minimumAroundRadius',
'hitsPerPage',
'minProximity',
];
numberKeys.forEach(function (k) {
var value = partialState[k];
if (typeof value === 'string') {
var parsedValue = parseFloat(value);
// global isNaN is ok to use here, value is only number or NaN
numbers[k] = isNaN(parsedValue) ? value : parsedValue;
}
});
// there's two formats of insideBoundingBox, we need to parse
// the one which is an array of float geo rectangles
if (Array.isArray(partialState.insideBoundingBox)) {
numbers.insideBoundingBox = partialState.insideBoundingBox.map(function (
geoRect
) {
if (Array.isArray(geoRect)) {
return geoRect.map(function (value) {
return parseFloat(value);
});
}
return geoRect;
});
}
if (partialState.numericRefinements) {
var numericRefinements = {};
Object.keys(partialState.numericRefinements).forEach(function (attribute) {
var operators = partialState.numericRefinements[attribute] || {};
numericRefinements[attribute] = {};
Object.keys(operators).forEach(function (operator) {
var values = operators[operator];
var parsedValues = values.map(function (v) {
if (Array.isArray(v)) {
return v.map(function (vPrime) {
if (typeof vPrime === 'string') {
return parseFloat(vPrime);
}
return vPrime;
});
} else if (typeof v === 'string') {
return parseFloat(v);
}
return v;
});
numericRefinements[attribute][operator] = parsedValues;
});
});
numbers.numericRefinements = numericRefinements;
}
return merge({}, partialState, numbers);
};
/**
* Factory for SearchParameters
* @param {object|SearchParameters} newParameters existing parameters or partial
* object for the properties of a new SearchParameters
* @return {SearchParameters} frozen instance of SearchParameters
*/
SearchParameters.make = function makeSearchParameters(newParameters) {
var instance = new SearchParameters(newParameters);
var hierarchicalFacets = newParameters.hierarchicalFacets || [];
hierarchicalFacets.forEach(function (facet) {
if (facet.rootPath) {
var currentRefinement = instance.getHierarchicalRefinement(facet.name);
if (
currentRefinement.length > 0 &&
currentRefinement[0].indexOf(facet.rootPath) !== 0
) {
instance = instance.clearRefinements(facet.name);
}
// get it again in case it has been cleared
currentRefinement = instance.getHierarchicalRefinement(facet.name);
if (currentRefinement.length === 0) {
instance = instance.toggleHierarchicalFacetRefinement(
facet.name,
facet.rootPath
);
}
}
});
return instance;
};
/**
* Validates the new parameters based on the previous state
* @param {SearchParameters} currentState the current state
* @param {object|SearchParameters} parameters the new parameters to set
* @return {Error|null} Error if the modification is invalid, null otherwise
*/
SearchParameters.validate = function (currentState, parameters) {
var params = parameters || {};
if (
currentState.tagFilters &&
params.tagRefinements &&
params.tagRefinements.length > 0
) {
return new Error(
'[Tags] Cannot switch from the managed tag API to the advanced API. It is probably ' +
'an error, if it is really what you want, you should first clear the tags with clearTags method.'
);
}
if (currentState.tagRefinements.length > 0 && params.tagFilters) {
return new Error(
'[Tags] Cannot switch from the advanced tag API to the managed API. It is probably ' +
'an error, if it is not, you should first clear the tags with clearTags method.'
);
}
if (
currentState.numericFilters &&
params.numericRefinements &&
objectHasKeys(params.numericRefinements)
) {
return new Error(
"[Numeric filters] Can't switch from the advanced to the managed API. It" +
' is probably an error, if this is really what you want, you have to first' +
' clear the numeric filters.'
);
}
if (objectHasKeys(currentState.numericRefinements) && params.numericFilters) {
return new Error(
"[Numeric filters] Can't switch from the managed API to the advanced. It" +
' is probably an error, if this is really what you want, you have to first' +
' clear the numeric filters.'
);
}
return null;
};
SearchParameters.prototype = {
constructor: SearchParameters,
/**
* Remove all refinements (disjunctive + conjunctive + excludes + numeric filters)
* @method
* @param {undefined|string|SearchParameters.clearCallback} [attribute] optional string or function
* - If not given, means to clear all the filters.
* - If `string`, means to clear all refinements for the `attribute` named filter.
* - If `function`, means to clear all the refinements that return truthy values.
* @return {SearchParameters} new instance with filters cleared
*/
clearRefinements: function clearRefinements(attribute) {
var patch = {
numericRefinements: this._clearNumericRefinements(attribute),
facetsRefinements: RefinementList.clearRefinement(
this.facetsRefinements,
attribute,
'conjunctiveFacet'
),
facetsExcludes: RefinementList.clearRefinement(
this.facetsExcludes,
attribute,
'exclude'
),
disjunctiveFacetsRefinements: RefinementList.clearRefinement(
this.disjunctiveFacetsRefinements,
attribute,
'disjunctiveFacet'
),
hierarchicalFacetsRefinements: RefinementList.clearRefinement(
this.hierarchicalFacetsRefinements,
attribute,
'hierarchicalFacet'
),
};
if (
patch.numericRefinements === this.numericRefinements &&
patch.facetsRefinements === this.facetsRefinements &&
patch.facetsExcludes === this.facetsExcludes &&
patch.disjunctiveFacetsRefinements ===
this.disjunctiveFacetsRefinements &&
patch.hierarchicalFacetsRefinements === this.hierarchicalFacetsRefinements
) {
return this;
}
return this.setQueryParameters(patch);
},
/**
* Remove all the refined tags from the SearchParameters
* @method
* @return {SearchParameters} new instance with tags cleared
*/
clearTags: function clearTags() {
if (this.tagFilters === undefined && this.tagRefinements.length === 0)
return this;
return this.setQueryParameters({
tagFilters: undefined,
tagRefinements: [],
});
},
/**
* Set the index.
* @method
* @param {string} index the index name
* @return {SearchParameters} new instance
*/
setIndex: function setIndex(index) {
if (index === this.index) return this;
return this.setQueryParameters({
index: index,
});
},
/**
* Query setter
* @method
* @param {string} newQuery value for the new query
* @return {SearchParameters} new instance
*/
setQuery: function setQuery(newQuery) {
if (newQuery === this.query) return this;
return this.setQueryParameters({
query: newQuery,
});
},
/**
* Page setter
* @method
* @param {number} newPage new page number
* @return {SearchParameters} new instance
*/
setPage: function setPage(newPage) {
if (newPage === this.page) return this;
return this.setQueryParameters({
page: newPage,
});
},
/**
* Facets setter
* The facets are the simple facets, used for conjunctive (and) faceting.
* @method
* @param {string[]} facets all the attributes of the algolia records used for conjunctive faceting
* @return {SearchParameters} new instance
*/
setFacets: function setFacets(facets) {
return this.setQueryParameters({
facets: facets,
});
},
/**
* Disjunctive facets setter
* Change the list of disjunctive (or) facets the helper chan handle.
* @method
* @param {string[]} facets all the attributes of the algolia records used for disjunctive faceting
* @return {SearchParameters} new instance
*/
setDisjunctiveFacets: function setDisjunctiveFacets(facets) {
return this.setQueryParameters({
disjunctiveFacets: facets,
});
},
/**
* HitsPerPage setter
* Hits per page represents the number of hits retrieved for this query
* @method
* @param {number} n number of hits retrieved per page of results
* @return {SearchParameters} new instance
*/
setHitsPerPage: function setHitsPerPage(n) {
if (this.hitsPerPage === n) return this;
return this.setQueryParameters({
hitsPerPage: n,
});
},
/**
* typoTolerance setter
* Set the value of typoTolerance
* @method
* @param {string} typoTolerance new value of typoTolerance ("true", "false", "min" or "strict")
* @return {SearchParameters} new instance
*/
setTypoTolerance: function setTypoTolerance(typoTolerance) {
if (this.typoTolerance === typoTolerance) return this;
return this.setQueryParameters({
typoTolerance: typoTolerance,
});
},
/**
* Add a numeric filter for a given attribute
* When value is an array, they are combined with OR
* When value is a single value, it will combined with AND
* @method
* @param {string} attribute attribute to set the filter on
* @param {string} operator operator of the filter (possible values: =, >, >=, <, <=, !=)
* @param {number | number[]} value value of the filter
* @return {SearchParameters} new instance
* @example
* // for price = 50 or 40
* state.addNumericRefinement('price', '=', [50, 40]);
* @example
* // for size = 38 and 40
* state.addNumericRefinement('size', '=', 38);
* state.addNumericRefinement('size', '=', 40);
*/
addNumericRefinement: function (attribute, operator, value) {
var val = valToNumber(value);
if (this.isNumericRefined(attribute, operator, val)) return this;
var mod = merge({}, this.numericRefinements);
mod[attribute] = merge({}, mod[attribute]);
if (mod[attribute][operator]) {
// Array copy
mod[attribute][operator] = mod[attribute][operator].slice();
// Add the element. Concat can't be used here because value can be an array.
mod[attribute][operator].push(val);
} else {
mod[attribute][operator] = [val];
}
return this.setQueryParameters({
numericRefinements: mod,
});
},
/**
* Get the list of conjunctive refinements for a single facet
* @param {string} facetName name of the attribute used for faceting
* @return {string[]} list of refinements
*/
getConjunctiveRefinements: function (facetName) {
if (!this.isConjunctiveFacet(facetName)) {
return [];
}
return this.facetsRefinements[facetName] || [];
},
/**
* Get the list of disjunctive refinements for a single facet
* @param {string} facetName name of the attribute used for faceting
* @return {string[]} list of refinements
*/
getDisjunctiveRefinements: function (facetName) {
if (!this.isDisjunctiveFacet(facetName)) {
return [];
}
return this.disjunctiveFacetsRefinements[facetName] || [];
},
/**
* Get the list of hierarchical refinements for a single facet
* @param {string} facetName name of the attribute used for faceting
* @return {string[]} list of refinements
*/
getHierarchicalRefinement: function (facetName) {
// we send an array but we currently do not support multiple
// hierarchicalRefinements for a hierarchicalFacet
return this.hierarchicalFacetsRefinements[facetName] || [];
},
/**
* Get the list of exclude refinements for a single facet
* @param {string} facetName name of the attribute used for faceting
* @return {string[]} list of refinements
*/
getExcludeRefinements: function (facetName) {
if (!this.isConjunctiveFacet(facetName)) {
return [];
}
return this.facetsExcludes[facetName] || [];
},
/**
* Remove all the numeric filter for a given (attribute, operator)
* @method
* @param {string} attribute attribute to set the filter on
* @param {string} [operator] operator of the filter (possible values: =, >, >=, <, <=, !=)
* @param {number} [number] the value to be removed
* @return {SearchParameters} new instance
*/
removeNumericRefinement: function (attribute, operator, number) {
var paramValue = number;
if (paramValue !== undefined) {
if (!this.isNumericRefined(attribute, operator, paramValue)) {
return this;
}
return this.setQueryParameters({
numericRefinements: this._clearNumericRefinements(function (
value,
key
) {
return (
key === attribute &&
value.op === operator &&
isEqualNumericRefinement(value.val, valToNumber(paramValue))
);
}),
});
} else if (operator !== undefined) {
if (!this.isNumericRefined(attribute, operator)) return this;
return this.setQueryParameters({
numericRefinements: this._clearNumericRefinements(function (
value,
key
) {
return key === attribute && value.op === operator;
}),
});
}
if (!this.isNumericRefined(attribute)) return this;
return this.setQueryParameters({
numericRefinements: this._clearNumericRefinements(function (value, key) {
return key === attribute;
}),
});
},
/**
* Get the list of numeric refinements for a single facet
* @param {string} facetName name of the attribute used for faceting
* @return {SearchParameters.OperatorList} list of refinements
*/
getNumericRefinements: function (facetName) {
return this.numericRefinements[facetName] || {};
},
/**
* Return the current refinement for the (attribute, operator)
* @param {string} attribute attribute in the record
* @param {string} operator operator applied on the refined values
* @return {Array.<number|number[]>} refined values
*/
getNumericRefinement: function (attribute, operator) {
return (
this.numericRefinements[attribute] &&
this.numericRefinements[attribute][operator]
);
},
/**
* Clear numeric filters.
* @method
* @private
* @param {string|SearchParameters.clearCallback} [attribute] optional string or function
* - If not given, means to clear all the filters.
* - If `string`, means to clear all refinements for the `attribute` named filter.
* - If `function`, means to clear all the refinements that return truthy values.
* @return {Object.<string, OperatorList>} new numeric refinements
*/
_clearNumericRefinements: function _clearNumericRefinements(attribute) {
if (attribute === undefined) {
if (!objectHasKeys(this.numericRefinements)) {
return this.numericRefinements;
}
return {};
} else if (typeof attribute === 'string') {
return omit(this.numericRefinements, [attribute]);
} else if (typeof attribute === 'function') {
var hasChanged = false;
var numericRefinements = this.numericRefinements;
var newNumericRefinements = Object.keys(numericRefinements).reduce(
function (memo, key) {
var operators = numericRefinements[key];
var operatorList = {};
operators = operators || {};
Object.keys(operators).forEach(function (operator) {
var values = operators[operator] || [];
var outValues = [];
values.forEach(function (value) {
var predicateResult = attribute(
{ val: value, op: operator },
key,
'numeric'
);
if (!predicateResult) outValues.push(value);
});
if (outValues.length !== values.length) {
hasChanged = true;
}
operatorList[operator] = outValues;
});
memo[key] = operatorList;
return memo;
},
{}
);
if (hasChanged) return newNumericRefinements;
return this.numericRefinements;
}
// We return nothing if the attribute is not undefined, a string or a function,
// as it is not a valid value for a refinement
return undefined;
},
/**
* Add a facet to the facets attribute of the helper configuration, if it
* isn't already present.
* @method
* @param {string} facet facet name to add
* @return {SearchParameters} new instance
*/
addFacet: function addFacet(facet) {
if (this.isConjunctiveFacet(facet)) {
return this;
}
return this.setQueryParameters({
facets: this.facets.concat([facet]),
});
},
/**
* Add a disjunctive facet to the disjunctiveFacets attribute of the helper
* configuration, if it isn't already present.
* @method
* @param {string} facet disjunctive facet name to add
* @return {SearchParameters} new instance
*/
addDisjunctiveFacet: function addDisjunctiveFacet(facet) {
if (this.isDisjunctiveFacet(facet)) {
return this;
}
return this.setQueryParameters({
disjunctiveFacets: this.disjunctiveFacets.concat([facet]),
});
},
/**
* Add a hierarchical facet to the hierarchicalFacets attribute of the helper
* configuration.
* @method
* @param {object} hierarchicalFacet hierarchical facet to add
* @return {SearchParameters} new instance
* @throws will throw an error if a hierarchical facet with the same name was already declared
*/
addHierarchicalFacet: function addHierarchicalFacet(hierarchicalFacet) {
if (this.isHierarchicalFacet(hierarchicalFacet.name)) {
throw new Error(
'Cannot declare two hierarchical facets with the same name: `' +
hierarchicalFacet.name +
'`'
);
}
return this.setQueryParameters({
hierarchicalFacets: this.hierarchicalFacets.concat([hierarchicalFacet]),
});
},
/**
* Add a refinement on a "normal" facet
* @method
* @param {string} facet attribute to apply the faceting on
* @param {string} value value of the attribute (will be converted to string)
* @return {SearchParameters} new instance
*/
addFacetRefinement: function addFacetRefinement(facet, value) {
if (!this.isConjunctiveFacet(facet)) {
throw new Error(
facet +
' is not defined in the facets attribute of the helper configuration'
);
}
if (RefinementList.isRefined(this.facetsRefinements, facet, value))
return this;
return this.setQueryParameters({
facetsRefinements: RefinementList.addRefinement(
this.facetsRefinements,
facet,
value
),
});
},
/**
* Exclude a value from a "normal" facet
* @method
* @param {string} facet attribute to apply the exclusion on
* @param {string} value value of the attribute (will be converted to string)
* @return {SearchParameters} new instance
*/
addExcludeRefinement: function addExcludeRefinement(facet, value) {
if (!this.isConjunctiveFacet(facet)) {
throw new Error(
facet +
' is not defined in the facets attribute of the helper configuration'
);
}
if (RefinementList.isRefined(this.facetsExcludes, facet, value))
return this;
return this.setQueryParameters({
facetsExcludes: RefinementList.addRefinement(
this.facetsExcludes,
facet,
value
),
});
},
/**
* Adds a refinement on a disjunctive facet.
* @method
* @param {string} facet attribute to apply the faceting on
* @param {string} value value of the attribute (will be converted to string)
* @return {SearchParameters} new instance
*/
addDisjunctiveFacetRefinement: function addDisjunctiveFacetRefinement(
facet,
value
) {
if (!this.isDisjunctiveFacet(facet)) {
throw new Error(
facet +
' is not defined in the disjunctiveFacets attribute of the helper configuration'
);
}
if (
RefinementList.isRefined(this.disjunctiveFacetsRefinements, facet, value)
)
return this;
return this.setQueryParameters({
disjunctiveFacetsRefinements: RefinementList.addRefinement(
this.disjunctiveFacetsRefinements,
facet,
value
),
});
},
/**
* addTagRefinement adds a tag to the list used to filter the results
* @param {string} tag tag to be added
* @return {SearchParameters} new instance
*/
addTagRefinement: function addTagRefinement(tag) {
if (this.isTagRefined(tag)) return this;
var modification = {
tagRefinements: this.tagRefinements.concat(tag),
};
return this.setQueryParameters(modification);
},
/**
* Remove a facet from the facets attribute of the helper configuration, if it
* is present.
* @method
* @param {string} facet facet name to remove
* @return {SearchParameters} new instance
*/
removeFacet: function removeFacet(facet) {
if (!this.isConjunctiveFacet(facet)) {
return this;
}
return this.clearRefinements(facet).setQueryParameters({
facets: this.facets.filter(function (f) {
return f !== facet;
}),
});
},
/**
* Remove a disjunctive facet from the disjunctiveFacets attribute of the
* helper configuration, if it is present.
* @method
* @param {string} facet disjunctive facet name to remove
* @return {SearchParameters} new instance
*/
removeDisjunctiveFacet: function removeDisjunctiveFacet(facet) {
if (!this.isDisjunctiveFacet(facet)) {
return this;
}
return this.clearRefinements(facet).setQueryParameters({
disjunctiveFacets: this.disjunctiveFacets.filter(function (f) {
return f !== facet;
}),
});
},
/**
* Remove a hierarchical facet from the hierarchicalFacets attribute of the
* helper configuration, if it is present.
* @method
* @param {string} facet hierarchical facet name to remove
* @return {SearchParameters} new instance
*/
removeHierarchicalFacet: function removeHierarchicalFacet(facet) {
if (!this.isHierarchicalFacet(facet)) {
return this;
}
return this.clearRefinements(facet).setQueryParameters({
hierarchicalFacets: this.hierarchicalFacets.filter(function (f) {
return f.name !== facet;
}),
});
},
/**
* Remove a refinement set on facet. If a value is provided, it will clear the
* refinement for the given value, otherwise it will clear all the refinement
* values for the faceted attribute.
* @method
* @param {string} facet name of the attribute used for faceting
* @param {string} [value] value used to filter
* @return {SearchParameters} new instance
*/
removeFacetRefinement: function removeFacetRefinement(facet, value) {
if (!this.isConjunctiveFacet(facet)) {
throw new Error(
facet +
' is not defined in the facets attribute of the helper configuration'
);
}
if (!RefinementList.isRefined(this.facetsRefinements, facet, value))
return this;
return this.setQueryParameters({
facetsRefinements: RefinementList.removeRefinement(
this.facetsRefinements,
facet,
value
),
});
},
/**
* Remove a negative refinement on a facet
* @method
* @param {string} facet name of the attribute used for faceting
* @param {string} value value used to filter
* @return {SearchParameters} new instance
*/
removeExcludeRefinement: function removeExcludeRefinement(facet, value) {
if (!this.isConjunctiveFacet(facet)) {
throw new Error(
facet +
' is not defined in the facets attribute of the helper configuration'
);
}
if (!RefinementList.isRefined(this.facetsExcludes, facet, value))
return this;
return this.setQueryParameters({
facetsExcludes: RefinementList.removeRefinement(
this.facetsExcludes,
facet,
value
),
});
},
/**
* Remove a refinement on a disjunctive facet
* @method
* @param {string} facet name of the attribute used for faceting
* @param {string} value value used to filter
* @return {SearchParameters} new instance
*/
removeDisjunctiveFacetRefinement: function removeDisjunctiveFacetRefinement(
facet,
value
) {
if (!this.isDisjunctiveFacet(facet)) {
throw new Error(
facet +
' is not defined in the disjunctiveFacets attribute of the helper configuration'
);
}
if (
!RefinementList.isRefined(this.disjunctiveFacetsRefinements, facet, value)
)
return this;
return this.setQueryParameters({
disjunctiveFacetsRefinements: RefinementList.removeRefinement(
this.disjunctiveFacetsRefinements,
facet,
value
),
});
},
/**
* Remove a tag from the list of tag refinements
* @method
* @param {string} tag the tag to remove
* @return {SearchParameters} new instance
*/
removeTagRefinement: function removeTagRefinement(tag) {
if (!this.isTagRefined(tag)) return this;
var modification = {
tagRefinements: this.tagRefinements.filter(function (t) {
return t !== tag;
}),
};
return this.setQueryParameters(modification);
},
/**
* Generic toggle refinement method to use with facet, disjunctive facets
* and hierarchical facets
* @param {string} facet the facet to refine
* @param {string} value the associated value
* @return {SearchParameters} new instance
* @throws will throw an error if the facet is not declared in the settings of the helper
* @deprecated since version 2.19.0, see {@link SearchParameters#toggleFacetRefinement}
*/
toggleRefinement: function toggleRefinement(facet, value) {
return this.toggleFacetRefinement(facet, value);
},
/**
* Generic toggle refinement method to use with facet, disjunctive facets
* and hierarchical facets
* @param {string} facet the facet to refine
* @param {string} value the associated value
* @return {SearchParameters} new instance
* @throws will throw an error if the facet is not declared in the settings of the helper
*/
toggleFacetRefinement: function toggleFacetRefinement(facet, value) {
if (this.isHierarchicalFacet(facet)) {
return this.toggleHierarchicalFacetRefinement(facet, value);
} else if (this.isConjunctiveFacet(facet)) {
return this.toggleConjunctiveFacetRefinement(facet, value);
} else if (this.isDisjunctiveFacet(facet)) {
return this.toggleDisjunctiveFacetRefinement(facet, value);
}
throw new Error(
'Cannot refine the undeclared facet ' +
facet +
'; it should be added to the helper options facets, disjunctiveFacets or hierarchicalFacets'
);
},
/**
* Switch the refinement applied over a facet/value
* @method
* @param {string} facet name of the attribute used for faceting
* @param {value} value value used for filtering
* @return {SearchParameters} new instance
*/
toggleConjunctiveFacetRefinement: function toggleConjunctiveFacetRefinement(
facet,
value
) {
if (!this.isConjunctiveFacet(facet)) {
throw new Error(
facet +
' is not defined in the facets attribute of the helper configuration'
);
}
return this.setQueryParameters({
facetsRefinements: RefinementList.toggleRefinement(
this.facetsRefinements,
facet,
value
),
});
},
/**
* Switch the refinement applied over a facet/value
* @method
* @param {string} facet name of the attribute used for faceting
* @param {value} value value used for filtering
* @return {SearchParameters} new instance
*/
toggleExcludeFacetRefinement: function toggleExcludeFacetRefinement(
facet,
value
) {
if (!this.isConjunctiveFacet(facet)) {
throw new Error(
facet +
' is not defined in the facets attribute of the helper configuration'
);
}
return this.setQueryParameters({
facetsExcludes: RefinementList.toggleRefinement(
this.facetsExcludes,
facet,
value
),
});
},
/**
* Switch the refinement applied over a facet/value
* @method
* @param {string} facet name of the attribute used for faceting
* @param {value} value value used for filtering
* @return {SearchParameters} new instance
*/
toggleDisjunctiveFacetRefinement: function toggleDisjunctiveFacetRefinement(
facet,
value
) {
if (!this.isDisjunctiveFacet(facet)) {
throw new Error(
facet +
' is not defined in the disjunctiveFacets attribute of the helper configuration'
);
}
return this.setQueryParameters({
disjunctiveFacetsRefinements: RefinementList.toggleRefinement(
this.disjunctiveFacetsRefinements,
facet,
value
),
});
},
/**
* Switch the refinement applied over a facet/value
* @method
* @param {string} facet name of the attribute used for faceting
* @param {value} value value used for filtering
* @return {SearchParameters} new instance
*/
toggleHierarchicalFacetRefinement: function toggleHierarchicalFacetRefinement(
facet,
value
) {
if (!this.isHierarchicalFacet(facet)) {
throw new Error(
facet +
' is not defined in the hierarchicalFacets attribute of the helper configuration'
);
}
var separator = this._getHierarchicalFacetSeparator(
this.getHierarchicalFacetByName(facet)
);
var mod = {};
var upOneOrMultipleLevel =
this.hierarchicalFacetsRefinements[facet] !== undefined &&
this.hierarchicalFacetsRefinements[facet].length > 0 &&
// remove current refinement:
// refinement was 'beer > IPA', call is toggleRefine('beer > IPA'), refinement should be `beer`
(this.hierarchicalFacetsRefinements[facet][0] === value ||
// remove a parent refinement of the current refinement:
// - refinement was 'beer > IPA > Flying dog'
// - call is toggleRefine('beer > IPA')
// - refinement should be `beer`
this.hierarchicalFacetsRefinements[facet][0].indexOf(
value + separator
) === 0);
if (upOneOrMultipleLevel) {
if (value.indexOf(separator) === -1) {
// go back to root level
mod[facet] = [];
} else {
mod[facet] = [value.slice(0, value.lastIndexOf(separator))];
}
} else {
mod[facet] = [value];
}
return this.setQueryParameters({
hierarchicalFacetsRefinements: defaultsPure(
{},
mod,
this.hierarchicalFacetsRefinements
),
});
},
/**
* Adds a refinement on a hierarchical facet.
* @param {string} facet the facet name
* @param {string} path the hierarchical facet path
* @return {SearchParameter} the new state
* @throws Error if the facet is not defined or if the facet is refined
*/
addHierarchicalFacetRefinement: function (facet, path) {
if (this.isHierarchicalFacetRefined(facet)) {
throw new Error(facet + ' is already refined.');
}
if (!this.isHierarchicalFacet(facet)) {
throw new Error(
facet +
' is not defined in the hierarchicalFacets attribute of the helper configuration.'
);
}
var mod = {};
mod[facet] = [path];
return this.setQueryParameters({
hierarchicalFacetsRefinements: defaultsPure(
{},
mod,
this.hierarchicalFacetsRefinements
),
});
},
/**
* Removes the refinement set on a hierarchical facet.
* @param {string} facet the facet name
* @return {SearchParameter} the new state
* @throws Error if the facet is not defined or if the facet is not refined
*/
removeHierarchicalFacetRefinement: function (facet) {
if (!this.isHierarchicalFacetRefined(facet)) {
return this;
}
var mod = {};
mod[facet] = [];
return this.setQueryParameters({
hierarchicalFacetsRefinements: defaultsPure(
{},
mod,
this.hierarchicalFacetsRefinements
),
});
},
/**
* Switch the tag refinement
* @method
* @param {string} tag the tag to remove or add
* @return {SearchParameters} new instance
*/
toggleTagRefinement: function toggleTagRefinement(tag) {
if (this.isTagRefined(tag)) {
return this.removeTagRefinement(tag);
}
return this.addTagRefinement(tag);
},
/**
* Test if the facet name is from one of the disjunctive facets
* @method
* @param {string} facet facet name to test
* @return {boolean} true if facet is a disjunctive facet
*/
isDisjunctiveFacet: function (facet) {
return this.disjunctiveFacets.indexOf(facet) > -1;
},
/**
* Test if the facet name is from one of the hierarchical facets
* @method
* @param {string} facetName facet name to test
* @return {boolean} true if facetName is a hierarchical facet
*/
isHierarchicalFacet: function (facetName) {
return this.getHierarchicalFacetByName(facetName) !== undefined;
},
/**
* Test if the facet name is from one of the conjunctive/normal facets
* @method
* @param {string} facet facet name to test
* @return {boolean} true if facet is a conjunctive facet
*/
isConjunctiveFacet: function (facet) {
return this.facets.indexOf(facet) > -1;
},
/**
* Returns true if the facet is refined, either for a specific value or in
* general.
* @method
* @param {string} facet name of the attribute for used for faceting
* @param {string} value, optional value. If passed will test that this value
* is filtering the given facet.
* @return {boolean} returns true if refined
*/
isFacetRefined: function isFacetRefined(facet, value) {
if (!this.isConjunctiveFacet(facet)) {
return false;
}
return RefinementList.isRefined(this.facetsRefinements, facet, value);
},
/**
* Returns true if the facet contains exclusions or if a specific value is
* excluded.
*
* @method
* @param {string} facet name of the attribute for used for faceting
* @param {string} [value] optional value. If passed will test that this value
* is filtering the given facet.
* @return {boolean} returns true if refined
*/
isExcludeRefined: function isExcludeRefined(facet, value) {
if (!this.isConjunctiveFacet(facet)) {
return false;
}
return RefinementList.isRefined(this.facetsExcludes, facet, value);
},
/**
* Returns true if the facet contains a refinement, or if a value passed is a
* refinement for the facet.
* @method
* @param {string} facet name of the attribute for used for faceting
* @param {string} value optional, will test if the value is used for refinement
* if there is one, otherwise will test if the facet contains any refinement
* @return {boolean} true if the facet is refined
*/
isDisjunctiveFacetRefined: function isDisjunctiveFacetRefined(facet, value) {
if (!this.isDisjunctiveFacet(facet)) {
return false;
}
return RefinementList.isRefined(
this.disjunctiveFacetsRefinements,
facet,
value
);
},
/**
* Returns true if the facet contains a refinement, or if a value passed is a
* refinement for the facet.
* @method
* @param {string} facet name of the attribute for used for faceting
* @param {string} value optional, will test if the value is used for refinement
* if there is one, otherwise will test if the facet contains any refinement
* @return {boolean} true if the facet is refined
*/
isHierarchicalFacetRefined: function isHierarchicalFacetRefined(
facet,
value
) {
if (!this.isHierarchicalFacet(facet)) {
return false;
}
var refinements = this.getHierarchicalRefinement(facet);
if (!value) {
return refinements.length > 0;
}
return refinements.indexOf(value) !== -1;
},
/**
* Test if the triple (attribute, operator, value) is already refined.
* If only the attribute and the operator are provided, it tests if the
* contains any refinement value.
* @method
* @param {string} attribute attribute for which the refinement is applied
* @param {string} [operator] operator of the refinement
* @param {string} [value] value of the refinement
* @return {boolean} true if it is refined
*/
isNumericRefined: function isNumericRefined(attribute, operator, value) {
if (value === undefined && operator === undefined) {
return Boolean(this.numericRefinements[attribute]);
}
var isOperatorDefined =
this.numericRefinements[attribute] &&
this.numericRefinements[attribute][operator] !== undefined;
if (value === undefined || !isOperatorDefined) {
return isOperatorDefined;
}
var parsedValue = valToNumber(value);
var isAttributeValueDefined =
findArray(this.numericRefinements[attribute][operator], parsedValue) !==
undefined;
return isOperatorDefined && isAttributeValueDefined;
},
/**
* Returns true if the tag refined, false otherwise
* @method
* @param {string} tag the tag to check
* @return {boolean} true if tag is refined
*/
isTagRefined: function isTagRefined(tag) {
return this.tagRefinements.indexOf(tag) !== -1;
},
/**
* Returns the list of all disjunctive facets refined
* @method
* @param {string} facet name of the attribute used for faceting
* @param {value} value value used for filtering
* @return {string[]} returns the list of refinements
*/
getRefinedDisjunctiveFacets: function getRefinedDisjunctiveFacets() {
// eslint-disable-next-line consistent-this
var self = this;
// attributes used for numeric filter can also be disjunctive
var disjunctiveNumericRefinedFacets = intersection(
Object.keys(this.numericRefinements).filter(function (facet) {
return Object.keys(self.numericRefinements[facet]).length > 0;
}),
this.disjunctiveFacets
);
return Object.keys(this.disjunctiveFacetsRefinements)
.filter(function (facet) {
return self.disjunctiveFacetsRefinements[facet].length > 0;
})
.concat(disjunctiveNumericRefinedFacets)
.concat(this.getRefinedHierarchicalFacets())
.sort();
},
/**
* Returns the list of all disjunctive facets refined
* @method
* @param {string} facet name of the attribute used for faceting
* @param {value} value value used for filtering
* @return {string[]} returns the list of refinements
*/
getRefinedHierarchicalFacets: function getRefinedHierarchicalFacets() {
// eslint-disable-next-line consistent-this
var self = this;
return intersection(
// enforce the order between the two arrays,
// so that refinement name index === hierarchical facet index
this.hierarchicalFacets.map(function (facet) {
return facet.name;
}),
Object.keys(this.hierarchicalFacetsRefinements).filter(function (facet) {
return self.hierarchicalFacetsRefinements[facet].length > 0;
})
).sort();
},
/**
* Returned the list of all disjunctive facets not refined
* @method
* @return {string[]} returns the list of facets that are not refined
*/
getUnrefinedDisjunctiveFacets: function () {
var refinedFacets = this.getRefinedDisjunctiveFacets();
return this.disjunctiveFacets.filter(function (f) {
return refinedFacets.indexOf(f) === -1;
});
},
managedParameters: [
'index',
'facets',
'disjunctiveFacets',
'facetsRefinements',
'hierarchicalFacets',
'facetsExcludes',
'disjunctiveFacetsRefinements',
'numericRefinements',
'tagRefinements',
'hierarchicalFacetsRefinements',
],
getQueryParams: function getQueryParams() {
var managedParameters = this.managedParameters;
var queryParams = {};
// eslint-disable-next-line consistent-this
var self = this;
Object.keys(this).forEach(function (paramName) {
var paramValue = self[paramName];
if (
managedParameters.indexOf(paramName) === -1 &&
paramValue !== undefined
) {
queryParams[paramName] = paramValue;
}
});
return queryParams;
},
/**
* Let the user set a specific value for a given parameter. Will return the
* same instance if the parameter is invalid or if the value is the same as the
* previous one.
* @method
* @param {string} parameter the parameter name
* @param {any} value the value to be set, must be compliant with the definition
* of the attribute on the object
* @return {SearchParameters} the updated state
*/
setQueryParameter: function setParameter(parameter, value) {
if (this[parameter] === value) return this;
var modification = {};
modification[parameter] = value;
return this.setQueryParameters(modification);
},
/**
* Let the user set any of the parameters with a plain object.
* @method
* @param {object} params all the keys and the values to be updated
* @return {SearchParameters} a new updated instance
*/
setQueryParameters: function setQueryParameters(params) {
if (!params) return this;
var error = SearchParameters.validate(this, params);
if (error) {
throw error;
}
// eslint-disable-next-line consistent-this
var self = this;
var nextWithNumbers = SearchParameters._parseNumbers(params);
var previousPlainObject = Object.keys(this).reduce(function (acc, key) {
acc[key] = self[key];
return acc;
}, {});
var nextPlainObject = Object.keys(nextWithNumbers).reduce(function (
previous,
key
) {
var isPreviousValueDefined = previous[key] !== undefined;
var isNextValueDefined = nextWithNumbers[key] !== undefined;
if (isPreviousValueDefined && !isNextValueDefined) {
return omit(previous, [key]);
}
if (isNextValueDefined) {
previous[key] = nextWithNumbers[key];
}
return previous;
},
previousPlainObject);
return new this.constructor(nextPlainObject);
},
/**
* Returns a new instance with the page reset. Two scenarios possible:
* the page is omitted -> return the given instance
* the page is set -> return a new instance with a page of 0
* @return {SearchParameters} a new updated instance
*/
resetPage: function () {
if (this.page === undefined) {
return this;
}
return this.setPage(0);
},
/**
* Helper function to get the hierarchicalFacet separator or the default one (`>`)
* @param {object} hierarchicalFacet the hierarchicalFacet object
* @return {string} returns the hierarchicalFacet.separator or `>` as default
*/
_getHierarchicalFacetSortBy: function (hierarchicalFacet) {
return hierarchicalFacet.sortBy || ['isRefined:desc', 'name:asc'];
},
/**
* Helper function to get the hierarchicalFacet separator or the default one (`>`)
* @private
* @param {object} hierarchicalFacet the hierarchicalFacet object
* @return {string} returns the hierarchicalFacet.separator or `>` as default
*/
_getHierarchicalFacetSeparator: function (hierarchicalFacet) {
return hierarchicalFacet.separator || ' > ';
},
/**
* Helper function to get the hierarchicalFacet prefix path or null
* @private
* @param {object} hierarchicalFacet the hierarchicalFacet object
* @return {string} returns the hierarchicalFacet.rootPath or null as default
*/
_getHierarchicalRootPath: function (hierarchicalFacet) {
return hierarchicalFacet.rootPath || null;
},
/**
* Helper function to check if we show the parent level of the hierarchicalFacet
* @private
* @param {object} hierarchicalFacet the hierarchicalFacet object
* @return {string} returns the hierarchicalFacet.showParentLevel or true as default
*/
_getHierarchicalShowParentLevel: function (hierarchicalFacet) {
if (typeof hierarchicalFacet.showParentLevel === 'boolean') {
return hierarchicalFacet.showParentLevel;
}
return true;
},
/**
* Helper function to get the hierarchicalFacet by it's name
* @param {string} hierarchicalFacetName the hierarchicalFacet name
* @return {object} a hierarchicalFacet
*/
getHierarchicalFacetByName: function (hierarchicalFacetName) {
return find(this.hierarchicalFacets, function (f) {
return f.name === hierarchicalFacetName;
});
},
/**
* Get the current breadcrumb for a hierarchical facet, as an array
* @param {string} facetName Hierarchical facet name
* @return {array.<string>} the path as an array of string
*/
getHierarchicalFacetBreadcrumb: function (facetName) {
if (!this.isHierarchicalFacet(facetName)) {
return [];
}
var refinement = this.getHierarchicalRefinement(facetName)[0];
if (!refinement) return [];
var separator = this._getHierarchicalFacetSeparator(
this.getHierarchicalFacetByName(facetName)
);
var path = refinement.split(separator);
return path.map(function (part) {
return part.trim();
});
},
toString: function () {
return JSON.stringify(this, null, 2);
},
};
/**
* Callback used for clearRefinement method
* @callback SearchParameters.clearCallback
* @param {OperatorList|FacetList} value the value of the filter
* @param {string} key the current attribute name
* @param {string} type `numeric`, `disjunctiveFacet`, `conjunctiveFacet`, `hierarchicalFacet` or `exclude`
* depending on the type of facet
* @return {boolean} `true` if the element should be removed. `false` otherwise.
*/
module.exports = SearchParameters;
/***/ }),
/***/ 10210:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
module.exports = generateTrees;
var fv = __webpack_require__(94039);
var find = __webpack_require__(7888);
var prepareHierarchicalFacetSortBy = __webpack_require__(82293);
var orderBy = __webpack_require__(42148);
var escapeFacetValue = fv.escapeFacetValue;
var unescapeFacetValue = fv.unescapeFacetValue;
function generateTrees(state) {
return function generate(hierarchicalFacetResult, hierarchicalFacetIndex) {
var hierarchicalFacet = state.hierarchicalFacets[hierarchicalFacetIndex];
var hierarchicalFacetRefinement =
(state.hierarchicalFacetsRefinements[hierarchicalFacet.name] &&
state.hierarchicalFacetsRefinements[hierarchicalFacet.name][0]) ||
'';
var hierarchicalSeparator =
state._getHierarchicalFacetSeparator(hierarchicalFacet);
var hierarchicalRootPath =
state._getHierarchicalRootPath(hierarchicalFacet);
var hierarchicalShowParentLevel =
state._getHierarchicalShowParentLevel(hierarchicalFacet);
var sortBy = prepareHierarchicalFacetSortBy(
state._getHierarchicalFacetSortBy(hierarchicalFacet)
);
var rootExhaustive = hierarchicalFacetResult.every(function (facetResult) {
return facetResult.exhaustive;
});
var generateTreeFn = generateHierarchicalTree(
sortBy,
hierarchicalSeparator,
hierarchicalRootPath,
hierarchicalShowParentLevel,
hierarchicalFacetRefinement
);
var results = hierarchicalFacetResult;
if (hierarchicalRootPath) {
results = hierarchicalFacetResult.slice(
hierarchicalRootPath.split(hierarchicalSeparator).length
);
}
return results.reduce(generateTreeFn, {
name: state.hierarchicalFacets[hierarchicalFacetIndex].name,
count: null, // root level, no count
isRefined: true, // root level, always refined
path: null, // root level, no path
escapedValue: null,
exhaustive: rootExhaustive,
data: null,
});
};
}
function generateHierarchicalTree(
sortBy,
hierarchicalSeparator,
hierarchicalRootPath,
hierarchicalShowParentLevel,
currentRefinement
) {
return function generateTree(
hierarchicalTree,
hierarchicalFacetResult,
currentHierarchicalLevel
) {
var parent = hierarchicalTree;
if (currentHierarchicalLevel > 0) {
var level = 0;
parent = hierarchicalTree;
while (level < currentHierarchicalLevel) {
/**
* @type {object[]]} hierarchical data
*/
var data = parent && Array.isArray(parent.data) ? parent.data : [];
parent = find(data, function (subtree) {
return subtree.isRefined;
});
level++;
}
}
// we found a refined parent, let's add current level data under it
if (parent) {
// filter values in case an object has multiple categories:
// {
// categories: {
// level0: ['beers', 'bières'],
// level1: ['beers > IPA', 'bières > Belges']
// }
// }
//
// If parent refinement is `beers`, then we do not want to have `bières > Belges`
// showing up
var picked = Object.keys(hierarchicalFacetResult.data)
.map(function (facetValue) {
return [facetValue, hierarchicalFacetResult.data[facetValue]];
})
.filter(function (tuple) {
var facetValue = tuple[0];
return onlyMatchingTree(
facetValue,
parent.path || hierarchicalRootPath,
currentRefinement,
hierarchicalSeparator,
hierarchicalRootPath,
hierarchicalShowParentLevel
);
});
parent.data = orderBy(
picked.map(function (tuple) {
var facetValue = tuple[0];
var facetCount = tuple[1];
return format(
facetCount,
facetValue,
hierarchicalSeparator,
unescapeFacetValue(currentRefinement),
hierarchicalFacetResult.exhaustive
);
}),
sortBy[0],
sortBy[1]
);
}
return hierarchicalTree;
};
}
// eslint-disable-next-line max-params
function onlyMatchingTree(
facetValue,
parentPath,
currentRefinement,
hierarchicalSeparator,
hierarchicalRootPath,
hierarchicalShowParentLevel
) {
// we want the facetValue is a child of hierarchicalRootPath
if (
hierarchicalRootPath &&
(facetValue.indexOf(hierarchicalRootPath) !== 0 ||
hierarchicalRootPath === facetValue)
) {
return false;
}
// we always want root levels (only when there is no prefix path)
return (
(!hierarchicalRootPath &&
facetValue.indexOf(hierarchicalSeparator) === -1) ||
// if there is a rootPath, being root level mean 1 level under rootPath
(hierarchicalRootPath &&
facetValue.split(hierarchicalSeparator).length -
hierarchicalRootPath.split(hierarchicalSeparator).length ===
1) ||
// if current refinement is a root level and current facetValue is a root level,
// keep the facetValue
(facetValue.indexOf(hierarchicalSeparator) === -1 &&
currentRefinement.indexOf(hierarchicalSeparator) === -1) ||
// currentRefinement is a child of the facet value
currentRefinement.indexOf(facetValue) === 0 ||
// facetValue is a child of the current parent, add it
(facetValue.indexOf(parentPath + hierarchicalSeparator) === 0 &&
(hierarchicalShowParentLevel ||
facetValue.indexOf(currentRefinement) === 0))
);
}
function format(
facetCount,
facetValue,
hierarchicalSeparator,
currentRefinement,
exhaustive
) {
var parts = facetValue.split(hierarchicalSeparator);
return {
name: parts[parts.length - 1].trim(),
path: facetValue,
escapedValue: escapeFacetValue(facetValue),
count: facetCount,
isRefined:
currentRefinement === facetValue ||
currentRefinement.indexOf(facetValue + hierarchicalSeparator) === 0,
exhaustive: exhaustive,
data: null,
};
}
/***/ }),
/***/ 23076:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
var compact = __webpack_require__(74587);
var defaultsPure = __webpack_require__(52344);
var fv = __webpack_require__(94039);
var find = __webpack_require__(7888);
var findIndex = __webpack_require__(69725);
var formatSort = __webpack_require__(82293);
var merge = __webpack_require__(60185);
var orderBy = __webpack_require__(42148);
var escapeFacetValue = fv.escapeFacetValue;
var unescapeFacetValue = fv.unescapeFacetValue;
var generateHierarchicalTree = __webpack_require__(10210);
/**
* @typedef SearchResults.Facet
* @type {object}
* @property {string} name name of the attribute in the record
* @property {object} data the faceting data: value, number of entries
* @property {object} stats undefined unless facet_stats is retrieved from algolia
*/
/**
* @typedef SearchResults.HierarchicalFacet
* @type {object}
* @property {string} name name of the current value given the hierarchical level, trimmed.
* If root node, you get the facet name
* @property {number} count number of objects matching this hierarchical value
* @property {string} path the current hierarchical value full path
* @property {boolean} isRefined `true` if the current value was refined, `false` otherwise
* @property {HierarchicalFacet[]} data sub values for the current level
*/
/**
* @typedef SearchResults.FacetValue
* @type {object}
* @property {string} name the facet value itself
* @property {number} count times this facet appears in the results
* @property {boolean} isRefined is the facet currently selected
* @property {boolean} isExcluded is the facet currently excluded (only for conjunctive facets)
*/
/**
* @typedef Refinement
* @type {object}
* @property {string} type the type of filter used:
* `numeric`, `facet`, `exclude`, `disjunctive`, `hierarchical`
* @property {string} attributeName name of the attribute used for filtering
* @property {string} name the value of the filter
* @property {number} numericValue the value as a number. Only for numeric filters.
* @property {string} operator the operator used. Only for numeric filters.
* @property {number} count the number of computed hits for this filter. Only on facets.
* @property {boolean} exhaustive if the count is exhaustive
*/
/**
* Turn an array of attributes in an object of attributes with their position in the array as value
* @param {string[]} attributes the list of attributes in the record
* @return {object} the list of attributes indexed by attribute name
*/
function getIndices(attributes) {
var indices = {};
attributes.forEach(function (val, idx) {
indices[val] = idx;
});
return indices;
}
function assignFacetStats(dest, facetStats, key) {
if (facetStats && facetStats[key]) {
dest.stats = facetStats[key];
}
}
/**
* @typedef {Object} HierarchicalFacet
* @property {string} name
* @property {string[]} attributes
*/
/**
* @param {HierarchicalFacet[]} hierarchicalFacets All hierarchical facets
* @param {string} hierarchicalAttributeName The name of the hierarchical attribute
* @return {HierarchicalFacet} The hierarchical facet matching the attribute name
*/
function findMatchingHierarchicalFacetFromAttributeName(
hierarchicalFacets,
hierarchicalAttributeName
) {
return find(
hierarchicalFacets,
function facetKeyMatchesAttribute(hierarchicalFacet) {
var facetNames = hierarchicalFacet.attributes || [];
return facetNames.indexOf(hierarchicalAttributeName) > -1;
}
);
}
// eslint-disable-next-line valid-jsdoc
/**
* Constructor for SearchResults
* @class
* @classdesc SearchResults contains the results of a query to Algolia using the
* {@link AlgoliaSearchHelper}.
* @param {SearchParameters} state state that led to the response
* @param {array.<object>} results the results from algolia client
* @example <caption>SearchResults of the first query in
* <a href="http://demos.algolia.com/instant-search-demo">the instant search demo</a></caption>
{
"hitsPerPage": 10,
"processingTimeMS": 2,
"facets": [
{
"name": "type",
"data": {
"HardGood": 6627,
"BlackTie": 550,
"Music": 665,
"Software": 131,
"Game": 456,
"Movie": 1571
},
"exhaustive": false
},
{
"exhaustive": false,
"data": {
"Free shipping": 5507
},
"name": "shipping"
}
],
"hits": [
{
"thumbnailImage": "http://img.bbystatic.com/BestBuy_US/images/products/1688/1688832_54x108_s.gif",
"_highlightResult": {
"shortDescription": {
"matchLevel": "none",
"value": "Safeguard your PC, Mac, Android and iOS devices with comprehensive Internet protection",
"matchedWords": []
},
"category": {
"matchLevel": "none",
"value": "Computer Security Software",
"matchedWords": []
},
"manufacturer": {
"matchedWords": [],
"value": "Webroot",
"matchLevel": "none"
},
"name": {
"value": "Webroot SecureAnywhere Internet Security (3-Device) (1-Year Subscription) - Mac/Windows",
"matchedWords": [],
"matchLevel": "none"
}
},
"image": "http://img.bbystatic.com/BestBuy_US/images/products/1688/1688832_105x210_sc.jpg",
"shipping": "Free shipping",
"bestSellingRank": 4,
"shortDescription": "Safeguard your PC, Mac, Android and iOS devices with comprehensive Internet protection",
"url": "http://www.bestbuy.com/site/webroot-secureanywhere-internet-security-3-devi…d=1219060687969&skuId=1688832&cmp=RMX&ky=2d3GfEmNIzjA0vkzveHdZEBgpPCyMnLTJ",
"name": "Webroot SecureAnywhere Internet Security (3-Device) (1-Year Subscription) - Mac/Windows",
"category": "Computer Security Software",
"salePrice_range": "1 - 50",
"objectID": "1688832",
"type": "Software",
"customerReviewCount": 5980,
"salePrice": 49.99,
"manufacturer": "Webroot"
},
....
],
"nbHits": 10000,
"disjunctiveFacets": [
{
"exhaustive": false,
"data": {
"5": 183,
"12": 112,
"7": 149,
...
},
"name": "customerReviewCount",
"stats": {
"max": 7461,
"avg": 157.939,
"min": 1
}
},
{
"data": {
"Printer Ink": 142,
"Wireless Speakers": 60,
"Point & Shoot Cameras": 48,
...
},
"name": "category",
"exhaustive": false
},
{
"exhaustive": false,
"data": {
"> 5000": 2,
"1 - 50": 6524,
"501 - 2000": 566,
"201 - 500": 1501,
"101 - 200": 1360,
"2001 - 5000": 47
},
"name": "salePrice_range"
},
{
"data": {
"Dynex™": 202,
"Insignia™": 230,
"PNY": 72,
...
},
"name": "manufacturer",
"exhaustive": false
}
],
"query": "",
"nbPages": 100,
"page": 0,
"index": "bestbuy"
}
**/
function SearchResults(state, results, options) {
var mainSubResponse = results[0];
this._rawResults = results;
// eslint-disable-next-line consistent-this
var self = this;
// https://www.algolia.com/doc/api-reference/api-methods/search/#response
Object.keys(mainSubResponse).forEach(function (key) {
self[key] = mainSubResponse[key];
});
// Make every key of the result options reachable from the instance
Object.keys(options || {}).forEach(function (key) {
self[key] = options[key];
});
/**
* query used to generate the results
* @name query
* @member {string}
* @memberof SearchResults
* @instance
*/
/**
* The query as parsed by the engine given all the rules.
* @name parsedQuery
* @member {string}
* @memberof SearchResults
* @instance
*/
/**
* all the records that match the search parameters. Each record is
* augmented with a new attribute `_highlightResult`
* which is an object keyed by attribute and with the following properties:
* - `value` : the value of the facet highlighted (html)
* - `matchLevel`: `full`, `partial` or `none`, depending on how the query terms match
* @name hits
* @member {object[]}
* @memberof SearchResults
* @instance
*/
/**
* index where the results come from
* @name index
* @member {string}
* @memberof SearchResults
* @instance
*/
/**
* number of hits per page requested
* @name hitsPerPage
* @member {number}
* @memberof SearchResults
* @instance
*/
/**
* total number of hits of this query on the index
* @name nbHits
* @member {number}
* @memberof SearchResults
* @instance
*/
/**
* total number of pages with respect to the number of hits per page and the total number of hits
* @name nbPages
* @member {number}
* @memberof SearchResults
* @instance
*/
/**
* current page
* @name page
* @member {number}
* @memberof SearchResults
* @instance
*/
/**
* The position if the position was guessed by IP.
* @name aroundLatLng
* @member {string}
* @memberof SearchResults
* @instance
* @example "48.8637,2.3615",
*/
/**
* The radius computed by Algolia.
* @name automaticRadius
* @member {string}
* @memberof SearchResults
* @instance
* @example "126792922",
*/
/**
* String identifying the server used to serve this request.
*
* getRankingInfo needs to be set to `true` for this to be returned
*
* @name serverUsed
* @member {string}
* @memberof SearchResults
* @instance
* @example "c7-use-2.algolia.net",
*/
/**
* Boolean that indicates if the computation of the counts did time out.
* @deprecated
* @name timeoutCounts
* @member {boolean}
* @memberof SearchResults
* @instance
*/
/**
* Boolean that indicates if the computation of the hits did time out.
* @deprecated
* @name timeoutHits
* @member {boolean}
* @memberof SearchResults
* @instance
*/
/**
* True if the counts of the facets is exhaustive
* @name exhaustiveFacetsCount
* @member {boolean}
* @memberof SearchResults
* @instance
*/
/**
* True if the number of hits is exhaustive
* @name exhaustiveNbHits
* @member {boolean}
* @memberof SearchResults
* @instance
*/
/**
* Contains the userData if they are set by a [query rule](https://www.algolia.com/doc/guides/query-rules/query-rules-overview/).
* @name userData
* @member {object[]}
* @memberof SearchResults
* @instance
*/
/**
* queryID is the unique identifier of the query used to generate the current search results.
* This value is only available if the `clickAnalytics` search parameter is set to `true`.
* @name queryID
* @member {string}
* @memberof SearchResults
* @instance
*/
/**
* sum of the processing time of all the queries
* @name processingTimeMS
* @member {number}
* @memberof SearchResults
* @instance
*/
this.processingTimeMS = results.reduce(function (sum, result) {
return result.processingTimeMS === undefined
? sum
: sum + result.processingTimeMS;
}, 0);
/**
* disjunctive facets results
* @member {SearchResults.Facet[]}
*/
this.disjunctiveFacets = [];
/**
* disjunctive facets results
* @member {SearchResults.HierarchicalFacet[]}
*/
this.hierarchicalFacets = state.hierarchicalFacets.map(
function initFutureTree() {
return [];
}
);
/**
* other facets results
* @member {SearchResults.Facet[]}
*/
this.facets = [];
var disjunctiveFacets = state.getRefinedDisjunctiveFacets();
var facetsIndices = getIndices(state.facets);
var disjunctiveFacetsIndices = getIndices(state.disjunctiveFacets);
var nextDisjunctiveResult = 1;
// Since we send request only for disjunctive facets that have been refined,
// we get the facets information from the first, general, response.
var mainFacets = mainSubResponse.facets || {};
Object.keys(mainFacets).forEach(function (facetKey) {
var facetValueObject = mainFacets[facetKey];
var hierarchicalFacet = findMatchingHierarchicalFacetFromAttributeName(
state.hierarchicalFacets,
facetKey
);
if (hierarchicalFacet) {
// Place the hierarchicalFacet data at the correct index depending on
// the attributes order that was defined at the helper initialization
var facetIndex = hierarchicalFacet.attributes.indexOf(facetKey);
var idxAttributeName = findIndex(state.hierarchicalFacets, function (f) {
return f.name === hierarchicalFacet.name;
});
self.hierarchicalFacets[idxAttributeName][facetIndex] = {
attribute: facetKey,
data: facetValueObject,
exhaustive: mainSubResponse.exhaustiveFacetsCount,
};
} else {
var isFacetDisjunctive = state.disjunctiveFacets.indexOf(facetKey) !== -1;
var isFacetConjunctive = state.facets.indexOf(facetKey) !== -1;
var position;
if (isFacetDisjunctive) {
position = disjunctiveFacetsIndices[facetKey];
self.disjunctiveFacets[position] = {
name: facetKey,
data: facetValueObject,
exhaustive: mainSubResponse.exhaustiveFacetsCount,
};
assignFacetStats(
self.disjunctiveFacets[position],
mainSubResponse.facets_stats,
facetKey
);
}
if (isFacetConjunctive) {
position = facetsIndices[facetKey];
self.facets[position] = {
name: facetKey,
data: facetValueObject,
exhaustive: mainSubResponse.exhaustiveFacetsCount,
};
assignFacetStats(
self.facets[position],
mainSubResponse.facets_stats,
facetKey
);
}
}
});
// Make sure we do not keep holes within the hierarchical facets
this.hierarchicalFacets = compact(this.hierarchicalFacets);
// aggregate the refined disjunctive facets
disjunctiveFacets.forEach(function (disjunctiveFacet) {
var result = results[nextDisjunctiveResult];
var facets = result && result.facets ? result.facets : {};
var hierarchicalFacet = state.getHierarchicalFacetByName(disjunctiveFacet);
// There should be only item in facets.
Object.keys(facets).forEach(function (dfacet) {
var facetResults = facets[dfacet];
var position;
if (hierarchicalFacet) {
position = findIndex(state.hierarchicalFacets, function (f) {
return f.name === hierarchicalFacet.name;
});
var attributeIndex = findIndex(
self.hierarchicalFacets[position],
function (f) {
return f.attribute === dfacet;
}
);
// previous refinements and no results so not able to find it
if (attributeIndex === -1) {
return;
}
self.hierarchicalFacets[position][attributeIndex].data = merge(
{},
self.hierarchicalFacets[position][attributeIndex].data,
facetResults
);
} else {
position = disjunctiveFacetsIndices[dfacet];
var dataFromMainRequest =
(mainSubResponse.facets && mainSubResponse.facets[dfacet]) || {};
self.disjunctiveFacets[position] = {
name: dfacet,
data: defaultsPure({}, facetResults, dataFromMainRequest),
exhaustive: result.exhaustiveFacetsCount,
};
assignFacetStats(
self.disjunctiveFacets[position],
result.facets_stats,
dfacet
);
if (state.disjunctiveFacetsRefinements[dfacet]) {
state.disjunctiveFacetsRefinements[dfacet].forEach(function (
refinementValue
) {
// add the disjunctive refinements if it is no more retrieved
if (
!self.disjunctiveFacets[position].data[refinementValue] &&
state.disjunctiveFacetsRefinements[dfacet].indexOf(
unescapeFacetValue(refinementValue)
) > -1
) {
self.disjunctiveFacets[position].data[refinementValue] = 0;
}
});
}
}
});
nextDisjunctiveResult++;
});
// if we have some parent level values for hierarchical facets, merge them
state.getRefinedHierarchicalFacets().forEach(function (refinedFacet) {
var hierarchicalFacet = state.getHierarchicalFacetByName(refinedFacet);
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
var currentRefinement = state.getHierarchicalRefinement(refinedFacet);
// if we are already at a root refinement (or no refinement at all), there is no
// root level values request
if (
currentRefinement.length === 0 ||
currentRefinement[0].split(separator).length < 2
) {
return;
}
results.slice(nextDisjunctiveResult).forEach(function (result) {
var facets = result && result.facets ? result.facets : {};
Object.keys(facets).forEach(function (dfacet) {
var facetResults = facets[dfacet];
var position = findIndex(state.hierarchicalFacets, function (f) {
return f.name === hierarchicalFacet.name;
});
var attributeIndex = findIndex(
self.hierarchicalFacets[position],
function (f) {
return f.attribute === dfacet;
}
);
// previous refinements and no results so not able to find it
if (attributeIndex === -1) {
return;
}
// when we always get root levels, if the hits refinement is `beers > IPA` (count: 5),
// then the disjunctive values will be `beers` (count: 100),
// but we do not want to display
// | beers (100)
// > IPA (5)
// We want
// | beers (5)
// > IPA (5)
var defaultData = {};
if (currentRefinement.length > 0) {
var root = currentRefinement[0].split(separator)[0];
defaultData[root] =
self.hierarchicalFacets[position][attributeIndex].data[root];
}
self.hierarchicalFacets[position][attributeIndex].data = defaultsPure(
defaultData,
facetResults,
self.hierarchicalFacets[position][attributeIndex].data
);
});
nextDisjunctiveResult++;
});
});
// add the excludes
Object.keys(state.facetsExcludes).forEach(function (facetName) {
var excludes = state.facetsExcludes[facetName];
var position = facetsIndices[facetName];
self.facets[position] = {
name: facetName,
data: mainFacets[facetName],
exhaustive: mainSubResponse.exhaustiveFacetsCount,
};
excludes.forEach(function (facetValue) {
self.facets[position] = self.facets[position] || { name: facetName };
self.facets[position].data = self.facets[position].data || {};
self.facets[position].data[facetValue] = 0;
});
});
/**
* @type {Array}
*/
this.hierarchicalFacets = this.hierarchicalFacets.map(
generateHierarchicalTree(state)
);
/**
* @type {Array}
*/
this.facets = compact(this.facets);
/**
* @type {Array}
*/
this.disjunctiveFacets = compact(this.disjunctiveFacets);
this._state = state;
}
/**
* Get a facet object with its name
* @deprecated
* @param {string} name name of the faceted attribute
* @return {SearchResults.Facet} the facet object
*/
SearchResults.prototype.getFacetByName = function (name) {
function predicate(facet) {
return facet.name === name;
}
return (
find(this.facets, predicate) ||
find(this.disjunctiveFacets, predicate) ||
find(this.hierarchicalFacets, predicate)
);
};
/**
* Get the facet values of a specified attribute from a SearchResults object.
* @private
* @param {SearchResults} results the search results to search in
* @param {string} attribute name of the faceted attribute to search for
* @return {array|object} facet values. For the hierarchical facets it is an object.
*/
function extractNormalizedFacetValues(results, attribute) {
function predicate(facet) {
return facet.name === attribute;
}
if (results._state.isConjunctiveFacet(attribute)) {
var facet = find(results.facets, predicate);
if (!facet) return [];
return Object.keys(facet.data).map(function (name) {
var value = escapeFacetValue(name);
return {
name: name,
escapedValue: value,
count: facet.data[name],
isRefined: results._state.isFacetRefined(attribute, value),
isExcluded: results._state.isExcludeRefined(attribute, name),
};
});
} else if (results._state.isDisjunctiveFacet(attribute)) {
var disjunctiveFacet = find(results.disjunctiveFacets, predicate);
if (!disjunctiveFacet) return [];
return Object.keys(disjunctiveFacet.data).map(function (name) {
var value = escapeFacetValue(name);
return {
name: name,
escapedValue: value,
count: disjunctiveFacet.data[name],
isRefined: results._state.isDisjunctiveFacetRefined(attribute, value),
};
});
} else if (results._state.isHierarchicalFacet(attribute)) {
var hierarchicalFacetValues = find(results.hierarchicalFacets, predicate);
if (!hierarchicalFacetValues) return hierarchicalFacetValues;
var hierarchicalFacet =
results._state.getHierarchicalFacetByName(attribute);
var separator =
results._state._getHierarchicalFacetSeparator(hierarchicalFacet);
var currentRefinement = unescapeFacetValue(
results._state.getHierarchicalRefinement(attribute)[0] || ''
);
if (currentRefinement.indexOf(hierarchicalFacet.rootPath) === 0) {
currentRefinement = currentRefinement.replace(
hierarchicalFacet.rootPath + separator,
''
);
}
var currentRefinementSplit = currentRefinement.split(separator);
currentRefinementSplit.unshift(attribute);
setIsRefined(hierarchicalFacetValues, currentRefinementSplit, 0);
return hierarchicalFacetValues;
}
return undefined;
}
/**
* Set the isRefined of a hierarchical facet result based on the current state.
* @param {SearchResults.HierarchicalFacet} item Hierarchical facet to fix
* @param {string[]} currentRefinement array of parts of the current hierarchical refinement
* @param {number} depth recursion depth in the currentRefinement
* @return {undefined} function mutates the item
*/
function setIsRefined(item, currentRefinement, depth) {
item.isRefined = item.name === currentRefinement[depth];
if (item.data) {
item.data.forEach(function (child) {
setIsRefined(child, currentRefinement, depth + 1);
});
}
}
/**
* Sort nodes of a hierarchical or disjunctive facet results
* @private
* @param {function} sortFn sort function to apply
* @param {HierarchicalFacet|Array} node node upon which we want to apply the sort
* @param {string[]} names attribute names
* @param {number} [level=0] current index in the names array
* @return {HierarchicalFacet|Array} sorted node
*/
function recSort(sortFn, node, names, level) {
level = level || 0;
if (Array.isArray(node)) {
return sortFn(node, names[level]);
}
if (!node.data || node.data.length === 0) {
return node;
}
var children = node.data.map(function (childNode) {
return recSort(sortFn, childNode, names, level + 1);
});
var sortedChildren = sortFn(children, names[level]);
var newNode = defaultsPure({ data: sortedChildren }, node);
return newNode;
}
SearchResults.DEFAULT_SORT = ['isRefined:desc', 'count:desc', 'name:asc'];
function vanillaSortFn(order, data) {
return data.sort(order);
}
/**
* @typedef FacetOrdering
* @type {Object}
* @property {string[]} [order]
* @property {'count' | 'alpha' | 'hidden'} [sortRemainingBy]
*/
/**
* Sorts facet arrays via their facet ordering
* @param {Array} facetValues the values
* @param {FacetOrdering} facetOrdering the ordering
* @returns {Array} the sorted facet values
*/
function sortViaFacetOrdering(facetValues, facetOrdering) {
var orderedFacets = [];
var remainingFacets = [];
var order = facetOrdering.order || [];
/**
* an object with the keys being the values in order, the values their index:
* ['one', 'two'] -> { one: 0, two: 1 }
*/
var reverseOrder = order.reduce(function (acc, name, i) {
acc[name] = i;
return acc;
}, {});
facetValues.forEach(function (item) {
// hierarchical facets get sorted using their raw name
var name = item.path || item.name;
if (reverseOrder[name] !== undefined) {
orderedFacets[reverseOrder[name]] = item;
} else {
remainingFacets.push(item);
}
});
orderedFacets = orderedFacets.filter(function (facet) {
return facet;
});
var sortRemainingBy = facetOrdering.sortRemainingBy;
var ordering;
if (sortRemainingBy === 'hidden') {
return orderedFacets;
} else if (sortRemainingBy === 'alpha') {
ordering = [
['path', 'name'],
['asc', 'asc'],
];
} else {
ordering = [['count'], ['desc']];
}
return orderedFacets.concat(
orderBy(remainingFacets, ordering[0], ordering[1])
);
}
/**
* @param {SearchResults} results the search results class
* @param {string} attribute the attribute to retrieve ordering of
* @returns {FacetOrdering | undefined} the facet ordering
*/
function getFacetOrdering(results, attribute) {
return (
results.renderingContent &&
results.renderingContent.facetOrdering &&
results.renderingContent.facetOrdering.values &&
results.renderingContent.facetOrdering.values[attribute]
);
}
/**
* Get a the list of values for a given facet attribute. Those values are sorted
* refinement first, descending count (bigger value on top), and name ascending
* (alphabetical order). The sort formula can overridden using either string based
* predicates or a function.
*
* This method will return all the values returned by the Algolia engine plus all
* the values already refined. This means that it can happen that the
* `maxValuesPerFacet` [configuration](https://www.algolia.com/doc/rest-api/search#param-maxValuesPerFacet)
* might not be respected if you have facet values that are already refined.
* @param {string} attribute attribute name
* @param {object} opts configuration options.
* @param {boolean} [opts.facetOrdering]
* Force the use of facetOrdering from the result if a sortBy is present. If
* sortBy isn't present, facetOrdering will be used automatically.
* @param {Array.<string> | function} opts.sortBy
* When using strings, it consists of
* the name of the [FacetValue](#SearchResults.FacetValue) or the
* [HierarchicalFacet](#SearchResults.HierarchicalFacet) attributes with the
* order (`asc` or `desc`). For example to order the value by count, the
* argument would be `['count:asc']`.
*
* If only the attribute name is specified, the ordering defaults to the one
* specified in the default value for this attribute.
*
* When not specified, the order is
* ascending. This parameter can also be a function which takes two facet
* values and should return a number, 0 if equal, 1 if the first argument is
* bigger or -1 otherwise.
*
* The default value for this attribute `['isRefined:desc', 'count:desc', 'name:asc']`
* @return {FacetValue[]|HierarchicalFacet|undefined} depending on the type of facet of
* the attribute requested (hierarchical, disjunctive or conjunctive)
* @example
* helper.on('result', function(event){
* //get values ordered only by name ascending using the string predicate
* event.results.getFacetValues('city', {sortBy: ['name:asc']});
* //get values ordered only by count ascending using a function
* event.results.getFacetValues('city', {
* // this is equivalent to ['count:asc']
* sortBy: function(a, b) {
* if (a.count === b.count) return 0;
* if (a.count > b.count) return 1;
* if (b.count > a.count) return -1;
* }
* });
* });
*/
SearchResults.prototype.getFacetValues = function (attribute, opts) {
var facetValues = extractNormalizedFacetValues(this, attribute);
if (!facetValues) {
return undefined;
}
var options = defaultsPure({}, opts, {
sortBy: SearchResults.DEFAULT_SORT,
// if no sortBy is given, attempt to sort based on facetOrdering
// if it is given, we still allow to sort via facet ordering first
facetOrdering: !(opts && opts.sortBy),
});
// eslint-disable-next-line consistent-this
var results = this;
var attributes;
if (Array.isArray(facetValues)) {
attributes = [attribute];
} else {
var config = results._state.getHierarchicalFacetByName(facetValues.name);
attributes = config.attributes;
}
return recSort(
function (data, facetName) {
if (options.facetOrdering) {
var facetOrdering = getFacetOrdering(results, facetName);
if (facetOrdering) {
return sortViaFacetOrdering(data, facetOrdering);
}
}
if (Array.isArray(options.sortBy)) {
var order = formatSort(options.sortBy, SearchResults.DEFAULT_SORT);
return orderBy(data, order[0], order[1]);
} else if (typeof options.sortBy === 'function') {
return vanillaSortFn(options.sortBy, data);
}
throw new Error(
'options.sortBy is optional but if defined it must be ' +
'either an array of string (predicates) or a sorting function'
);
},
facetValues,
attributes
);
};
/**
* Returns the facet stats if attribute is defined and the facet contains some.
* Otherwise returns undefined.
* @param {string} attribute name of the faceted attribute
* @return {object} The stats of the facet
*/
SearchResults.prototype.getFacetStats = function (attribute) {
if (this._state.isConjunctiveFacet(attribute)) {
return getFacetStatsIfAvailable(this.facets, attribute);
} else if (this._state.isDisjunctiveFacet(attribute)) {
return getFacetStatsIfAvailable(this.disjunctiveFacets, attribute);
}
return undefined;
};
/**
* @typedef {Object} FacetListItem
* @property {string} name
*/
/**
* @param {FacetListItem[]} facetList (has more items, but enough for here)
* @param {string} facetName The attribute to look for
* @return {object|undefined} The stats of the facet
*/
function getFacetStatsIfAvailable(facetList, facetName) {
var data = find(facetList, function (facet) {
return facet.name === facetName;
});
return data && data.stats;
}
/**
* Returns all refinements for all filters + tags. It also provides
* additional information: count and exhaustiveness for each filter.
*
* See the [refinement type](#Refinement) for an exhaustive view of the available
* data.
*
* Note that for a numeric refinement, results are grouped per operator, this
* means that it will return responses for operators which are empty.
*
* @return {Array.<Refinement>} all the refinements
*/
SearchResults.prototype.getRefinements = function () {
var state = this._state;
// eslint-disable-next-line consistent-this
var results = this;
var res = [];
Object.keys(state.facetsRefinements).forEach(function (attributeName) {
state.facetsRefinements[attributeName].forEach(function (name) {
res.push(
getRefinement(state, 'facet', attributeName, name, results.facets)
);
});
});
Object.keys(state.facetsExcludes).forEach(function (attributeName) {
state.facetsExcludes[attributeName].forEach(function (name) {
res.push(
getRefinement(state, 'exclude', attributeName, name, results.facets)
);
});
});
Object.keys(state.disjunctiveFacetsRefinements).forEach(function (
attributeName
) {
state.disjunctiveFacetsRefinements[attributeName].forEach(function (name) {
res.push(
getRefinement(
state,
'disjunctive',
attributeName,
name,
results.disjunctiveFacets
)
);
});
});
Object.keys(state.hierarchicalFacetsRefinements).forEach(function (
attributeName
) {
state.hierarchicalFacetsRefinements[attributeName].forEach(function (name) {
res.push(
getHierarchicalRefinement(
state,
attributeName,
name,
results.hierarchicalFacets
)
);
});
});
Object.keys(state.numericRefinements).forEach(function (attributeName) {
var operators = state.numericRefinements[attributeName];
Object.keys(operators).forEach(function (operator) {
operators[operator].forEach(function (value) {
res.push({
type: 'numeric',
attributeName: attributeName,
name: value,
numericValue: value,
operator: operator,
});
});
});
});
state.tagRefinements.forEach(function (name) {
res.push({ type: 'tag', attributeName: '_tags', name: name });
});
return res;
};
/**
* @typedef {Object} Facet
* @property {string} name
* @property {Object} data
* @property {boolean} exhaustive
*/
/**
* @param {SearchParameters} state the current state
* @param {string} type the type of the refinement
* @param {string} attributeName The attribute of the facet
* @param {*} name The name of the facet
* @param {Facet[]} resultsFacets facets from the results
* @return {Refinement} the refinement
*/
function getRefinement(state, type, attributeName, name, resultsFacets) {
var facet = find(resultsFacets, function (f) {
return f.name === attributeName;
});
var count = facet && facet.data && facet.data[name] ? facet.data[name] : 0;
var exhaustive = (facet && facet.exhaustive) || false;
return {
type: type,
attributeName: attributeName,
name: name,
count: count,
exhaustive: exhaustive,
};
}
/**
* @param {SearchParameters} state the current state
* @param {string} attributeName the attribute of the hierarchical facet
* @param {string} name the name of the facet
* @param {Facet[]} resultsFacets facets from the results
* @return {HierarchicalFacet} the hierarchical facet
*/
function getHierarchicalRefinement(state, attributeName, name, resultsFacets) {
var facetDeclaration = state.getHierarchicalFacetByName(attributeName);
var separator = state._getHierarchicalFacetSeparator(facetDeclaration);
var split = name.split(separator);
var rootFacet = find(resultsFacets, function (facet) {
return facet.name === attributeName;
});
var facet = split.reduce(function (intermediateFacet, part) {
var newFacet =
intermediateFacet &&
find(intermediateFacet.data, function (f) {
return f.name === part;
});
return newFacet !== undefined ? newFacet : intermediateFacet;
}, rootFacet);
var count = (facet && facet.count) || 0;
var exhaustive = (facet && facet.exhaustive) || false;
var path = (facet && facet.path) || '';
return {
type: 'hierarchical',
attributeName: attributeName,
name: path,
count: count,
exhaustive: exhaustive,
};
}
module.exports = SearchResults;
/***/ }),
/***/ 49374:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
var EventEmitter = __webpack_require__(17331);
var DerivedHelper = __webpack_require__(68078);
var escapeFacetValue = (__webpack_require__(94039).escapeFacetValue);
var inherits = __webpack_require__(14853);
var merge = __webpack_require__(60185);
var objectHasKeys = __webpack_require__(90116);
var omit = __webpack_require__(49803);
var requestBuilder = __webpack_require__(96394);
var SearchParameters = __webpack_require__(17775);
var SearchResults = __webpack_require__(23076);
var version = __webpack_require__(24336);
/**
* Event triggered when a parameter is set or updated
* @event AlgoliaSearchHelper#event:change
* @property {object} event
* @property {SearchParameters} event.state the current parameters with the latest changes applied
* @property {SearchResults} event.results the previous results received from Algolia. `null` before the first request
* @example
* helper.on('change', function(event) {
* console.log('The parameters have changed');
* });
*/
/**
* Event triggered when a main search is sent to Algolia
* @event AlgoliaSearchHelper#event:search
* @property {object} event
* @property {SearchParameters} event.state the parameters used for this search
* @property {SearchResults} event.results the results from the previous search. `null` if it is the first search.
* @example
* helper.on('search', function(event) {
* console.log('Search sent');
* });
*/
/**
* Event triggered when a search using `searchForFacetValues` is sent to Algolia
* @event AlgoliaSearchHelper#event:searchForFacetValues
* @property {object} event
* @property {SearchParameters} event.state the parameters used for this search it is the first search.
* @property {string} event.facet the facet searched into
* @property {string} event.query the query used to search in the facets
* @example
* helper.on('searchForFacetValues', function(event) {
* console.log('searchForFacetValues sent');
* });
*/
/**
* Event triggered when a search using `searchOnce` is sent to Algolia
* @event AlgoliaSearchHelper#event:searchOnce
* @property {object} event
* @property {SearchParameters} event.state the parameters used for this search it is the first search.
* @example
* helper.on('searchOnce', function(event) {
* console.log('searchOnce sent');
* });
*/
/**
* Event triggered when the results are retrieved from Algolia
* @event AlgoliaSearchHelper#event:result
* @property {object} event
* @property {SearchResults} event.results the results received from Algolia
* @property {SearchParameters} event.state the parameters used to query Algolia. Those might be different from the one in the helper instance (for example if the network is unreliable).
* @example
* helper.on('result', function(event) {
* console.log('Search results received');
* });
*/
/**
* Event triggered when Algolia sends back an error. For example, if an unknown parameter is
* used, the error can be caught using this event.
* @event AlgoliaSearchHelper#event:error
* @property {object} event
* @property {Error} event.error the error returned by the Algolia.
* @example
* helper.on('error', function(event) {
* console.log('Houston we got a problem.');
* });
*/
/**
* Event triggered when the queue of queries have been depleted (with any result or outdated queries)
* @event AlgoliaSearchHelper#event:searchQueueEmpty
* @example
* helper.on('searchQueueEmpty', function() {
* console.log('No more search pending');
* // This is received before the result event if we're not expecting new results
* });
*
* helper.search();
*/
/**
* Initialize a new AlgoliaSearchHelper
* @class
* @classdesc The AlgoliaSearchHelper is a class that ease the management of the
* search. It provides an event based interface for search callbacks:
* - change: when the internal search state is changed.
* This event contains a {@link SearchParameters} object and the
* {@link SearchResults} of the last result if any.
* - search: when a search is triggered using the `search()` method.
* - result: when the response is retrieved from Algolia and is processed.
* This event contains a {@link SearchResults} object and the
* {@link SearchParameters} corresponding to this answer.
* - error: when the response is an error. This event contains the error returned by the server.
* @param {AlgoliaSearch} client an AlgoliaSearch client
* @param {string} index the index name to query
* @param {SearchParameters | object} options an object defining the initial
* config of the search. It doesn't have to be a {SearchParameters},
* just an object containing the properties you need from it.
*/
function AlgoliaSearchHelper(client, index, options) {
if (typeof client.addAlgoliaAgent === 'function') {
client.addAlgoliaAgent('JS Helper (' + version + ')');
}
this.setClient(client);
var opts = options || {};
opts.index = index;
this.state = SearchParameters.make(opts);
this.lastResults = null;
this._queryId = 0;
this._lastQueryIdReceived = -1;
this.derivedHelpers = [];
this._currentNbQueries = 0;
}
inherits(AlgoliaSearchHelper, EventEmitter);
/**
* Start the search with the parameters set in the state. When the
* method is called, it triggers a `search` event. The results will
* be available through the `result` event. If an error occurs, an
* `error` will be fired instead.
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires search
* @fires result
* @fires error
* @chainable
*/
AlgoliaSearchHelper.prototype.search = function () {
this._search({ onlyWithDerivedHelpers: false });
return this;
};
AlgoliaSearchHelper.prototype.searchOnlyWithDerivedHelpers = function () {
this._search({ onlyWithDerivedHelpers: true });
return this;
};
/**
* Gets the search query parameters that would be sent to the Algolia Client
* for the hits
* @return {object} Query Parameters
*/
AlgoliaSearchHelper.prototype.getQuery = function () {
var state = this.state;
return requestBuilder._getHitsSearchParams(state);
};
/**
* Start a search using a modified version of the current state. This method does
* not trigger the helper lifecycle and does not modify the state kept internally
* by the helper. This second aspect means that the next search call will be the
* same as a search call before calling searchOnce.
* @param {object} options can contain all the parameters that can be set to SearchParameters
* plus the index
* @param {function} [cb] optional callback executed when the response from the
* server is back.
* @return {promise|undefined} if a callback is passed the method returns undefined
* otherwise it returns a promise containing an object with two keys :
* - content with a SearchResults
* - state with the state used for the query as a SearchParameters
* @example
* // Changing the number of records returned per page to 1
* // This example uses the callback API
* var state = helper.searchOnce({hitsPerPage: 1},
* function(error, content, state) {
* // if an error occurred it will be passed in error, otherwise its value is null
* // content contains the results formatted as a SearchResults
* // state is the instance of SearchParameters used for this search
* });
* @example
* // Changing the number of records returned per page to 1
* // This example uses the promise API
* var state1 = helper.searchOnce({hitsPerPage: 1})
* .then(promiseHandler);
*
* function promiseHandler(res) {
* // res contains
* // {
* // content : SearchResults
* // state : SearchParameters (the one used for this specific search)
* // }
* }
*/
AlgoliaSearchHelper.prototype.searchOnce = function (options, cb) {
var tempState = !options
? this.state
: this.state.setQueryParameters(options);
var queries = requestBuilder._getQueries(tempState.index, tempState);
// eslint-disable-next-line consistent-this
var self = this;
this._currentNbQueries++;
this.emit('searchOnce', {
state: tempState,
});
if (cb) {
this.client
.search(queries)
.then(function (content) {
self._currentNbQueries--;
if (self._currentNbQueries === 0) {
self.emit('searchQueueEmpty');
}
cb(null, new SearchResults(tempState, content.results), tempState);
})
.catch(function (err) {
self._currentNbQueries--;
if (self._currentNbQueries === 0) {
self.emit('searchQueueEmpty');
}
cb(err, null, tempState);
});
return undefined;
}
return this.client.search(queries).then(
function (content) {
self._currentNbQueries--;
if (self._currentNbQueries === 0) self.emit('searchQueueEmpty');
return {
content: new SearchResults(tempState, content.results),
state: tempState,
_originalResponse: content,
};
},
function (e) {
self._currentNbQueries--;
if (self._currentNbQueries === 0) self.emit('searchQueueEmpty');
throw e;
}
);
};
/**
* Start the search for answers with the parameters set in the state.
* This method returns a promise.
* @param {Object} options - the options for answers API call
* @param {string[]} options.attributesForPrediction - Attributes to use for predictions. If empty, `searchableAttributes` is used instead.
* @param {string[]} options.queryLanguages - The languages in the query. Currently only supports ['en'].
* @param {number} options.nbHits - Maximum number of answers to retrieve from the Answers Engine. Cannot be greater than 1000.
*
* @return {promise} the answer results
* @deprecated answers is deprecated and will be replaced with new initiatives
*/
AlgoliaSearchHelper.prototype.findAnswers = function (options) {
// eslint-disable-next-line no-console
console.warn('[algoliasearch-helper] answers is no longer supported');
var state = this.state;
var derivedHelper = this.derivedHelpers[0];
if (!derivedHelper) {
return Promise.resolve([]);
}
var derivedState = derivedHelper.getModifiedState(state);
var data = merge(
{
attributesForPrediction: options.attributesForPrediction,
nbHits: options.nbHits,
},
{
params: omit(requestBuilder._getHitsSearchParams(derivedState), [
'attributesToSnippet',
'hitsPerPage',
'restrictSearchableAttributes',
'snippetEllipsisText',
]),
}
);
var errorMessage =
'search for answers was called, but this client does not have a function client.initIndex(index).findAnswers';
if (typeof this.client.initIndex !== 'function') {
throw new Error(errorMessage);
}
var index = this.client.initIndex(derivedState.index);
if (typeof index.findAnswers !== 'function') {
throw new Error(errorMessage);
}
return index.findAnswers(derivedState.query, options.queryLanguages, data);
};
/**
* Structure of each result when using
* [`searchForFacetValues()`](reference.html#AlgoliaSearchHelper#searchForFacetValues)
* @typedef FacetSearchHit
* @type {object}
* @property {string} value the facet value
* @property {string} highlighted the facet value highlighted with the query string
* @property {number} count number of occurrence of this facet value
* @property {boolean} isRefined true if the value is already refined
*/
/**
* Structure of the data resolved by the
* [`searchForFacetValues()`](reference.html#AlgoliaSearchHelper#searchForFacetValues)
* promise.
* @typedef FacetSearchResult
* @type {object}
* @property {FacetSearchHit} facetHits the results for this search for facet values
* @property {number} processingTimeMS time taken by the query inside the engine
*/
/**
* Search for facet values based on an query and the name of a faceted attribute. This
* triggers a search and will return a promise. On top of using the query, it also sends
* the parameters from the state so that the search is narrowed down to only the possible values.
*
* See the description of [FacetSearchResult](reference.html#FacetSearchResult)
* @param {string} facet the name of the faceted attribute
* @param {string} query the string query for the search
* @param {number} [maxFacetHits] the maximum number values returned. Should be > 0 and <= 100
* @param {object} [userState] the set of custom parameters to use on top of the current state. Setting a property to `undefined` removes
* it in the generated query.
* @return {promise.<FacetSearchResult>} the results of the search
*/
AlgoliaSearchHelper.prototype.searchForFacetValues = function (
facet,
query,
maxFacetHits,
userState
) {
var clientHasSFFV = typeof this.client.searchForFacetValues === 'function';
var clientHasInitIndex = typeof this.client.initIndex === 'function';
if (
!clientHasSFFV &&
!clientHasInitIndex &&
typeof this.client.search !== 'function'
) {
throw new Error(
'search for facet values (searchable) was called, but this client does not have a function client.searchForFacetValues or client.initIndex(index).searchForFacetValues'
);
}
var state = this.state.setQueryParameters(userState || {});
var isDisjunctive = state.isDisjunctiveFacet(facet);
var algoliaQuery = requestBuilder.getSearchForFacetQuery(
facet,
query,
maxFacetHits,
state
);
this._currentNbQueries++;
// eslint-disable-next-line consistent-this
var self = this;
var searchForFacetValuesPromise;
// newer algoliasearch ^3.27.1 - ~4.0.0
if (clientHasSFFV) {
searchForFacetValuesPromise = this.client.searchForFacetValues([
{ indexName: state.index, params: algoliaQuery },
]);
// algoliasearch < 3.27.1
} else if (clientHasInitIndex) {
searchForFacetValuesPromise = this.client
.initIndex(state.index)
.searchForFacetValues(algoliaQuery);
// algoliasearch ~5.0.0
} else {
// @MAJOR only use client.search
delete algoliaQuery.facetName;
searchForFacetValuesPromise = this.client
.search([
{
type: 'facet',
facet: facet,
indexName: state.index,
params: algoliaQuery,
},
])
.then(function processResponse(response) {
return response.results[0];
});
}
this.emit('searchForFacetValues', {
state: state,
facet: facet,
query: query,
});
return searchForFacetValuesPromise.then(
function addIsRefined(content) {
self._currentNbQueries--;
if (self._currentNbQueries === 0) self.emit('searchQueueEmpty');
content = Array.isArray(content) ? content[0] : content;
content.facetHits.forEach(function (f) {
f.escapedValue = escapeFacetValue(f.value);
f.isRefined = isDisjunctive
? state.isDisjunctiveFacetRefined(facet, f.escapedValue)
: state.isFacetRefined(facet, f.escapedValue);
});
return content;
},
function (e) {
self._currentNbQueries--;
if (self._currentNbQueries === 0) self.emit('searchQueueEmpty');
throw e;
}
);
};
/**
* Sets the text query used for the search.
*
* This method resets the current page to 0.
* @param {string} q the user query
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.setQuery = function (q) {
this._change({
state: this.state.resetPage().setQuery(q),
isPageReset: true,
});
return this;
};
/**
* Remove all the types of refinements except tags. A string can be provided to remove
* only the refinements of a specific attribute. For more advanced use case, you can
* provide a function instead. This function should follow the
* [clearCallback definition](#SearchParameters.clearCallback).
*
* This method resets the current page to 0.
* @param {string} [name] optional name of the facet / attribute on which we want to remove all refinements
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
* @example
* // Removing all the refinements
* helper.clearRefinements().search();
* @example
* // Removing all the filters on a the category attribute.
* helper.clearRefinements('category').search();
* @example
* // Removing only the exclude filters on the category facet.
* helper.clearRefinements(function(value, attribute, type) {
* return type === 'exclude' && attribute === 'category';
* }).search();
*/
AlgoliaSearchHelper.prototype.clearRefinements = function (name) {
this._change({
state: this.state.resetPage().clearRefinements(name),
isPageReset: true,
});
return this;
};
/**
* Remove all the tag filters.
*
* This method resets the current page to 0.
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.clearTags = function () {
this._change({
state: this.state.resetPage().clearTags(),
isPageReset: true,
});
return this;
};
/**
* Adds a disjunctive filter to a faceted attribute with the `value` provided. If the
* filter is already set, it doesn't change the filters.
*
* This method resets the current page to 0.
* @param {string} facet the facet to refine
* @param {string} value the associated value (will be converted to string)
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.addDisjunctiveFacetRefinement = function (
facet,
value
) {
this._change({
state: this.state.resetPage().addDisjunctiveFacetRefinement(facet, value),
isPageReset: true,
});
return this;
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since version 2.4.0, see {@link AlgoliaSearchHelper#addDisjunctiveFacetRefinement}
*/
AlgoliaSearchHelper.prototype.addDisjunctiveRefine = function () {
return this.addDisjunctiveFacetRefinement.apply(this, arguments);
};
/**
* Adds a refinement on a hierarchical facet. It will throw
* an exception if the facet is not defined or if the facet
* is already refined.
*
* This method resets the current page to 0.
* @param {string} facet the facet name
* @param {string} path the hierarchical facet path
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @throws Error if the facet is not defined or if the facet is refined
* @chainable
* @fires change
*/
AlgoliaSearchHelper.prototype.addHierarchicalFacetRefinement = function (
facet,
path
) {
this._change({
state: this.state.resetPage().addHierarchicalFacetRefinement(facet, path),
isPageReset: true,
});
return this;
};
/**
* Adds a an numeric filter to an attribute with the `operator` and `value` provided. If the
* filter is already set, it doesn't change the filters.
*
* This method resets the current page to 0.
* @param {string} attribute the attribute on which the numeric filter applies
* @param {string} operator the operator of the filter
* @param {number} value the value of the filter
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.addNumericRefinement = function (
attribute,
operator,
value
) {
this._change({
state: this.state
.resetPage()
.addNumericRefinement(attribute, operator, value),
isPageReset: true,
});
return this;
};
/**
* Adds a filter to a faceted attribute with the `value` provided. If the
* filter is already set, it doesn't change the filters.
*
* This method resets the current page to 0.
* @param {string} facet the facet to refine
* @param {string} value the associated value (will be converted to string)
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.addFacetRefinement = function (facet, value) {
this._change({
state: this.state.resetPage().addFacetRefinement(facet, value),
isPageReset: true,
});
return this;
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since version 2.4.0, see {@link AlgoliaSearchHelper#addFacetRefinement}
*/
AlgoliaSearchHelper.prototype.addRefine = function () {
return this.addFacetRefinement.apply(this, arguments);
};
/**
* Adds a an exclusion filter to a faceted attribute with the `value` provided. If the
* filter is already set, it doesn't change the filters.
*
* This method resets the current page to 0.
* @param {string} facet the facet to refine
* @param {string} value the associated value (will be converted to string)
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.addFacetExclusion = function (facet, value) {
this._change({
state: this.state.resetPage().addExcludeRefinement(facet, value),
isPageReset: true,
});
return this;
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since version 2.4.0, see {@link AlgoliaSearchHelper#addFacetExclusion}
*/
AlgoliaSearchHelper.prototype.addExclude = function () {
return this.addFacetExclusion.apply(this, arguments);
};
/**
* Adds a tag filter with the `tag` provided. If the
* filter is already set, it doesn't change the filters.
*
* This method resets the current page to 0.
* @param {string} tag the tag to add to the filter
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.addTag = function (tag) {
this._change({
state: this.state.resetPage().addTagRefinement(tag),
isPageReset: true,
});
return this;
};
/**
* Removes an numeric filter to an attribute with the `operator` and `value` provided. If the
* filter is not set, it doesn't change the filters.
*
* Some parameters are optional, triggering different behavior:
* - if the value is not provided, then all the numeric value will be removed for the
* specified attribute/operator couple.
* - if the operator is not provided either, then all the numeric filter on this attribute
* will be removed.
*
* This method resets the current page to 0.
* @param {string} attribute the attribute on which the numeric filter applies
* @param {string} [operator] the operator of the filter
* @param {number} [value] the value of the filter
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.removeNumericRefinement = function (
attribute,
operator,
value
) {
this._change({
state: this.state
.resetPage()
.removeNumericRefinement(attribute, operator, value),
isPageReset: true,
});
return this;
};
/**
* Removes a disjunctive filter to a faceted attribute with the `value` provided. If the
* filter is not set, it doesn't change the filters.
*
* If the value is omitted, then this method will remove all the filters for the
* attribute.
*
* This method resets the current page to 0.
* @param {string} facet the facet to refine
* @param {string} [value] the associated value
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.removeDisjunctiveFacetRefinement = function (
facet,
value
) {
this._change({
state: this.state
.resetPage()
.removeDisjunctiveFacetRefinement(facet, value),
isPageReset: true,
});
return this;
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since version 2.4.0, see {@link AlgoliaSearchHelper#removeDisjunctiveFacetRefinement}
*/
AlgoliaSearchHelper.prototype.removeDisjunctiveRefine = function () {
return this.removeDisjunctiveFacetRefinement.apply(this, arguments);
};
/**
* Removes the refinement set on a hierarchical facet.
* @param {string} facet the facet name
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @throws Error if the facet is not defined or if the facet is not refined
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.removeHierarchicalFacetRefinement = function (
facet
) {
this._change({
state: this.state.resetPage().removeHierarchicalFacetRefinement(facet),
isPageReset: true,
});
return this;
};
/**
* Removes a filter to a faceted attribute with the `value` provided. If the
* filter is not set, it doesn't change the filters.
*
* If the value is omitted, then this method will remove all the filters for the
* attribute.
*
* This method resets the current page to 0.
* @param {string} facet the facet to refine
* @param {string} [value] the associated value
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.removeFacetRefinement = function (facet, value) {
this._change({
state: this.state.resetPage().removeFacetRefinement(facet, value),
isPageReset: true,
});
return this;
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since version 2.4.0, see {@link AlgoliaSearchHelper#removeFacetRefinement}
*/
AlgoliaSearchHelper.prototype.removeRefine = function () {
return this.removeFacetRefinement.apply(this, arguments);
};
/**
* Removes an exclusion filter to a faceted attribute with the `value` provided. If the
* filter is not set, it doesn't change the filters.
*
* If the value is omitted, then this method will remove all the filters for the
* attribute.
*
* This method resets the current page to 0.
* @param {string} facet the facet to refine
* @param {string} [value] the associated value
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.removeFacetExclusion = function (facet, value) {
this._change({
state: this.state.resetPage().removeExcludeRefinement(facet, value),
isPageReset: true,
});
return this;
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since version 2.4.0, see {@link AlgoliaSearchHelper#removeFacetExclusion}
*/
AlgoliaSearchHelper.prototype.removeExclude = function () {
return this.removeFacetExclusion.apply(this, arguments);
};
/**
* Removes a tag filter with the `tag` provided. If the
* filter is not set, it doesn't change the filters.
*
* This method resets the current page to 0.
* @param {string} tag tag to remove from the filter
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.removeTag = function (tag) {
this._change({
state: this.state.resetPage().removeTagRefinement(tag),
isPageReset: true,
});
return this;
};
/**
* Adds or removes an exclusion filter to a faceted attribute with the `value` provided. If
* the value is set then it removes it, otherwise it adds the filter.
*
* This method resets the current page to 0.
* @param {string} facet the facet to refine
* @param {string} value the associated value
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.toggleFacetExclusion = function (facet, value) {
this._change({
state: this.state.resetPage().toggleExcludeFacetRefinement(facet, value),
isPageReset: true,
});
return this;
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since version 2.4.0, see {@link AlgoliaSearchHelper#toggleFacetExclusion}
*/
AlgoliaSearchHelper.prototype.toggleExclude = function () {
return this.toggleFacetExclusion.apply(this, arguments);
};
/**
* Adds or removes a filter to a faceted attribute with the `value` provided. If
* the value is set then it removes it, otherwise it adds the filter.
*
* This method can be used for conjunctive, disjunctive and hierarchical filters.
*
* This method resets the current page to 0.
* @param {string} facet the facet to refine
* @param {string} value the associated value
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @throws Error will throw an error if the facet is not declared in the settings of the helper
* @fires change
* @chainable
* @deprecated since version 2.19.0, see {@link AlgoliaSearchHelper#toggleFacetRefinement}
*/
AlgoliaSearchHelper.prototype.toggleRefinement = function (facet, value) {
return this.toggleFacetRefinement(facet, value);
};
/**
* Adds or removes a filter to a faceted attribute with the `value` provided. If
* the value is set then it removes it, otherwise it adds the filter.
*
* This method can be used for conjunctive, disjunctive and hierarchical filters.
*
* This method resets the current page to 0.
* @param {string} facet the facet to refine
* @param {string} value the associated value
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @throws Error will throw an error if the facet is not declared in the settings of the helper
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.toggleFacetRefinement = function (facet, value) {
this._change({
state: this.state.resetPage().toggleFacetRefinement(facet, value),
isPageReset: true,
});
return this;
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since version 2.4.0, see {@link AlgoliaSearchHelper#toggleFacetRefinement}
*/
AlgoliaSearchHelper.prototype.toggleRefine = function () {
return this.toggleFacetRefinement.apply(this, arguments);
};
/**
* Adds or removes a tag filter with the `value` provided. If
* the value is set then it removes it, otherwise it adds the filter.
*
* This method resets the current page to 0.
* @param {string} tag tag to remove or add
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.toggleTag = function (tag) {
this._change({
state: this.state.resetPage().toggleTagRefinement(tag),
isPageReset: true,
});
return this;
};
/**
* Increments the page number by one.
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
* @example
* helper.setPage(0).nextPage().getPage();
* // returns 1
*/
AlgoliaSearchHelper.prototype.nextPage = function () {
var page = this.state.page || 0;
return this.setPage(page + 1);
};
/**
* Decrements the page number by one.
* @fires change
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @chainable
* @example
* helper.setPage(1).previousPage().getPage();
* // returns 0
*/
AlgoliaSearchHelper.prototype.previousPage = function () {
var page = this.state.page || 0;
return this.setPage(page - 1);
};
/**
* @private
* @param {number} page The page number
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @chainable
* @fires change
*/
function setCurrentPage(page) {
if (page < 0) throw new Error('Page requested below 0.');
this._change({
state: this.state.setPage(page),
isPageReset: false,
});
return this;
}
/**
* Change the current page
* @deprecated
* @param {number} page The page number
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.setCurrentPage = setCurrentPage;
/**
* Updates the current page.
* @function
* @param {number} page The page number
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.setPage = setCurrentPage;
/**
* Updates the name of the index that will be targeted by the query.
*
* This method resets the current page to 0.
* @param {string} name the index name
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.setIndex = function (name) {
this._change({
state: this.state.resetPage().setIndex(name),
isPageReset: true,
});
return this;
};
/**
* Update a parameter of the search. This method reset the page
*
* The complete list of parameters is available on the
* [Algolia website](https://www.algolia.com/doc/rest#query-an-index).
* The most commonly used parameters have their own [shortcuts](#query-parameters-shortcuts)
* or benefit from higher-level APIs (all the kind of filters and facets have their own API)
*
* This method resets the current page to 0.
* @param {string} parameter name of the parameter to update
* @param {any} value new value of the parameter
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
* @example
* helper.setQueryParameter('hitsPerPage', 20).search();
*/
AlgoliaSearchHelper.prototype.setQueryParameter = function (parameter, value) {
this._change({
state: this.state.resetPage().setQueryParameter(parameter, value),
isPageReset: true,
});
return this;
};
/**
* Set the whole state (warning: will erase previous state)
* @param {SearchParameters} newState the whole new state
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @fires change
* @chainable
*/
AlgoliaSearchHelper.prototype.setState = function (newState) {
this._change({
state: SearchParameters.make(newState),
isPageReset: false,
});
return this;
};
/**
* Override the current state without triggering a change event.
* Do not use this method unless you know what you are doing. (see the example
* for a legit use case)
* @param {SearchParameters} newState the whole new state
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
* @example
* helper.on('change', function(state){
* // In this function you might want to find a way to store the state in the url/history
* updateYourURL(state)
* })
* window.onpopstate = function(event){
* // This is naive though as you should check if the state is really defined etc.
* helper.overrideStateWithoutTriggeringChangeEvent(event.state).search()
* }
* @chainable
*/
AlgoliaSearchHelper.prototype.overrideStateWithoutTriggeringChangeEvent =
function (newState) {
this.state = new SearchParameters(newState);
return this;
};
/**
* Check if an attribute has any numeric, conjunctive, disjunctive or hierarchical filters.
* @param {string} attribute the name of the attribute
* @return {boolean} true if the attribute is filtered by at least one value
* @example
* // hasRefinements works with numeric, conjunctive, disjunctive and hierarchical filters
* helper.hasRefinements('price'); // false
* helper.addNumericRefinement('price', '>', 100);
* helper.hasRefinements('price'); // true
*
* helper.hasRefinements('color'); // false
* helper.addFacetRefinement('color', 'blue');
* helper.hasRefinements('color'); // true
*
* helper.hasRefinements('material'); // false
* helper.addDisjunctiveFacetRefinement('material', 'plastic');
* helper.hasRefinements('material'); // true
*
* helper.hasRefinements('categories'); // false
* helper.toggleFacetRefinement('categories', 'kitchen > knife');
* helper.hasRefinements('categories'); // true
*
*/
AlgoliaSearchHelper.prototype.hasRefinements = function (attribute) {
if (objectHasKeys(this.state.getNumericRefinements(attribute))) {
return true;
} else if (this.state.isConjunctiveFacet(attribute)) {
return this.state.isFacetRefined(attribute);
} else if (this.state.isDisjunctiveFacet(attribute)) {
return this.state.isDisjunctiveFacetRefined(attribute);
} else if (this.state.isHierarchicalFacet(attribute)) {
return this.state.isHierarchicalFacetRefined(attribute);
}
// there's currently no way to know that the user did call `addNumericRefinement` at some point
// thus we cannot distinguish if there once was a numeric refinement that was cleared
// so we will return false in every other situations to be consistent
// while what we should do here is throw because we did not find the attribute in any type
// of refinement
return false;
};
/**
* Check if a value is excluded for a specific faceted attribute. If the value
* is omitted then the function checks if there is any excluding refinements.
*
* @param {string} facet name of the attribute for used for faceting
* @param {string} [value] optional value. If passed will test that this value
* is filtering the given facet.
* @return {boolean} true if refined
* @example
* helper.isExcludeRefined('color'); // false
* helper.isExcludeRefined('color', 'blue') // false
* helper.isExcludeRefined('color', 'red') // false
*
* helper.addFacetExclusion('color', 'red');
*
* helper.isExcludeRefined('color'); // true
* helper.isExcludeRefined('color', 'blue') // false
* helper.isExcludeRefined('color', 'red') // true
*/
AlgoliaSearchHelper.prototype.isExcluded = function (facet, value) {
return this.state.isExcludeRefined(facet, value);
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since 2.4.0, see {@link AlgoliaSearchHelper#hasRefinements}
*/
AlgoliaSearchHelper.prototype.isDisjunctiveRefined = function (facet, value) {
return this.state.isDisjunctiveFacetRefined(facet, value);
};
/**
* Check if the string is a currently filtering tag.
* @param {string} tag tag to check
* @return {boolean} true if the tag is currently refined
*/
AlgoliaSearchHelper.prototype.hasTag = function (tag) {
return this.state.isTagRefined(tag);
};
// eslint-disable-next-line valid-jsdoc
/**
* @deprecated since 2.4.0, see {@link AlgoliaSearchHelper#hasTag}
*/
AlgoliaSearchHelper.prototype.isTagRefined = function () {
return this.hasTagRefinements.apply(this, arguments);
};
/**
* Get the name of the currently used index.
* @return {string} name of the index
* @example
* helper.setIndex('highestPrice_products').getIndex();
* // returns 'highestPrice_products'
*/
AlgoliaSearchHelper.prototype.getIndex = function () {
return this.state.index;
};
function getCurrentPage() {
return this.state.page;
}
/**
* Get the currently selected page
* @deprecated
* @return {number} the current page
*/
AlgoliaSearchHelper.prototype.getCurrentPage = getCurrentPage;
/**
* Get the currently selected page
* @function
* @return {number} the current page
*/
AlgoliaSearchHelper.prototype.getPage = getCurrentPage;
/**
* Get all the tags currently set to filters the results.
*
* @return {string[]} The list of tags currently set.
*/
AlgoliaSearchHelper.prototype.getTags = function () {
return this.state.tagRefinements;
};
/**
* Get the list of refinements for a given attribute. This method works with
* conjunctive, disjunctive, excluding and numerical filters.
*
* See also SearchResults#getRefinements
*
* @param {string} facetName attribute name used for faceting
* @return {Array.<FacetRefinement|NumericRefinement>} All Refinement are objects that contain a value, and
* a type. Numeric also contains an operator.
* @example
* helper.addNumericRefinement('price', '>', 100);
* helper.getRefinements('price');
* // [
* // {
* // "value": [
* // 100
* // ],
* // "operator": ">",
* // "type": "numeric"
* // }
* // ]
* @example
* helper.addFacetRefinement('color', 'blue');
* helper.addFacetExclusion('color', 'red');
* helper.getRefinements('color');
* // [
* // {
* // "value": "blue",
* // "type": "conjunctive"
* // },
* // {
* // "value": "red",
* // "type": "exclude"
* // }
* // ]
* @example
* helper.addDisjunctiveFacetRefinement('material', 'plastic');
* // [
* // {
* // "value": "plastic",
* // "type": "disjunctive"
* // }
* // ]
*/
AlgoliaSearchHelper.prototype.getRefinements = function (facetName) {
var refinements = [];
if (this.state.isConjunctiveFacet(facetName)) {
var conjRefinements = this.state.getConjunctiveRefinements(facetName);
conjRefinements.forEach(function (r) {
refinements.push({
value: r,
type: 'conjunctive',
});
});
var excludeRefinements = this.state.getExcludeRefinements(facetName);
excludeRefinements.forEach(function (r) {
refinements.push({
value: r,
type: 'exclude',
});
});
} else if (this.state.isDisjunctiveFacet(facetName)) {
var disjunctiveRefinements =
this.state.getDisjunctiveRefinements(facetName);
disjunctiveRefinements.forEach(function (r) {
refinements.push({
value: r,
type: 'disjunctive',
});
});
}
var numericRefinements = this.state.getNumericRefinements(facetName);
Object.keys(numericRefinements).forEach(function (operator) {
var value = numericRefinements[operator];
refinements.push({
value: value,
operator: operator,
type: 'numeric',
});
});
return refinements;
};
/**
* Return the current refinement for the (attribute, operator)
* @param {string} attribute attribute in the record
* @param {string} operator operator applied on the refined values
* @return {Array.<number|number[]>} refined values
*/
AlgoliaSearchHelper.prototype.getNumericRefinement = function (
attribute,
operator
) {
return this.state.getNumericRefinement(attribute, operator);
};
/**
* Get the current breadcrumb for a hierarchical facet, as an array
* @param {string} facetName Hierarchical facet name
* @return {array.<string>} the path as an array of string
*/
AlgoliaSearchHelper.prototype.getHierarchicalFacetBreadcrumb = function (
facetName
) {
return this.state.getHierarchicalFacetBreadcrumb(facetName);
};
// /////////// PRIVATE
/**
* Perform the underlying queries
* @private
* @param {object} options options for the query
* @param {boolean} [options.onlyWithDerivedHelpers=false] if true, only the derived helpers will be queried
* @return {undefined} does not return anything
* @fires search
* @fires result
* @fires error
*/
AlgoliaSearchHelper.prototype._search = function (options) {
var state = this.state;
var states = [];
var mainQueries = [];
if (!options.onlyWithDerivedHelpers) {
mainQueries = requestBuilder._getQueries(state.index, state);
states.push({
state: state,
queriesCount: mainQueries.length,
helper: this,
});
this.emit('search', {
state: state,
results: this.lastResults,
});
}
var derivedQueries = this.derivedHelpers.map(function (derivedHelper) {
var derivedState = derivedHelper.getModifiedState(state);
var derivedStateQueries = derivedState.index
? requestBuilder._getQueries(derivedState.index, derivedState)
: [];
states.push({
state: derivedState,
queriesCount: derivedStateQueries.length,
helper: derivedHelper,
});
derivedHelper.emit('search', {
state: derivedState,
results: derivedHelper.lastResults,
});
return derivedStateQueries;
});
var queries = Array.prototype.concat.apply(mainQueries, derivedQueries);
var queryId = this._queryId++;
this._currentNbQueries++;
if (!queries.length) {
return Promise.resolve({ results: [] }).then(
this._dispatchAlgoliaResponse.bind(this, states, queryId)
);
}
try {
this.client
.search(queries)
.then(this._dispatchAlgoliaResponse.bind(this, states, queryId))
.catch(this._dispatchAlgoliaError.bind(this, queryId));
} catch (error) {
// If we reach this part, we're in an internal error state
this.emit('error', {
error: error,
});
}
return undefined;
};
/**
* Transform the responses as sent by the server and transform them into a user
* usable object that merge the results of all the batch requests. It will dispatch
* over the different helper + derived helpers (when there are some).
* @private
* @param {array.<{SearchParameters, AlgoliaQueries, AlgoliaSearchHelper}>} states state used to generate the request
* @param {number} queryId id of the current request
* @param {object} content content of the response
* @return {undefined}
*/
AlgoliaSearchHelper.prototype._dispatchAlgoliaResponse = function (
states,
queryId,
content
) {
// @TODO remove the number of outdated queries discarded instead of just one
if (queryId < this._lastQueryIdReceived) {
// Outdated answer
return;
}
this._currentNbQueries -= queryId - this._lastQueryIdReceived;
this._lastQueryIdReceived = queryId;
if (this._currentNbQueries === 0) this.emit('searchQueueEmpty');
var results = content.results.slice();
states.forEach(function (s) {
var state = s.state;
var queriesCount = s.queriesCount;
var helper = s.helper;
var specificResults = results.splice(0, queriesCount);
if (!state.index) {
helper.emit('result', {
results: null,
state: state,
});
return;
}
helper.lastResults = new SearchResults(state, specificResults);
helper.emit('result', {
results: helper.lastResults,
state: state,
});
});
};
AlgoliaSearchHelper.prototype._dispatchAlgoliaError = function (
queryId,
error
) {
if (queryId < this._lastQueryIdReceived) {
// Outdated answer
return;
}
this._currentNbQueries -= queryId - this._lastQueryIdReceived;
this._lastQueryIdReceived = queryId;
this.emit('error', {
error: error,
});
if (this._currentNbQueries === 0) this.emit('searchQueueEmpty');
};
AlgoliaSearchHelper.prototype.containsRefinement = function (
query,
facetFilters,
numericFilters,
tagFilters
) {
return (
query ||
facetFilters.length !== 0 ||
numericFilters.length !== 0 ||
tagFilters.length !== 0
);
};
/**
* Test if there are some disjunctive refinements on the facet
* @private
* @param {string} facet the attribute to test
* @return {boolean} true if there are refinements on this attribute
*/
AlgoliaSearchHelper.prototype._hasDisjunctiveRefinements = function (facet) {
return (
this.state.disjunctiveRefinements[facet] &&
this.state.disjunctiveRefinements[facet].length > 0
);
};
AlgoliaSearchHelper.prototype._change = function (event) {
var state = event.state;
var isPageReset = event.isPageReset;
if (state !== this.state) {
this.state = state;
this.emit('change', {
state: this.state,
results: this.lastResults,
isPageReset: isPageReset,
});
}
};
/**
* Clears the cache of the underlying Algolia client.
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
*/
AlgoliaSearchHelper.prototype.clearCache = function () {
if (this.client.clearCache) this.client.clearCache();
return this;
};
/**
* Updates the internal client instance. If the reference of the clients
* are equal then no update is actually done.
* @param {AlgoliaSearch} newClient an AlgoliaSearch client
* @return {AlgoliaSearchHelper} Method is chainable, it returns itself
*/
AlgoliaSearchHelper.prototype.setClient = function (newClient) {
if (this.client === newClient) return this;
if (typeof newClient.addAlgoliaAgent === 'function') {
newClient.addAlgoliaAgent('JS Helper (' + version + ')');
}
this.client = newClient;
return this;
};
/**
* Gets the instance of the currently used client.
* @return {AlgoliaSearch} the currently used client
*/
AlgoliaSearchHelper.prototype.getClient = function () {
return this.client;
};
/**
* Creates an derived instance of the Helper. A derived helper
* is a way to request other indices synchronised with the lifecycle
* of the main Helper. This mechanism uses the multiqueries feature
* of Algolia to aggregate all the requests in a single network call.
*
* This method takes a function that is used to create a new SearchParameter
* that will be used to create requests to Algolia. Those new requests
* are created just before the `search` event. The signature of the function
* is `SearchParameters -> SearchParameters`.
*
* This method returns a new DerivedHelper which is an EventEmitter
* that fires the same `search`, `result` and `error` events. Those
* events, however, will receive data specific to this DerivedHelper
* and the SearchParameters that is returned by the call of the
* parameter function.
* @param {function} fn SearchParameters -> SearchParameters
* @return {DerivedHelper} a new DerivedHelper
*/
AlgoliaSearchHelper.prototype.derive = function (fn) {
var derivedHelper = new DerivedHelper(this, fn);
this.derivedHelpers.push(derivedHelper);
return derivedHelper;
};
/**
* This method detaches a derived Helper from the main one. Prefer using the one from the
* derived helper itself, to remove the event listeners too.
* @private
* @param {DerivedHelper} derivedHelper the derived helper to detach
* @return {undefined} nothing is returned
* @throws Error
*/
AlgoliaSearchHelper.prototype.detachDerivedHelper = function (derivedHelper) {
var pos = this.derivedHelpers.indexOf(derivedHelper);
if (pos === -1) throw new Error('Derived helper already detached');
this.derivedHelpers.splice(pos, 1);
};
/**
* This method returns true if there is currently at least one on-going search.
* @return {boolean} true if there is a search pending
*/
AlgoliaSearchHelper.prototype.hasPendingRequests = function () {
return this._currentNbQueries > 0;
};
/**
* @typedef AlgoliaSearchHelper.NumericRefinement
* @type {object}
* @property {number[]} value the numbers that are used for filtering this attribute with
* the operator specified.
* @property {string} operator the faceting data: value, number of entries
* @property {string} type will be 'numeric'
*/
/**
* @typedef AlgoliaSearchHelper.FacetRefinement
* @type {object}
* @property {string} value the string use to filter the attribute
* @property {string} type the type of filter: 'conjunctive', 'disjunctive', 'exclude'
*/
module.exports = AlgoliaSearchHelper;
/***/ }),
/***/ 74587:
/***/ ((module) => {
"use strict";
module.exports = function compact(array) {
if (!Array.isArray(array)) {
return [];
}
return array.filter(Boolean);
};
/***/ }),
/***/ 52344:
/***/ ((module) => {
"use strict";
// NOTE: this behaves like lodash/defaults, but doesn't mutate the target
// it also preserve keys order
module.exports = function defaultsPure() {
var sources = Array.prototype.slice.call(arguments);
return sources.reduceRight(function (acc, source) {
Object.keys(Object(source)).forEach(function (key) {
if (source[key] === undefined) {
return;
}
if (acc[key] !== undefined) {
// remove if already added, so that we can add it in correct order
delete acc[key];
}
acc[key] = source[key];
});
return acc;
}, {});
};
/***/ }),
/***/ 94039:
/***/ ((module) => {
"use strict";
/**
* Replaces a leading - with \-
* @private
* @param {any} value the facet value to replace
* @returns {any} the escaped facet value or the value if it was not a string
*/
function escapeFacetValue(value) {
if (typeof value !== 'string') return value;
return String(value).replace(/^-/, '\\-');
}
/**
* Replaces a leading \- with -
* @private
* @param {any} value the escaped facet value
* @returns {any} the unescaped facet value or the value if it was not a string
*/
function unescapeFacetValue(value) {
if (typeof value !== 'string') return value;
return value.replace(/^\\-/, '-');
}
module.exports = {
escapeFacetValue: escapeFacetValue,
unescapeFacetValue: unescapeFacetValue,
};
/***/ }),
/***/ 7888:
/***/ ((module) => {
"use strict";
// @MAJOR can be replaced by native Array#find when we change support
module.exports = function find(array, comparator) {
if (!Array.isArray(array)) {
return undefined;
}
for (var i = 0; i < array.length; i++) {
if (comparator(array[i])) {
return array[i];
}
}
return undefined;
};
/***/ }),
/***/ 69725:
/***/ ((module) => {
"use strict";
// @MAJOR can be replaced by native Array#findIndex when we change support
module.exports = function find(array, comparator) {
if (!Array.isArray(array)) {
return -1;
}
for (var i = 0; i < array.length; i++) {
if (comparator(array[i])) {
return i;
}
}
return -1;
};
/***/ }),
/***/ 82293:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
var find = __webpack_require__(7888);
/**
* Transform sort format from user friendly notation to lodash format
* @param {string[]} sortBy array of predicate of the form "attribute:order"
* @param {string[]} [defaults] array of predicate of the form "attribute:order"
* @return {array.<string[]>} array containing 2 elements : attributes, orders
*/
module.exports = function formatSort(sortBy, defaults) {
var defaultInstructions = (defaults || []).map(function (sort) {
return sort.split(':');
});
return sortBy.reduce(
function preparePredicate(out, sort) {
var sortInstruction = sort.split(':');
var matchingDefault = find(
defaultInstructions,
function (defaultInstruction) {
return defaultInstruction[0] === sortInstruction[0];
}
);
if (sortInstruction.length > 1 || !matchingDefault) {
out[0].push(sortInstruction[0]);
out[1].push(sortInstruction[1]);
return out;
}
out[0].push(matchingDefault[0]);
out[1].push(matchingDefault[1]);
return out;
},
[[], []]
);
};
/***/ }),
/***/ 14853:
/***/ ((module) => {
"use strict";
function inherits(ctor, superCtor) {
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true,
},
});
}
module.exports = inherits;
/***/ }),
/***/ 22686:
/***/ ((module) => {
"use strict";
function intersection(arr1, arr2) {
return arr1.filter(function (value, index) {
return (
arr2.indexOf(value) > -1 &&
arr1.indexOf(value) === index /* skips duplicates */
);
});
}
module.exports = intersection;
/***/ }),
/***/ 60185:
/***/ ((module) => {
"use strict";
function clone(value) {
if (typeof value === 'object' && value !== null) {
return _merge(Array.isArray(value) ? [] : {}, value);
}
return value;
}
function isObjectOrArrayOrFunction(value) {
return (
typeof value === 'function' ||
Array.isArray(value) ||
Object.prototype.toString.call(value) === '[object Object]'
);
}
function _merge(target, source) {
if (target === source) {
return target;
}
// eslint-disable-next-line no-restricted-syntax
for (var key in source) {
if (
!Object.prototype.hasOwnProperty.call(source, key) ||
key === '__proto__' ||
key === 'constructor'
) {
// eslint-disable-next-line no-continue
continue;
}
var sourceVal = source[key];
var targetVal = target[key];
if (typeof targetVal !== 'undefined' && typeof sourceVal === 'undefined') {
// eslint-disable-next-line no-continue
continue;
}
if (
isObjectOrArrayOrFunction(targetVal) &&
isObjectOrArrayOrFunction(sourceVal)
) {
target[key] = _merge(targetVal, sourceVal);
} else {
target[key] = clone(sourceVal);
}
}
return target;
}
/**
* This method is like Object.assign, but recursively merges own and inherited
* enumerable keyed properties of source objects into the destination object.
*
* NOTE: this behaves like lodash/merge, but:
* - does mutate functions if they are a source
* - treats non-plain objects as plain
* - does not work for circular objects
* - treats sparse arrays as sparse
* - does not convert Array-like objects (Arguments, NodeLists, etc.) to arrays
*
* @param {Object} target The destination object.
* @param {...Object} [sources] The source objects.
* @returns {Object} Returns `object`.
*/
function merge(target) {
if (!isObjectOrArrayOrFunction(target)) {
target = {};
}
for (var i = 1, l = arguments.length; i < l; i++) {
var source = arguments[i];
if (isObjectOrArrayOrFunction(source)) {
_merge(target, source);
}
}
return target;
}
module.exports = merge;
/***/ }),
/***/ 90116:
/***/ ((module) => {
"use strict";
function objectHasKeys(obj) {
return obj && Object.keys(obj).length > 0;
}
module.exports = objectHasKeys;
/***/ }),
/***/ 49803:
/***/ ((module) => {
"use strict";
// https://github.com/babel/babel/blob/3aaafae053fa75febb3aa45d45b6f00646e30ba4/packages/babel-helpers/src/helpers.js#L604-L620
function _objectWithoutPropertiesLoose(source, excluded) {
if (source === null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key;
var i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
// eslint-disable-next-line no-continue
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
module.exports = _objectWithoutPropertiesLoose;
/***/ }),
/***/ 42148:
/***/ ((module) => {
"use strict";
function compareAscending(value, other) {
if (value !== other) {
var valIsDefined = value !== undefined;
var valIsNull = value === null;
var othIsDefined = other !== undefined;
var othIsNull = other === null;
if (
(!othIsNull && value > other) ||
(valIsNull && othIsDefined) ||
!valIsDefined
) {
return 1;
}
if (
(!valIsNull && value < other) ||
(othIsNull && valIsDefined) ||
!othIsDefined
) {
return -1;
}
}
return 0;
}
/**
* @param {Array<object>} collection object with keys in attributes
* @param {Array<string>} iteratees attributes
* @param {Array<string>} orders asc | desc
* @return {Array<object>} sorted collection
*/
function orderBy(collection, iteratees, orders) {
if (!Array.isArray(collection)) {
return [];
}
if (!Array.isArray(orders)) {
orders = [];
}
var result = collection.map(function (value, index) {
return {
criteria: iteratees.map(function (iteratee) {
return value[iteratee];
}),
index: index,
value: value,
};
});
result.sort(function comparer(object, other) {
var index = -1;
while (++index < object.criteria.length) {
var res = compareAscending(object.criteria[index], other.criteria[index]);
if (res) {
if (index >= orders.length) {
return res;
}
if (orders[index] === 'desc') {
return -res;
}
return res;
}
}
// This ensures a stable sort in V8 and other engines.
// See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
return object.index - other.index;
});
return result.map(function (res) {
return res.value;
});
}
module.exports = orderBy;
/***/ }),
/***/ 28023:
/***/ ((module) => {
"use strict";
function valToNumber(v) {
if (typeof v === 'number') {
return v;
} else if (typeof v === 'string') {
return parseFloat(v);
} else if (Array.isArray(v)) {
return v.map(valToNumber);
}
throw new Error(
'The value should be a number, a parsable string or an array of those.'
);
}
module.exports = valToNumber;
/***/ }),
/***/ 96394:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
var merge = __webpack_require__(60185);
function sortObject(obj) {
return Object.keys(obj)
.sort()
.reduce(function (acc, curr) {
acc[curr] = obj[curr];
return acc;
}, {});
}
var requestBuilder = {
/**
* Get all the queries to send to the client, those queries can used directly
* with the Algolia client.
* @private
* @param {string} index The name of the index
* @param {SearchParameters} state The state from which to get the queries
* @return {object[]} The queries
*/
_getQueries: function getQueries(index, state) {
var queries = [];
// One query for the hits
queries.push({
indexName: index,
params: requestBuilder._getHitsSearchParams(state),
});
// One for each disjunctive facets
state.getRefinedDisjunctiveFacets().forEach(function (refinedFacet) {
queries.push({
indexName: index,
params: requestBuilder._getDisjunctiveFacetSearchParams(
state,
refinedFacet
),
});
});
// More to get the parent levels of the hierarchical facets when refined
state.getRefinedHierarchicalFacets().forEach(function (refinedFacet) {
var hierarchicalFacet = state.getHierarchicalFacetByName(refinedFacet);
var currentRefinement = state.getHierarchicalRefinement(refinedFacet);
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
// If we are deeper than level 0 (starting from `beer > IPA`)
// we want to get all parent values
if (
currentRefinement.length > 0 &&
currentRefinement[0].split(separator).length > 1
) {
// We generate a map of the filters we will use for our facet values queries
var filtersMap = currentRefinement[0]
.split(separator)
.slice(0, -1)
.reduce(function createFiltersMap(map, segment, level) {
return map.concat({
attribute: hierarchicalFacet.attributes[level],
value:
level === 0
? segment
: [map[map.length - 1].value, segment].join(separator),
});
}, []);
filtersMap.forEach(function (filter, level) {
var params = requestBuilder._getDisjunctiveFacetSearchParams(
state,
filter.attribute,
level === 0
);
// Keep facet filters unrelated to current hierarchical attributes
function hasHierarchicalFacetFilter(value) {
return hierarchicalFacet.attributes.some(function (attribute) {
return attribute === value.split(':')[0];
});
}
var filteredFacetFilters = (params.facetFilters || []).reduce(
function (acc, facetFilter) {
if (Array.isArray(facetFilter)) {
var filtered = facetFilter.filter(function (filterValue) {
return !hasHierarchicalFacetFilter(filterValue);
});
if (filtered.length > 0) {
acc.push(filtered);
}
}
if (
typeof facetFilter === 'string' &&
!hasHierarchicalFacetFilter(facetFilter)
) {
acc.push(facetFilter);
}
return acc;
},
[]
);
var parent = filtersMap[level - 1];
if (level > 0) {
params.facetFilters = filteredFacetFilters.concat(
parent.attribute + ':' + parent.value
);
} else {
params.facetFilters =
filteredFacetFilters.length > 0
? filteredFacetFilters
: undefined;
}
queries.push({ indexName: index, params: params });
});
}
});
return queries;
},
/**
* Build search parameters used to fetch hits
* @private
* @param {SearchParameters} state The state from which to get the queries
* @return {object.<string, any>} The search parameters for hits
*/
_getHitsSearchParams: function (state) {
var facets = state.facets
.concat(state.disjunctiveFacets)
.concat(requestBuilder._getHitsHierarchicalFacetsAttributes(state))
.sort();
var facetFilters = requestBuilder._getFacetFilters(state);
var numericFilters = requestBuilder._getNumericFilters(state);
var tagFilters = requestBuilder._getTagFilters(state);
var additionalParams = {
facets: facets.indexOf('*') > -1 ? ['*'] : facets,
tagFilters: tagFilters,
};
if (facetFilters.length > 0) {
additionalParams.facetFilters = facetFilters;
}
if (numericFilters.length > 0) {
additionalParams.numericFilters = numericFilters;
}
return sortObject(merge({}, state.getQueryParams(), additionalParams));
},
/**
* Build search parameters used to fetch a disjunctive facet
* @private
* @param {SearchParameters} state The state from which to get the queries
* @param {string} facet the associated facet name
* @param {boolean} hierarchicalRootLevel ?? FIXME
* @return {object} The search parameters for a disjunctive facet
*/
_getDisjunctiveFacetSearchParams: function (
state,
facet,
hierarchicalRootLevel
) {
var facetFilters = requestBuilder._getFacetFilters(
state,
facet,
hierarchicalRootLevel
);
var numericFilters = requestBuilder._getNumericFilters(state, facet);
var tagFilters = requestBuilder._getTagFilters(state);
var additionalParams = {
hitsPerPage: 0,
page: 0,
analytics: false,
clickAnalytics: false,
};
if (tagFilters.length > 0) {
additionalParams.tagFilters = tagFilters;
}
var hierarchicalFacet = state.getHierarchicalFacetByName(facet);
if (hierarchicalFacet) {
additionalParams.facets =
requestBuilder._getDisjunctiveHierarchicalFacetAttribute(
state,
hierarchicalFacet,
hierarchicalRootLevel
);
} else {
additionalParams.facets = facet;
}
if (numericFilters.length > 0) {
additionalParams.numericFilters = numericFilters;
}
if (facetFilters.length > 0) {
additionalParams.facetFilters = facetFilters;
}
return sortObject(merge({}, state.getQueryParams(), additionalParams));
},
/**
* Return the numeric filters in an algolia request fashion
* @private
* @param {SearchParameters} state the state from which to get the filters
* @param {string} [facetName] the name of the attribute for which the filters should be excluded
* @return {string[]} the numeric filters in the algolia format
*/
_getNumericFilters: function (state, facetName) {
if (state.numericFilters) {
return state.numericFilters;
}
var numericFilters = [];
Object.keys(state.numericRefinements).forEach(function (attribute) {
var operators = state.numericRefinements[attribute] || {};
Object.keys(operators).forEach(function (operator) {
var values = operators[operator] || [];
if (facetName !== attribute) {
values.forEach(function (value) {
if (Array.isArray(value)) {
var vs = value.map(function (v) {
return attribute + operator + v;
});
numericFilters.push(vs);
} else {
numericFilters.push(attribute + operator + value);
}
});
}
});
});
return numericFilters;
},
/**
* Return the tags filters depending on which format is used, either tagFilters or tagRefinements
* @private
* @param {SearchParameters} state the state from which to get the filters
* @return {string} Tag filters in a single string
*/
_getTagFilters: function (state) {
if (state.tagFilters) {
return state.tagFilters;
}
return state.tagRefinements.join(',');
},
/**
* Build facetFilters parameter based on current refinements. The array returned
* contains strings representing the facet filters in the algolia format.
* @private
* @param {SearchParameters} state The state from which to get the queries
* @param {string} [facet] if set, the current disjunctive facet
* @param {boolean} [hierarchicalRootLevel] ?? FIXME
* @return {array.<string>} The facet filters in the algolia format
*/
_getFacetFilters: function (state, facet, hierarchicalRootLevel) {
var facetFilters = [];
var facetsRefinements = state.facetsRefinements || {};
Object.keys(facetsRefinements)
.sort()
.forEach(function (facetName) {
var facetValues = facetsRefinements[facetName] || [];
facetValues.sort().forEach(function (facetValue) {
facetFilters.push(facetName + ':' + facetValue);
});
});
var facetsExcludes = state.facetsExcludes || {};
Object.keys(facetsExcludes)
.sort()
.forEach(function (facetName) {
var facetValues = facetsExcludes[facetName] || [];
facetValues.sort().forEach(function (facetValue) {
facetFilters.push(facetName + ':-' + facetValue);
});
});
var disjunctiveFacetsRefinements = state.disjunctiveFacetsRefinements || {};
Object.keys(disjunctiveFacetsRefinements)
.sort()
.forEach(function (facetName) {
var facetValues = disjunctiveFacetsRefinements[facetName] || [];
if (facetName === facet || !facetValues || facetValues.length === 0) {
return;
}
var orFilters = [];
facetValues.sort().forEach(function (facetValue) {
orFilters.push(facetName + ':' + facetValue);
});
facetFilters.push(orFilters);
});
var hierarchicalFacetsRefinements =
state.hierarchicalFacetsRefinements || {};
Object.keys(hierarchicalFacetsRefinements)
.sort()
.forEach(function (facetName) {
var facetValues = hierarchicalFacetsRefinements[facetName] || [];
var facetValue = facetValues[0];
if (facetValue === undefined) {
return;
}
var hierarchicalFacet = state.getHierarchicalFacetByName(facetName);
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
var rootPath = state._getHierarchicalRootPath(hierarchicalFacet);
var attributeToRefine;
var attributesIndex;
// we ask for parent facet values only when the `facet` is the current hierarchical facet
if (facet === facetName) {
// if we are at the root level already, no need to ask for facet values, we get them from
// the hits query
if (
facetValue.indexOf(separator) === -1 ||
(!rootPath && hierarchicalRootLevel === true) ||
(rootPath &&
rootPath.split(separator).length ===
facetValue.split(separator).length)
) {
return;
}
if (!rootPath) {
attributesIndex = facetValue.split(separator).length - 2;
facetValue = facetValue.slice(0, facetValue.lastIndexOf(separator));
} else {
attributesIndex = rootPath.split(separator).length - 1;
facetValue = rootPath;
}
attributeToRefine = hierarchicalFacet.attributes[attributesIndex];
} else {
attributesIndex = facetValue.split(separator).length - 1;
attributeToRefine = hierarchicalFacet.attributes[attributesIndex];
}
if (attributeToRefine) {
facetFilters.push([attributeToRefine + ':' + facetValue]);
}
});
return facetFilters;
},
_getHitsHierarchicalFacetsAttributes: function (state) {
var out = [];
return state.hierarchicalFacets.reduce(
// ask for as much levels as there's hierarchical refinements
function getHitsAttributesForHierarchicalFacet(
allAttributes,
hierarchicalFacet
) {
var hierarchicalRefinement = state.getHierarchicalRefinement(
hierarchicalFacet.name
)[0];
// if no refinement, ask for root level
if (!hierarchicalRefinement) {
allAttributes.push(hierarchicalFacet.attributes[0]);
return allAttributes;
}
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
var level = hierarchicalRefinement.split(separator).length;
var newAttributes = hierarchicalFacet.attributes.slice(0, level + 1);
return allAttributes.concat(newAttributes);
},
out
);
},
_getDisjunctiveHierarchicalFacetAttribute: function (
state,
hierarchicalFacet,
rootLevel
) {
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
if (rootLevel === true) {
var rootPath = state._getHierarchicalRootPath(hierarchicalFacet);
var attributeIndex = 0;
if (rootPath) {
attributeIndex = rootPath.split(separator).length;
}
return [hierarchicalFacet.attributes[attributeIndex]];
}
var hierarchicalRefinement =
state.getHierarchicalRefinement(hierarchicalFacet.name)[0] || '';
// if refinement is 'beers > IPA > Flying dog',
// then we want `facets: ['beers > IPA']` as disjunctive facet (parent level values)
var parentLevel = hierarchicalRefinement.split(separator).length - 1;
return hierarchicalFacet.attributes.slice(0, parentLevel + 1);
},
getSearchForFacetQuery: function (facetName, query, maxFacetHits, state) {
var stateForSearchForFacetValues = state.isDisjunctiveFacet(facetName)
? state.clearRefinements(facetName)
: state;
var searchForFacetSearchParameters = {
facetQuery: query,
facetName: facetName,
};
if (typeof maxFacetHits === 'number') {
searchForFacetSearchParameters.maxFacetHits = maxFacetHits;
}
return sortObject(
merge(
{},
requestBuilder._getHitsSearchParams(stateForSearchForFacetValues),
searchForFacetSearchParameters
)
);
},
};
module.exports = requestBuilder;
/***/ }),
/***/ 46801:
/***/ ((module) => {
"use strict";
module.exports = function isValidUserToken(userToken) {
if (userToken === null) {
return false;
}
return /^[a-zA-Z0-9_-]{1,64}$/.test(userToken);
};
/***/ }),
/***/ 24336:
/***/ ((module) => {
"use strict";
module.exports = '3.14.2';
/***/ }),
/***/ 70290:
/***/ (function(module) {
/*! algoliasearch-lite.umd.js | 4.20.0 | © Algolia, inc. | https://github.com/algolia/algoliasearch-client-javascript */
!function(e,t){ true?module.exports=t():0}(this,(function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function r(r){for(var n=1;n<arguments.length;n++){var o=null!=arguments[n]?arguments[n]:{};n%2?t(Object(o),!0).forEach((function(t){e(r,t,o[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(o)):t(Object(o)).forEach((function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(o,e))}))}return r}function n(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function o(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(!(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)))return;var r=[],n=!0,o=!1,a=void 0;try{for(var u,i=e[Symbol.iterator]();!(n=(u=i.next()).done)&&(r.push(u.value),!t||r.length!==t);n=!0);}catch(e){o=!0,a=e}finally{try{n||null==i.return||i.return()}finally{if(o)throw a}}return r}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function a(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t<e.length;t++)r[t]=e[t];return r}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function u(e){var t,r="algoliasearch-client-js-".concat(e.key),n=function(){return void 0===t&&(t=e.localStorage||window.localStorage),t},a=function(){return JSON.parse(n().getItem(r)||"{}")},u=function(e){n().setItem(r,JSON.stringify(e))},i=function(){var t=e.timeToLive?1e3*e.timeToLive:null,r=a(),n=Object.fromEntries(Object.entries(r).filter((function(e){return void 0!==o(e,2)[1].timestamp})));if(u(n),t){var i=Object.fromEntries(Object.entries(n).filter((function(e){var r=o(e,2)[1],n=(new Date).getTime();return!(r.timestamp+t<n)})));u(i)}};return{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){i();var t=JSON.stringify(e);return a()[t]})).then((function(e){return Promise.all([e?e.value:t(),void 0!==e])})).then((function(e){var t=o(e,2),n=t[0],a=t[1];return Promise.all([n,a||r.miss(n)])})).then((function(e){return o(e,1)[0]}))},set:function(e,t){return Promise.resolve().then((function(){var o=a();return o[JSON.stringify(e)]={timestamp:(new Date).getTime(),value:t},n().setItem(r,JSON.stringify(o)),t}))},delete:function(e){return Promise.resolve().then((function(){var t=a();delete t[JSON.stringify(e)],n().setItem(r,JSON.stringify(t))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function i(e){var t=a(e.caches),r=t.shift();return void 0===r?{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},n=t();return n.then((function(e){return Promise.all([e,r.miss(e)])})).then((function(e){return o(e,1)[0]}))},set:function(e,t){return Promise.resolve(t)},delete:function(e){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(e,n){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(e,n,o).catch((function(){return i({caches:t}).get(e,n,o)}))},set:function(e,n){return r.set(e,n).catch((function(){return i({caches:t}).set(e,n)}))},delete:function(e){return r.delete(e).catch((function(){return i({caches:t}).delete(e)}))},clear:function(){return r.clear().catch((function(){return i({caches:t}).clear()}))}}}function s(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},t={};return{get:function(r,n){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);var u=n(),i=o&&o.miss||function(){return Promise.resolve()};return u.then((function(e){return i(e)})).then((function(){return u}))},set:function(r,n){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(e){return delete t[JSON.stringify(e)],Promise.resolve()},clear:function(){return t={},Promise.resolve()}}}function c(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function l(e,t){return t?(Object.keys(t).forEach((function(r){e[r]=t[r](e)})),e):e}function f(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n<t;n++)r[n-1]=arguments[n];var o=0;return e.replace(/%s/g,(function(){return encodeURIComponent(r[o++])}))}var m={WithinQueryParameters:0,WithinHeaders:1};function h(e,t){var r=e||{},n=r.data||{};return Object.keys(r).forEach((function(e){-1===["timeout","headers","queryParameters","data","cacheable"].indexOf(e)&&(n[e]=r[e])})),{data:Object.entries(n).length>0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var d={Read:1,Write:2,Any:3},p=1,v=2,g=3;function y(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:p;return r(r({},e),{},{status:t,lastUpdate:Date.now()})}function b(e){return"string"==typeof e?{protocol:"https",url:e,accept:d.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||d.Any}}var O="GET",P="POST";function q(e,t){return Promise.all(t.map((function(t){return e.get(t,(function(){return Promise.resolve(y(t))}))}))).then((function(e){var r=e.filter((function(e){return function(e){return e.status===p||Date.now()-e.lastUpdate>12e4}(e)})),n=e.filter((function(e){return function(e){return e.status===g&&Date.now()-e.lastUpdate<=12e4}(e)})),o=[].concat(a(r),a(n));return{getTimeout:function(e,t){return(0===n.length&&0===e?1:n.length+3+e)*t},statelessHosts:o.length>0?o.map((function(e){return b(e)})):t}}))}function j(e,t,n,o){var u=[],i=function(e,t){if(e.method===O||void 0===e.data&&void 0===t.data)return;var n=Array.isArray(e.data)?e.data:r(r({},e.data),t.data);return JSON.stringify(n)}(n,o),s=function(e,t){var n=r(r({},e.headers),t.headers),o={};return Object.keys(n).forEach((function(e){var t=n[e];o[e.toLowerCase()]=t})),o}(e,o),c=n.method,l=n.method!==O?{}:r(r({},n.data),o.data),f=r(r(r({"x-algolia-agent":e.userAgent.value},e.queryParameters),l),o.queryParameters),m=0,h=function t(r,a){var l=r.pop();if(void 0===l)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:A(u)};var h={data:i,headers:s,method:c,url:S(l,n.path,f),connectTimeout:a(m,e.timeouts.connect),responseTimeout:a(m,o.timeout)},d=function(e){var t={request:h,response:e,host:l,triesLeft:r.length};return u.push(t),t},p={onSuccess:function(e){return function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e)},onRetry:function(n){var o=d(n);return n.isTimedOut&&m++,Promise.all([e.logger.info("Retryable failure",N(o)),e.hostsCache.set(l,y(l,n.isTimedOut?g:v))]).then((function(){return t(r,a)}))},onFail:function(e){throw d(e),function(e,t){var r=e.content,n=e.status,o=r;try{o=JSON.parse(r).message}catch(e){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(o,n,t)}(e,A(u))}};return e.requester.send(h).then((function(e){return function(e,t){return function(e){var t=e.status;return e.isTimedOut||function(e){var t=e.isTimedOut,r=e.status;return!t&&0==~~r}(e)||2!=~~(t/100)&&4!=~~(t/100)}(e)?t.onRetry(e):2==~~(e.status/100)?t.onSuccess(e):t.onFail(e)}(e,p)}))};return q(e.hostsCache,t).then((function(e){return h(a(e.statelessHosts).reverse(),e.getTimeout)}))}function w(e){var t={value:"Algolia for JavaScript (".concat(e,")"),add:function(e){var r="; ".concat(e.segment).concat(void 0!==e.version?" (".concat(e.version,")"):"");return-1===t.value.indexOf(r)&&(t.value="".concat(t.value).concat(r)),t}};return t}function S(e,t,r){var n=T(r),o="".concat(e.protocol,"://").concat(e.url,"/").concat("/"===t.charAt(0)?t.substr(1):t);return n.length&&(o+="?".concat(n)),o}function T(e){return Object.keys(e).map((function(t){return f("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function A(e){return e.map((function(e){return N(e)}))}function N(e){var t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r(r({},e),{},{request:r(r({},e.request),{},{headers:r(r({},e.request.headers),t)})})}var x=function(e){var t=e.appId,n=function(e,t,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:function(){return e===m.WithinHeaders?n:{}},queryParameters:function(){return e===m.WithinQueryParameters?n:{}}}}(void 0!==e.authMode?e.authMode:m.WithinHeaders,t,e.apiKey),a=function(e){var t=e.hostsCache,r=e.logger,n=e.requester,a=e.requestsCache,u=e.responsesCache,i=e.timeouts,s=e.userAgent,c=e.hosts,l=e.queryParameters,f={hostsCache:t,logger:r,requester:n,requestsCache:a,responsesCache:u,timeouts:i,userAgent:s,headers:e.headers,queryParameters:l,hosts:c.map((function(e){return b(e)})),read:function(e,t){var r=h(t,f.timeouts.read),n=function(){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Read)})),e,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();var a={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(a,(function(){return f.requestsCache.get(a,(function(){return f.requestsCache.set(a,n()).then((function(e){return Promise.all([f.requestsCache.delete(a),e])}),(function(e){return Promise.all([f.requestsCache.delete(a),Promise.reject(e)])})).then((function(e){var t=o(e,2);t[0];return t[1]}))}))}),{miss:function(e){return f.responsesCache.set(a,e)}})},write:function(e,t){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Write)})),e,h(t,f.timeouts.write))}};return f}(r(r({hosts:[{url:"".concat(t,"-dsn.algolia.net"),accept:d.Read},{url:"".concat(t,".algolia.net"),accept:d.Write}].concat(c([{url:"".concat(t,"-1.algolianet.com")},{url:"".concat(t,"-2.algolianet.com")},{url:"".concat(t,"-3.algolianet.com")}]))},e),{},{headers:r(r(r({},n.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:r(r({},n.queryParameters()),e.queryParameters)}));return l({transporter:a,appId:t,addAlgoliaAgent:function(e,t){a.userAgent.add({segment:e,version:t})},clearCache:function(){return Promise.all([a.requestsCache.clear(),a.responsesCache.clear()]).then((function(){}))}},e.methods)},C=function(e){return function(t,r){return t.method===O?e.transporter.read(t,r):e.transporter.write(t,r)}},E=function(e){return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n={transporter:e.transporter,appId:e.appId,indexName:t};return l(n,r.methods)}},J=function(e){return function(t,n){var o=t.map((function(e){return r(r({},e),{},{params:T(e.params||{})})}));return e.transporter.read({method:P,path:"1/indexes/*/queries",data:{requests:o},cacheable:!0},n)}},k=function(e){return function(t,o){return Promise.all(t.map((function(t){var a=t.params,u=a.facetName,i=a.facetQuery,s=n(a,["facetName","facetQuery"]);return E(e)(t.indexName,{methods:{searchForFacetValues:R}}).searchForFacetValues(u,i,r(r({},o),s))})))}},I=function(e){return function(t,r,n){return e.transporter.read({method:P,path:f("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n)}},F=function(e){return function(t,r){return e.transporter.read({method:P,path:f("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r)}},R=function(e){return function(t,r,n){return e.transporter.read({method:P,path:f("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n)}},D=1,W=2,H=3;function Q(e,t,n){var o,a={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:function(e){return new Promise((function(t){var r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((function(t){return r.setRequestHeader(t,e.headers[t])}));var n,o=function(e,n){return setTimeout((function(){r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e)},a=o(e.connectTimeout,"Connection timeout");r.onreadystatechange=function(){r.readyState>r.OPENED&&void 0===n&&(clearTimeout(a),n=o(e.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(a),clearTimeout(n),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(a),clearTimeout(n),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))}},logger:(o=H,{debug:function(e,t){return D>=o&&console.debug(e,t),Promise.resolve()},info:function(e,t){return W>=o&&console.info(e,t),Promise.resolve()},error:function(e,t){return console.error(e,t),Promise.resolve()}}),responsesCache:s(),requestsCache:s({serializable:!1}),hostsCache:i({caches:[u({key:"".concat("4.20.0","-").concat(e)}),s()]}),userAgent:w("4.20.0").add({segment:"Browser",version:"lite"}),authMode:m.WithinQueryParameters};return x(r(r(r({},a),n),{},{methods:{search:J,searchForFacetValues:k,multipleQueries:J,multipleSearchForFacetValues:k,customRequest:C,initIndex:function(e){return function(t){return E(e)(t,{methods:{search:F,searchForFacetValues:R,findAnswers:I}})}}}}))}return Q.version="4.20.0",Q}));
/***/ }),
/***/ 40304:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
"default": () => (/* binding */ SearchPage)
});
// EXTERNAL MODULE: ./node_modules/react/index.js
var react = __webpack_require__(67294);
// EXTERNAL MODULE: ./node_modules/clsx/dist/clsx.m.js
var clsx_m = __webpack_require__(86010);
// EXTERNAL MODULE: ./node_modules/algoliasearch-helper/index.js
var algoliasearch_helper = __webpack_require__(8131);
var algoliasearch_helper_default = /*#__PURE__*/__webpack_require__.n(algoliasearch_helper);
// EXTERNAL MODULE: ./node_modules/algoliasearch/dist/algoliasearch-lite.umd.js
var algoliasearch_lite_umd = __webpack_require__(70290);
var algoliasearch_lite_umd_default = /*#__PURE__*/__webpack_require__.n(algoliasearch_lite_umd);
// EXTERNAL MODULE: ./node_modules/@docusaurus/core/lib/client/exports/ExecutionEnvironment.js
var ExecutionEnvironment = __webpack_require__(58087);
// EXTERNAL MODULE: ./node_modules/@docusaurus/core/lib/client/exports/Head.js
var Head = __webpack_require__(71098);
// EXTERNAL MODULE: ./node_modules/@docusaurus/core/lib/client/exports/Link.js + 1 modules
var Link = __webpack_require__(31984);
// EXTERNAL MODULE: ./node_modules/@docusaurus/plugin-content-docs/lib/client/index.js + 1 modules
var client = __webpack_require__(88249);
// EXTERNAL MODULE: ./node_modules/@docusaurus/core/lib/client/exports/useDocusaurusContext.js
var useDocusaurusContext = __webpack_require__(8241);
;// CONCATENATED MODULE: ./node_modules/@docusaurus/theme-common/lib/utils/usePluralForm.js
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// We want to ensurer a stable plural form order in all cases
// It is more convenient and natural to handle "small values" first
// See https://twitter.com/sebastienlorber/status/1366820663261077510
const OrderedPluralForms = [
'zero',
'one',
'two',
'few',
'many',
'other'
];
function sortPluralForms(pluralForms) {
return OrderedPluralForms.filter((pf)=>pluralForms.includes(pf));
}
// Hardcoded english/fallback implementation
const EnglishPluralForms = {
locale: 'en',
pluralForms: sortPluralForms([
'one',
'other'
]),
select: (count)=>count === 1 ? 'one' : 'other'
};
function createLocalePluralForms(locale) {
const pluralRules = new Intl.PluralRules(locale);
return {
locale,
pluralForms: sortPluralForms(pluralRules.resolvedOptions().pluralCategories),
select: (count)=>pluralRules.select(count)
};
}
/**
* Poor man's `PluralSelector` implementation, using an English fallback. We
* want a lightweight, future-proof and good-enough solution. We don't want a
* perfect and heavy solution.
*
* Docusaurus classic theme has only 2 deeply nested labels requiring complex
* plural rules. We don't want to use `Intl` + `PluralRules` polyfills + full
* ICU syntax (react-intl) just for that.
*
* Notes:
* - 2021: 92+% Browsers support `Intl.PluralRules`, and support will increase
* in the future
* - NodeJS >= 13 has full ICU support by default
* - In case of "mismatch" between SSR and Browser ICU support, React keeps
* working!
*/ function useLocalePluralForms() {
const { i18n: { currentLocale } } = (0,useDocusaurusContext/* default */.Z)();
return (0,react.useMemo)(()=>{
try {
return createLocalePluralForms(currentLocale);
} catch (err) {
console.error(`Failed to use Intl.PluralRules for locale "${currentLocale}".
Docusaurus will fallback to the default (English) implementation.
Error: ${err.message}
`);
return EnglishPluralForms;
}
}, [
currentLocale
]);
}
function selectPluralMessage(pluralMessages, count, localePluralForms) {
const separator = '|';
const parts = pluralMessages.split(separator);
if (parts.length === 1) {
return parts[0];
}
if (parts.length > localePluralForms.pluralForms.length) {
console.error(`For locale=${localePluralForms.locale}, a maximum of ${localePluralForms.pluralForms.length} plural forms are expected (${localePluralForms.pluralForms.join(',')}), but the message contains ${parts.length}: ${pluralMessages}`);
}
const pluralForm = localePluralForms.select(count);
const pluralFormIndex = localePluralForms.pluralForms.indexOf(pluralForm);
// In case of not enough plural form messages, we take the last one (other)
// instead of returning undefined
return parts[Math.min(pluralFormIndex, parts.length - 1)];
}
/**
* Reads the current locale and returns an interface very similar to
* `Intl.PluralRules`.
*/ function usePluralForm() {
const localePluralForm = useLocalePluralForms();
return {
selectMessage: (count, pluralMessages)=>selectPluralMessage(pluralMessages, count, localePluralForm)
};
} //# sourceMappingURL=usePluralForm.js.map
// EXTERNAL MODULE: ./node_modules/@docusaurus/theme-common/lib/hooks/useSearchPage.js
var useSearchPage = __webpack_require__(80958);
// EXTERNAL MODULE: ./node_modules/@docusaurus/theme-common/lib/utils/reactUtils.js
var reactUtils = __webpack_require__(37806);
// EXTERNAL MODULE: ./node_modules/@docusaurus/theme-common/lib/utils/metadataUtils.js + 1 modules
var metadataUtils = __webpack_require__(89712);
// EXTERNAL MODULE: ./node_modules/@docusaurus/theme-common/lib/utils/generalUtils.js
var generalUtils = __webpack_require__(54995);
// EXTERNAL MODULE: ./node_modules/@docusaurus/core/lib/client/exports/Translate.js + 1 modules
var Translate = __webpack_require__(92210);
// EXTERNAL MODULE: ./node_modules/@docusaurus/theme-search-algolia/lib/client/useAlgoliaThemeConfig.js
var useAlgoliaThemeConfig = __webpack_require__(49704);
// EXTERNAL MODULE: ./node_modules/@docusaurus/theme-search-algolia/lib/client/useSearchResultUrlProcessor.js
var useSearchResultUrlProcessor = __webpack_require__(30888);
// EXTERNAL MODULE: ./node_modules/@docusaurus/theme-classic/lib/theme/Layout/index.js + 71 modules
var Layout = __webpack_require__(33737);
;// CONCATENATED MODULE: ./node_modules/@docusaurus/theme-search-algolia/lib/theme/SearchPage/styles.module.css
// extracted by mini-css-extract-plugin
/* harmony default export */ const styles_module = ({"searchQueryInput":"searchQueryInput_u2C7","searchVersionInput":"searchVersionInput_m0Ui","searchResultsColumn":"searchResultsColumn_JPFH","algoliaLogo":"algoliaLogo_rT1R","algoliaLogoPathFill":"algoliaLogoPathFill_WdUC","searchResultItem":"searchResultItem_Tv2o","searchResultItemHeading":"searchResultItemHeading_KbCB","searchResultItemPath":"searchResultItemPath_lhe1","searchResultItemSummary":"searchResultItemSummary_AEaO","searchQueryColumn":"searchQueryColumn_RTkw","searchVersionColumn":"searchVersionColumn_ypXd","searchLogoColumn":"searchLogoColumn_rJIA","loadingSpinner":"loadingSpinner_XVxU","loading-spin":"loading-spin_vzvp","loader":"loader_vvXV"});
;// CONCATENATED MODULE: ./node_modules/@docusaurus/theme-search-algolia/lib/theme/SearchPage/index.js
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/ /* eslint-disable jsx-a11y/no-autofocus */ function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _object_spread(target) {
for(var i = 1; i < arguments.length; i++){
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_define_property(target, key, source[key]);
});
}
return target;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) {
symbols = symbols.filter(function(sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
}
keys.push.apply(keys, symbols);
}
return keys;
}
function _object_spread_props(target, source) {
source = source != null ? source : {};
if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function(key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
return target;
}
// Very simple pluralization: probably good enough for now
function useDocumentsFoundPlural() {
const { selectMessage } = usePluralForm();
return (count)=>selectMessage(count, (0,Translate/* translate */.I)({
id: 'theme.SearchPage.documentsFound.plurals',
description: 'Pluralized label for "{count} documents found". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',
message: 'One document found|{count} documents found'
}, {
count
}));
}
function useDocsSearchVersionsHelpers() {
const allDocsData = (0,client/* useAllDocsData */._r)();
// State of the version select menus / algolia facet filters
// docsPluginId -> versionName map
const [searchVersions, setSearchVersions] = (0,react.useState)(()=>Object.entries(allDocsData).reduce((acc, [pluginId, pluginData])=>_object_spread_props(_object_spread({}, acc), {
[pluginId]: pluginData.versions[0].name
}), {}));
// Set the value of a single select menu
const setSearchVersion = (pluginId, searchVersion)=>setSearchVersions((s)=>_object_spread_props(_object_spread({}, s), {
[pluginId]: searchVersion
}));
const versioningEnabled = Object.values(allDocsData).some((docsData)=>docsData.versions.length > 1);
return {
allDocsData,
versioningEnabled,
searchVersions,
setSearchVersion
};
}
// We want to display one select per versioned docs plugin instance
function SearchVersionSelectList({ docsSearchVersionsHelpers }) {
const versionedPluginEntries = Object.entries(docsSearchVersionsHelpers.allDocsData)// Do not show a version select for unversioned docs plugin instances
.filter(([, docsData])=>docsData.versions.length > 1);
return /*#__PURE__*/ react.createElement("div", {
className: (0,clsx_m/* default */.Z)('col', 'col--3', 'padding-left--none', styles_module.searchVersionColumn)
}, versionedPluginEntries.map(([pluginId, docsData])=>{
const labelPrefix = versionedPluginEntries.length > 1 ? `${pluginId}: ` : '';
return /*#__PURE__*/ react.createElement("select", {
key: pluginId,
onChange: (e)=>docsSearchVersionsHelpers.setSearchVersion(pluginId, e.target.value),
defaultValue: docsSearchVersionsHelpers.searchVersions[pluginId],
className: styles_module.searchVersionInput
}, docsData.versions.map((version, i)=>/*#__PURE__*/ react.createElement("option", {
key: i,
label: `${labelPrefix}${version.label}`,
value: version.name
})));
}));
}
function SearchPageContent() {
const { i18n: { currentLocale } } = (0,useDocusaurusContext/* default */.Z)();
const { algolia: { appId, apiKey, indexName } } = (0,useAlgoliaThemeConfig/* useAlgoliaThemeConfig */.L)();
const processSearchResultUrl = (0,useSearchResultUrlProcessor/* useSearchResultUrlProcessor */.l)();
const documentsFoundPlural = useDocumentsFoundPlural();
const docsSearchVersionsHelpers = useDocsSearchVersionsHelpers();
const [searchQuery, setSearchQuery] = (0,useSearchPage/* useSearchQueryString */.K)();
const initialSearchResultState = {
items: [],
query: null,
totalResults: null,
totalPages: null,
lastPage: null,
hasMore: null,
loading: null
};
const [searchResultState, searchResultStateDispatcher] = (0,react.useReducer)((prevState, data)=>{
switch(data.type){
case 'reset':
{
return initialSearchResultState;
}
case 'loading':
{
return _object_spread_props(_object_spread({}, prevState), {
loading: true
});
}
case 'update':
{
if (searchQuery !== data.value.query) {
return prevState;
}
return _object_spread_props(_object_spread({}, data.value), {
items: data.value.lastPage === 0 ? data.value.items : prevState.items.concat(data.value.items)
});
}
case 'advance':
{
const hasMore = prevState.totalPages > prevState.lastPage + 1;
return _object_spread_props(_object_spread({}, prevState), {
lastPage: hasMore ? prevState.lastPage + 1 : prevState.lastPage,
hasMore
});
}
default:
return prevState;
}
}, initialSearchResultState);
const algoliaClient = algoliasearch_lite_umd_default()(appId, apiKey);
const algoliaHelper = algoliasearch_helper_default()(algoliaClient, indexName, {
hitsPerPage: 15,
advancedSyntax: true,
disjunctiveFacets: [
'language',
'docusaurus_tag'
]
});
algoliaHelper.on('result', ({ results: { query, hits, page, nbHits, nbPages } })=>{
if (query === '' || !Array.isArray(hits)) {
searchResultStateDispatcher({
type: 'reset'
});
return;
}
const sanitizeValue = (value)=>value.replace(/algolia-docsearch-suggestion--highlight/g, 'search-result-match');
const items = hits.map(({ url, _highlightResult: { hierarchy }, _snippetResult: snippet = {} })=>{
const titles = Object.keys(hierarchy).map((key)=>sanitizeValue(hierarchy[key].value));
return {
title: titles.pop(),
url: processSearchResultUrl(url),
summary: snippet.content ? `${sanitizeValue(snippet.content.value)}...` : '',
breadcrumbs: titles
};
});
searchResultStateDispatcher({
type: 'update',
value: {
items,
query,
totalResults: nbHits,
totalPages: nbPages,
lastPage: page,
hasMore: nbPages > page + 1,
loading: false
}
});
});
const [loaderRef, setLoaderRef] = (0,react.useState)(null);
const prevY = (0,react.useRef)(0);
const observer = (0,react.useRef)(ExecutionEnvironment["default"].canUseIntersectionObserver && new IntersectionObserver((entries)=>{
const { isIntersecting, boundingClientRect: { y: currentY } } = entries[0];
if (isIntersecting && prevY.current > currentY) {
searchResultStateDispatcher({
type: 'advance'
});
}
prevY.current = currentY;
}, {
threshold: 1
}));
const getTitle = ()=>searchQuery ? (0,Translate/* translate */.I)({
id: 'theme.SearchPage.existingResultsTitle',
message: 'Search results for "{query}"',
description: 'The search page title for non-empty query'
}, {
query: searchQuery
}) : (0,Translate/* translate */.I)({
id: 'theme.SearchPage.emptyResultsTitle',
message: 'Search the documentation',
description: 'The search page title for empty query'
});
const makeSearch = (0,reactUtils/* useEvent */.zX)((page = 0)=>{
algoliaHelper.addDisjunctiveFacetRefinement('docusaurus_tag', 'default');
algoliaHelper.addDisjunctiveFacetRefinement('language', currentLocale);
Object.entries(docsSearchVersionsHelpers.searchVersions).forEach(([pluginId, searchVersion])=>{
algoliaHelper.addDisjunctiveFacetRefinement('docusaurus_tag', `docs-${pluginId}-${searchVersion}`);
});
algoliaHelper.setQuery(searchQuery).setPage(page).search();
});
(0,react.useEffect)(()=>{
if (!loaderRef) {
return undefined;
}
const currentObserver = observer.current;
if (currentObserver) {
currentObserver.observe(loaderRef);
return ()=>currentObserver.unobserve(loaderRef);
}
return ()=>true;
}, [
loaderRef
]);
(0,react.useEffect)(()=>{
searchResultStateDispatcher({
type: 'reset'
});
if (searchQuery) {
searchResultStateDispatcher({
type: 'loading'
});
setTimeout(()=>{
makeSearch();
}, 300);
}
}, [
searchQuery,
docsSearchVersionsHelpers.searchVersions,
makeSearch
]);
(0,react.useEffect)(()=>{
if (!searchResultState.lastPage || searchResultState.lastPage === 0) {
return;
}
makeSearch(searchResultState.lastPage);
}, [
makeSearch,
searchResultState.lastPage
]);
return /*#__PURE__*/ react.createElement(Layout/* default */.Z, null, /*#__PURE__*/ react.createElement(Head/* default */.Z, null, /*#__PURE__*/ react.createElement("title", null, (0,generalUtils/* useTitleFormatter */.p)(getTitle())), /*#__PURE__*/ react.createElement("meta", {
property: "robots",
content: "noindex, follow"
})), /*#__PURE__*/ react.createElement("div", {
className: "container margin-vert--lg"
}, /*#__PURE__*/ react.createElement("h1", null, getTitle()), /*#__PURE__*/ react.createElement("form", {
className: "row",
onSubmit: (e)=>e.preventDefault()
}, /*#__PURE__*/ react.createElement("div", {
className: (0,clsx_m/* default */.Z)('col', styles_module.searchQueryColumn, {
'col--9': docsSearchVersionsHelpers.versioningEnabled,
'col--12': !docsSearchVersionsHelpers.versioningEnabled
})
}, /*#__PURE__*/ react.createElement("input", {
type: "search",
name: "q",
className: styles_module.searchQueryInput,
placeholder: (0,Translate/* translate */.I)({
id: 'theme.SearchPage.inputPlaceholder',
message: 'Type your search here',
description: 'The placeholder for search page input'
}),
"aria-label": (0,Translate/* translate */.I)({
id: 'theme.SearchPage.inputLabel',
message: 'Search',
description: 'The ARIA label for search page input'
}),
onChange: (e)=>setSearchQuery(e.target.value),
value: searchQuery,
autoComplete: "off",
autoFocus: true
})), docsSearchVersionsHelpers.versioningEnabled && /*#__PURE__*/ react.createElement(SearchVersionSelectList, {
docsSearchVersionsHelpers: docsSearchVersionsHelpers
})), /*#__PURE__*/ react.createElement("div", {
className: "row"
}, /*#__PURE__*/ react.createElement("div", {
className: (0,clsx_m/* default */.Z)('col', 'col--8', styles_module.searchResultsColumn)
}, !!searchResultState.totalResults && documentsFoundPlural(searchResultState.totalResults)), /*#__PURE__*/ react.createElement("div", {
className: (0,clsx_m/* default */.Z)('col', 'col--4', 'text--right', styles_module.searchLogoColumn)
}, /*#__PURE__*/ react.createElement("a", {
target: "_blank",
rel: "noopener noreferrer",
href: "https://www.algolia.com/",
"aria-label": (0,Translate/* translate */.I)({
id: 'theme.SearchPage.algoliaLabel',
message: 'Search by Algolia',
description: 'The ARIA label for Algolia mention'
})
}, /*#__PURE__*/ react.createElement("svg", {
viewBox: "0 0 168 24",
className: styles_module.algoliaLogo
}, /*#__PURE__*/ react.createElement("g", {
fill: "none"
}, /*#__PURE__*/ react.createElement("path", {
className: styles_module.algoliaLogoPathFill,
d: "M120.925 18.804c-4.386.02-4.386-3.54-4.386-4.106l-.007-13.336 2.675-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-10.846-2.18c.821 0 1.43-.047 1.855-.129v-2.719a6.334 6.334 0 0 0-1.574-.199 5.7 5.7 0 0 0-.897.069 2.699 2.699 0 0 0-.814.24c-.24.116-.439.28-.582.491-.15.212-.219.335-.219.656 0 .628.219.991.616 1.23s.938.362 1.615.362zm-.233-9.7c.883 0 1.629.109 2.231.328.602.218 1.088.525 1.444.915.363.396.609.922.76 1.483.157.56.232 1.175.232 1.85v6.874a32.5 32.5 0 0 1-1.868.314c-.834.123-1.772.185-2.813.185-.69 0-1.327-.069-1.895-.198a4.001 4.001 0 0 1-1.471-.636 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.803 0-.656.13-1.073.384-1.525a3.24 3.24 0 0 1 1.047-1.106c.445-.287.95-.492 1.532-.615a8.8 8.8 0 0 1 1.82-.185 8.404 8.404 0 0 1 1.972.24v-.438c0-.307-.035-.6-.11-.874a1.88 1.88 0 0 0-.384-.73 1.784 1.784 0 0 0-.724-.493 3.164 3.164 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.735 7.735 0 0 0-1.26.307l-.321-2.192c.335-.117.834-.233 1.478-.349a10.98 10.98 0 0 1 2.073-.178zm52.842 9.626c.822 0 1.43-.048 1.854-.13V13.7a6.347 6.347 0 0 0-1.574-.199c-.294 0-.595.021-.896.069a2.7 2.7 0 0 0-.814.24 1.46 1.46 0 0 0-.582.491c-.15.212-.218.335-.218.656 0 .628.218.991.615 1.23.404.245.938.362 1.615.362zm-.226-9.694c.883 0 1.629.108 2.231.327.602.219 1.088.526 1.444.915.355.39.609.923.759 1.483a6.8 6.8 0 0 1 .233 1.852v6.873c-.41.088-1.034.19-1.868.314-.834.123-1.772.184-2.813.184-.69 0-1.327-.068-1.895-.198a4.001 4.001 0 0 1-1.471-.635 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.804 0-.656.13-1.073.384-1.524.26-.45.608-.82 1.047-1.107.445-.286.95-.491 1.532-.614a8.803 8.803 0 0 1 2.751-.13c.329.034.671.096 1.04.185v-.437a3.3 3.3 0 0 0-.109-.875 1.873 1.873 0 0 0-.384-.731 1.784 1.784 0 0 0-.724-.492 3.165 3.165 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.75 7.75 0 0 0-1.26.307l-.321-2.193c.335-.116.834-.232 1.478-.348a11.633 11.633 0 0 1 2.073-.177zm-8.034-1.271a1.626 1.626 0 0 1-1.628-1.62c0-.895.725-1.62 1.628-1.62.904 0 1.63.725 1.63 1.62 0 .895-.733 1.62-1.63 1.62zm1.348 13.22h-2.689V7.27l2.69-.423v11.956zm-4.714 0c-4.386.02-4.386-3.54-4.386-4.107l-.008-13.336 2.676-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-8.698-5.903c0-1.156-.253-2.119-.746-2.788-.493-.677-1.183-1.01-2.067-1.01-.882 0-1.574.333-2.065 1.01-.493.676-.733 1.632-.733 2.788 0 1.168.246 1.953.74 2.63.492.683 1.183 1.018 2.066 1.018.882 0 1.574-.342 2.067-1.019.492-.683.738-1.46.738-2.63zm2.737-.007c0 .902-.13 1.584-.397 2.33a5.52 5.52 0 0 1-1.128 1.906 4.986 4.986 0 0 1-1.752 1.223c-.685.286-1.739.45-2.265.45-.528-.006-1.574-.157-2.252-.45a5.096 5.096 0 0 1-1.744-1.223c-.487-.527-.863-1.162-1.137-1.906a6.345 6.345 0 0 1-.41-2.33c0-.902.123-1.77.397-2.508a5.554 5.554 0 0 1 1.15-1.892 5.133 5.133 0 0 1 1.75-1.216c.679-.287 1.425-.423 2.232-.423.808 0 1.553.142 2.237.423a4.88 4.88 0 0 1 1.753 1.216 5.644 5.644 0 0 1 1.135 1.892c.287.738.431 1.606.431 2.508zm-20.138 0c0 1.12.246 2.363.738 2.882.493.52 1.13.78 1.91.78.424 0 .828-.062 1.204-.178.377-.116.677-.253.917-.417V9.33a10.476 10.476 0 0 0-1.766-.226c-.971-.028-1.71.37-2.23 1.004-.513.636-.773 1.75-.773 2.788zm7.438 5.274c0 1.824-.466 3.156-1.404 4.004-.936.846-2.367 1.27-4.296 1.27-.705 0-2.17-.137-3.34-.396l.431-2.118c.98.205 2.272.26 2.95.26 1.074 0 1.84-.219 2.299-.656.459-.437.684-1.086.684-1.948v-.437a8.07 8.07 0 0 1-1.047.397c-.43.13-.93.198-1.492.198-.739 0-1.41-.116-2.018-.349a4.206 4.206 0 0 1-1.567-1.025c-.431-.45-.774-1.017-1.013-1.694-.24-.677-.363-1.885-.363-2.773 0-.834.13-1.88.384-2.577.26-.696.629-1.298 1.129-1.796.493-.498 1.095-.881 1.8-1.162a6.605 6.605 0 0 1 2.428-.457c.87 0 1.67.109 2.45.24.78.129 1.444.265 1.985.415V18.17zM6.972 6.677v1.627c-.712-.446-1.52-.67-2.425-.67-.585 0-1.045.13-1.38.391a1.24 1.24 0 0 0-.502 1.03c0 .425.164.765.494 1.02.33.256.835.532 1.516.83.447.192.795.356 1.045.495.25.138.537.332.862.582.324.25.563.548.718.894.154.345.23.741.23 1.188 0 .947-.334 1.691-1.004 2.234-.67.542-1.537.814-2.601.814-1.18 0-2.16-.229-2.936-.686v-1.708c.84.628 1.814.942 2.92.942.585 0 1.048-.136 1.388-.407.34-.271.51-.646.51-1.125 0-.287-.1-.55-.302-.79-.203-.24-.42-.42-.655-.542-.234-.123-.585-.29-1.053-.503a61.27 61.27 0 0 1-.582-.271 13.67 13.67 0 0 1-.55-.287 4.275 4.275 0 0 1-.567-.351 6.92 6.92 0 0 1-.455-.4c-.18-.17-.31-.34-.39-.51-.08-.17-.155-.37-.224-.598a2.553 2.553 0 0 1-.104-.742c0-.915.333-1.638.998-2.17.664-.532 1.523-.798 2.576-.798.968 0 1.793.17 2.473.51zm7.468 5.696v-.287c-.022-.607-.187-1.088-.495-1.444-.309-.357-.75-.535-1.324-.535-.532 0-.99.194-1.373.583-.382.388-.622.949-.717 1.683h3.909zm1.005 2.792v1.404c-.596.34-1.383.51-2.362.51-1.255 0-2.255-.377-3-1.132-.744-.755-1.116-1.744-1.116-2.968 0-1.297.34-2.316 1.021-3.055.68-.74 1.548-1.11 2.6-1.11 1.033 0 1.852.323 2.458.966.606.644.91 1.572.91 2.784 0 .33-.033.676-.096 1.038h-5.314c.107.702.405 1.239.894 1.611.49.372 1.106.558 1.85.558.862 0 1.58-.202 2.155-.606zm6.605-1.77h-1.212c-.596 0-1.045.116-1.349.35-.303.234-.454.532-.454.894 0 .372.117.664.35.877.235.213.575.32 1.022.32.51 0 .912-.142 1.204-.424.293-.281.44-.651.44-1.108v-.91zm-4.068-2.554V9.325c.627-.361 1.457-.542 2.489-.542 2.116 0 3.175 1.026 3.175 3.08V17h-1.548v-.957c-.415.68-1.143 1.02-2.186 1.02-.766 0-1.38-.22-1.843-.661-.462-.442-.694-1.003-.694-1.684 0-.776.293-1.38.878-1.81.585-.431 1.404-.647 2.457-.647h1.34V11.8c0-.554-.133-.971-.399-1.253-.266-.282-.707-.423-1.324-.423a4.07 4.07 0 0 0-2.345.718zm9.333-1.93v1.42c.394-1 1.101-1.5 2.123-1.5.148 0 .313.016.494.048v1.531a1.885 1.885 0 0 0-.75-.143c-.542 0-.989.24-1.34.718-.351.479-.527 1.048-.527 1.707V17h-1.563V8.91h1.563zm5.01 4.084c.022.82.272 1.492.75 2.019.479.526 1.15.79 2.01.79.639 0 1.235-.176 1.788-.527v1.404c-.521.319-1.186.479-1.995.479-1.265 0-2.276-.4-3.031-1.197-.755-.798-1.133-1.792-1.133-2.984 0-1.16.38-2.151 1.14-2.975.761-.825 1.79-1.237 3.088-1.237.702 0 1.346.149 1.93.447v1.436a3.242 3.242 0 0 0-1.77-.495c-.84 0-1.513.266-2.019.798-.505.532-.758 1.213-.758 2.042zM40.24 5.72v4.579c.458-1 1.293-1.5 2.505-1.5.787 0 1.42.245 1.899.734.479.49.718 1.17.718 2.042V17h-1.564v-5.106c0-.553-.14-.98-.422-1.284-.282-.303-.652-.455-1.11-.455-.531 0-1.002.202-1.411.606-.41.405-.615 1.022-.615 1.851V17h-1.563V5.72h1.563zm14.966 10.02c.596 0 1.096-.253 1.5-.758.404-.506.606-1.157.606-1.955 0-.915-.202-1.62-.606-2.114-.404-.495-.92-.742-1.548-.742-.553 0-1.05.224-1.491.67-.442.447-.662 1.133-.662 2.058 0 .958.212 1.67.638 2.138.425.469.946.703 1.563.703zM53.004 5.72v4.42c.574-.894 1.388-1.341 2.44-1.341 1.022 0 1.857.383 2.506 1.149.649.766.973 1.781.973 3.047 0 1.138-.309 2.109-.925 2.912-.617.803-1.463 1.205-2.537 1.205-1.075 0-1.894-.447-2.457-1.34V17h-1.58V5.72h1.58zm9.908 11.104l-3.223-7.913h1.739l1.005 2.632 1.26 3.415c.096-.32.48-1.458 1.15-3.415l.909-2.632h1.66l-2.92 7.866c-.777 2.074-1.963 3.11-3.559 3.11a2.92 2.92 0 0 1-.734-.079v-1.34c.17.042.351.064.543.064 1.032 0 1.755-.57 2.17-1.708z"
}), /*#__PURE__*/ react.createElement("path", {
fill: "#5468FF",
d: "M78.988.938h16.594a2.968 2.968 0 0 1 2.966 2.966V20.5a2.967 2.967 0 0 1-2.966 2.964H78.988a2.967 2.967 0 0 1-2.966-2.964V3.897A2.961 2.961 0 0 1 78.988.938z"
}), /*#__PURE__*/ react.createElement("path", {
fill: "white",
d: "M89.632 5.967v-.772a.978.978 0 0 0-.978-.977h-2.28a.978.978 0 0 0-.978.977v.793c0 .088.082.15.171.13a7.127 7.127 0 0 1 1.984-.28c.65 0 1.295.088 1.917.259.082.02.164-.04.164-.13m-6.248 1.01l-.39-.389a.977.977 0 0 0-1.382 0l-.465.465a.973.973 0 0 0 0 1.38l.383.383c.062.061.15.047.205-.014.226-.307.472-.601.746-.874.281-.28.568-.526.883-.751.068-.042.075-.137.02-.2m4.16 2.453v3.341c0 .096.104.165.192.117l2.97-1.537c.068-.034.089-.117.055-.184a3.695 3.695 0 0 0-3.08-1.866c-.068 0-.136.054-.136.13m0 8.048a4.489 4.489 0 0 1-4.49-4.482 4.488 4.488 0 0 1 4.49-4.482 4.488 4.488 0 0 1 4.489 4.482 4.484 4.484 0 0 1-4.49 4.482m0-10.85a6.363 6.363 0 1 0 0 12.729 6.37 6.37 0 0 0 6.372-6.368 6.358 6.358 0 0 0-6.371-6.36"
})))))), searchResultState.items.length > 0 ? /*#__PURE__*/ react.createElement("main", null, searchResultState.items.map(({ title, url, summary, breadcrumbs }, i)=>/*#__PURE__*/ react.createElement("article", {
key: i,
className: styles_module.searchResultItem
}, /*#__PURE__*/ react.createElement("h2", {
className: styles_module.searchResultItemHeading
}, /*#__PURE__*/ react.createElement(Link/* default */.Z, {
to: url,
dangerouslySetInnerHTML: {
__html: title
}
})), breadcrumbs.length > 0 && /*#__PURE__*/ react.createElement("nav", {
"aria-label": "breadcrumbs"
}, /*#__PURE__*/ react.createElement("ul", {
className: (0,clsx_m/* default */.Z)('breadcrumbs', styles_module.searchResultItemPath)
}, breadcrumbs.map((html, index)=>/*#__PURE__*/ react.createElement("li", {
key: index,
className: "breadcrumbs__item",
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML: {
__html: html
}
})))), summary && /*#__PURE__*/ react.createElement("p", {
className: styles_module.searchResultItemSummary,
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML: {
__html: summary
}
})))) : [
searchQuery && !searchResultState.loading && /*#__PURE__*/ react.createElement("p", {
key: "no-results"
}, /*#__PURE__*/ react.createElement(Translate/* default */.Z, {
id: "theme.SearchPage.noResultsText",
description: "The paragraph for empty search result"
}, "No results were found")),
!!searchResultState.loading && /*#__PURE__*/ react.createElement("div", {
key: "spinner",
className: styles_module.loadingSpinner
})
], searchResultState.hasMore && /*#__PURE__*/ react.createElement("div", {
className: styles_module.loader,
ref: setLoaderRef
}, /*#__PURE__*/ react.createElement(Translate/* default */.Z, {
id: "theme.SearchPage.fetchingNewResults",
description: "The paragraph for fetching new search results"
}, "Fetching new results..."))));
}
function SearchPage() {
return /*#__PURE__*/ react.createElement(metadataUtils/* HtmlClassNameProvider */.FG, {
className: "search-page-wrapper"
}, /*#__PURE__*/ react.createElement(SearchPageContent, null));
}
/***/ })
}]);