algoliasearch-helper
Advanced tools
Comparing version 2.0.4 to 2.1.0
{ | ||
"name": "algoliasearch-helper", | ||
"version": "2.1.0", | ||
"homepage": "https://github.com/algolia/algoliasearch-helper-js", | ||
@@ -26,4 +27,4 @@ "authors": [ | ||
"dependencies": { | ||
"algoliasearch": "3.1.x" | ||
"algoliasearch": "3.x" | ||
} | ||
} |
54
index.js
"use strict"; | ||
var AlgoliaSearchHelper = require( "./src/algoliasearch.helper" ); | ||
var SearchParameters = require( "./src/SearchParameters" ); | ||
var SearchResults = require( "./src/SearchResults" ); | ||
/** | ||
* The algoliasearch-helper module is a function that instanciate the helper. | ||
* @module algoliasearch-helper | ||
* The algoliasearchHelper module 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( result ) { | ||
* console.log( result ); | ||
* } ); | ||
* helper.toggleRefine( "Movies & TV Shows" ) | ||
* .toggleRefine( "Free shipping" ) | ||
* .search(); | ||
* @module algoliasearchHelper | ||
* @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 {SearchParamaters}, just an object containing the properties you need from it. | ||
* @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} | ||
*/ | ||
function helper( client, index, opts ) { | ||
function algoliasearchHelper( client, index, opts ) { | ||
return new AlgoliaSearchHelper( client, index, opts ); | ||
@@ -17,6 +36,27 @@ } | ||
* The version currently used | ||
* @member module:algoliasearch-helper.version | ||
* @member module:algoliasearchHelper.version | ||
*/ | ||
helper.version = "2.0.4"; | ||
algoliasearchHelper.version = "2.1.0"; | ||
module.exports = helper; | ||
/** | ||
* Constructor for the Helper. | ||
* @member module:algoliasearchHelper.AlgoliaSearchHelper | ||
* @see AlgoliaSearchHelper | ||
*/ | ||
algoliasearchHelper.AlgoliaSearchHelper = AlgoliaSearchHelper; | ||
/** | ||
* Constructor for the object containing all the parameters of the search. | ||
* @member module:algoliasearchHelper.SearchParameters | ||
* @see SearchParameters | ||
*/ | ||
algoliasearchHelper.SearchParameters = SearchParameters; | ||
/** | ||
* Constructor for the object containing the results of the search. | ||
* @member module:algoliasearchHelper.SearchResults | ||
* @see SearchResults | ||
*/ | ||
algoliasearchHelper.SearchResults = SearchResults; | ||
module.exports = algoliasearchHelper; |
{ | ||
"name": "algoliasearch-helper", | ||
"version": "2.0.4", | ||
"version": "2.1.0", | ||
"description": "Helper for implementing advanced search features with algolia", | ||
@@ -11,2 +11,3 @@ "main": "index.js", | ||
"dev": "DEBUG=zuul* zuul --no-coverage --local 8090 --ui tape test/run.js", | ||
"dev-coverage": "DEBUG=zuul* zuul --local 8090 --ui tape test/run.js", | ||
"lint": "eslint src index.js; true", | ||
@@ -17,2 +18,3 @@ "watch-lint": " onchange '.eslintrc' 'src/**/*.js' 'index.js' -- npm run lint ", | ||
"doc": "jsdoc -r src index.js -d docs -c .jsdoc --readme README.MD", | ||
"doc:watch" : "onchange 'src/**/*.js' 'index.js' -- npm run doc", | ||
"publish-doc": "git checkout gh-pages && git merge master && npm run build && npm run doc && git commit -a -m 'Update doc' && git push origin gh-pages && git checkout master", | ||
@@ -22,2 +24,7 @@ "test-ci": "echo \"Error: no test specified\" && exit 1", | ||
}, | ||
"browserify": { | ||
"transform": [ | ||
"envify" | ||
] | ||
}, | ||
"author": { | ||
@@ -37,2 +44,3 @@ "name": "Algolia SAS", | ||
"bulkify": "1.1.1", | ||
"envify": "3.4.0", | ||
"eslint": "0.17.1", | ||
@@ -51,3 +59,3 @@ "http-server": "0.8.0", | ||
"dependencies": { | ||
"lodash": "3.5.0" | ||
"lodash": "3.9.x" | ||
}, | ||
@@ -54,0 +62,0 @@ "peerDependencies": { |
@@ -12,3 +12,2 @@ *Coming from V1 (or js client v2)?* Read the [migration guide](https://github.com/algolia/algoliasearch-helper-js/wiki/Migration-guide-:-V1-to-V2) to the new version of the Helper. | ||
## Features | ||
a | ||
- Search parameters tracking | ||
@@ -15,0 +14,0 @@ - Facets exclusions |
@@ -22,3 +22,3 @@ "use strict"; | ||
* @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 {SearchParamaters}, just an object containing the properties you need from it. | ||
* @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. | ||
*/ | ||
@@ -28,4 +28,6 @@ function AlgoliaSearchHelper( client, index, options ) { | ||
this.index = index; | ||
this.state = new SearchParameters( options ); | ||
this.state = SearchParameters.make( options ); | ||
this.lastResults = null; | ||
this._queryId = 0; | ||
this._lastQueryIdReceived = -1; | ||
} | ||
@@ -67,2 +69,12 @@ | ||
/** | ||
* Remove all the tag filtering | ||
* @return {AlgoliaSearchHelper} | ||
*/ | ||
AlgoliaSearchHelper.prototype.clearTags = function() { | ||
this.state = this.state.clearTags(); | ||
this._change(); | ||
return this; | ||
}; | ||
/** | ||
* Ensure a facet refinement exists | ||
@@ -80,3 +92,16 @@ * @param {string} facet the facet to refine | ||
/** | ||
* Ensure a facet refinement does not exist | ||
* Add a numeric refinement on the given attribute | ||
* @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} | ||
*/ | ||
AlgoliaSearchHelper.prototype.addNumericRefinement = function( attribute, operator, value ) { | ||
this.state = this.state.addNumericRefinement( attribute, operator, value ); | ||
this._change(); | ||
return this; | ||
}; | ||
/** | ||
* Ensure a facet refinement exists | ||
* @param {string} facet the facet to refine | ||
@@ -86,4 +111,4 @@ * @param {string} value the associated value | ||
*/ | ||
AlgoliaSearchHelper.prototype.removeDisjunctiveRefine = function( facet, value ) { | ||
this.state = this.state.removeDisjunctiveFacetRefinement( facet, value ); | ||
AlgoliaSearchHelper.prototype.addRefine = function( facet, value ) { | ||
this.state = this.state.addFacetRefinement( facet, value ); | ||
this._change(); | ||
@@ -94,10 +119,9 @@ return this; | ||
/** | ||
* Add a numeric refinement on the given attribute | ||
* @param {string} attribute | ||
* @param {string} operator | ||
* @param {number} value | ||
* Ensure a facet exclude exists | ||
* @param {string} facet the facet to refine | ||
* @param {string} value the associated value | ||
* @return {AlgoliaSearchHelper} | ||
*/ | ||
AlgoliaSearchHelper.prototype.addNumericRefinement = function( attribute, operator, value ) { | ||
this.state = this.state.addNumericRefinement( attribute, operator, value ); | ||
AlgoliaSearchHelper.prototype.addExclude = function( facet, value ) { | ||
this.state = this.state.addExcludeRefinement( facet, value ); | ||
this._change(); | ||
@@ -108,6 +132,17 @@ return this; | ||
/** | ||
* Add a tag refinement | ||
* @param {string} tag the tag to add to the filter | ||
* @return {AlgoliaSearchHelper} | ||
*/ | ||
AlgoliaSearchHelper.prototype.addTag = function( tag ) { | ||
this.state = this.state.addTagRefinement( tag ); | ||
this._change(); | ||
return this; | ||
}; | ||
/** | ||
* Remove a numeric filter. | ||
* @param {string} attribute | ||
* @param {string} operator | ||
* @param {number} value | ||
* @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} | ||
@@ -121,4 +156,5 @@ */ | ||
/** | ||
* Ensure a facet refinement exists | ||
* Ensure a facet refinement does not exist | ||
* @param {string} facet the facet to refine | ||
@@ -128,4 +164,4 @@ * @param {string} value the associated value | ||
*/ | ||
AlgoliaSearchHelper.prototype.addRefine = function( facet, value ) { | ||
this.state = this.state.addFacetRefinement( facet, value ); | ||
AlgoliaSearchHelper.prototype.removeDisjunctiveRefine = function( facet, value ) { | ||
this.state = this.state.removeDisjunctiveFacetRefinement( facet, value ); | ||
this._change(); | ||
@@ -148,3 +184,3 @@ return this; | ||
/** | ||
* Ensure a facet exclude exists | ||
* Ensure a facet exclude does not exist | ||
* @param {string} facet the facet to refine | ||
@@ -154,4 +190,4 @@ * @param {string} value the associated value | ||
*/ | ||
AlgoliaSearchHelper.prototype.addExclude = function( facet, value ) { | ||
this.state = this.state.addExcludeRefinement( facet, value ); | ||
AlgoliaSearchHelper.prototype.removeExclude = function( facet, value ) { | ||
this.state = this.state.removeExcludeRefinement( facet, value ); | ||
this._change(); | ||
@@ -162,9 +198,8 @@ return this; | ||
/** | ||
* Ensure a facet exclude does not exist | ||
* @param {string} facet the facet to refine | ||
* @param {string} value the associated value | ||
* Ensure that a tag is not filtering the results | ||
* @param {string} tag tag to remove from the filter | ||
* @return {AlgoliaSearchHelper} | ||
*/ | ||
AlgoliaSearchHelper.prototype.removeExclude = function( facet, value ) { | ||
this.state = this.state.removeExcludeRefinement( facet, value ); | ||
AlgoliaSearchHelper.prototype.removeTag = function( tag ) { | ||
this.state = this.state.removeTagRefinement( tag ); | ||
this._change(); | ||
@@ -193,6 +228,6 @@ return this; | ||
AlgoliaSearchHelper.prototype.toggleRefine = function( facet, value ) { | ||
if( this.state.facets.indexOf( facet ) > -1 ) { | ||
if( this.state.isConjunctiveFacet( facet ) ) { | ||
this.state = this.state.toggleFacetRefinement( facet, value ); | ||
} | ||
else if( this.state.disjunctiveFacets.indexOf( facet ) > -1 ) { | ||
else if( this.state.isDisjunctiveFacet( facet ) ) { | ||
this.state = this.state.toggleDisjunctiveFacetRefinement( facet, value ); | ||
@@ -212,2 +247,13 @@ } | ||
/** | ||
* Toggle tag refinement | ||
* @param {string} tag tag to remove or add | ||
* @return {AlgoliaSearchHelper} | ||
*/ | ||
AlgoliaSearchHelper.prototype.toggleTag = function( tag ) { | ||
this.state = this.state.toggleTagRefinement( tag ); | ||
this._change(); | ||
return this; | ||
}; | ||
/** | ||
* Go to next page | ||
@@ -253,2 +299,18 @@ * @return {AlgoliaSearchHelper} | ||
/** | ||
* Update any single parameter of the state/configuration (based on SearchParameters). | ||
* @param {string} parameter name of the parameter to update | ||
* @param {any} value new value of the parameter | ||
* @return {AlgoliaSearchHelper} | ||
*/ | ||
AlgoliaSearchHelper.prototype.setQueryParameter = function( parameter, value ) { | ||
var newState = this.state.setQueryParameter( parameter, value ); | ||
if( this.state === newState ) return this; | ||
this.state = newState; | ||
this._change(); | ||
return this; | ||
}; | ||
/** | ||
* Set the whole state ( warning : will erase previous state ) | ||
@@ -286,3 +348,3 @@ * @param {SearchParameters} newState the whole new state | ||
/** | ||
* Check the refinement state of a facet | ||
* Check the refinement state of a given value for a facet | ||
* @param {string} facet the facet | ||
@@ -293,6 +355,6 @@ * @param {string} value the associated value | ||
AlgoliaSearchHelper.prototype.isRefined = function( facet, value ) { | ||
if( this.state.facets.indexOf( facet ) > -1 ) { | ||
if( this.state.isConjunctiveFacet( facet ) ) { | ||
return this.state.isFacetRefined( facet, value ); | ||
} | ||
else if( this.state.disjunctiveFacets.indexOf( facet ) > -1 ) { | ||
else if( this.state.isDisjunctiveFacet( facet ) ) { | ||
return this.state.isDisjunctiveFacetRefined( facet, value ); | ||
@@ -304,2 +366,11 @@ } | ||
/** | ||
* Check if the facet has any disjunctive or conjunctive refinements | ||
* @param {string} facet the facet attribute name | ||
* @return {boolean} true if the facet is facetted by at least one value | ||
*/ | ||
AlgoliaSearchHelper.prototype.hasRefinements = function( facet ) { | ||
return this.isRefined( facet ); | ||
}; | ||
/** | ||
* Check the exclude state of a facet | ||
@@ -325,3 +396,13 @@ * @param {string} facet the facet | ||
/** | ||
* Check if the string is a currently filtering tag | ||
* @param {string} tag tag to check | ||
* @return {boolean} | ||
*/ | ||
AlgoliaSearchHelper.prototype.isTagRefined = function( tag ) { | ||
return this.state.isTagRefined( tag ); | ||
}; | ||
/** | ||
* Get the underlying configured index name | ||
* @return {string} | ||
*/ | ||
@@ -334,3 +415,3 @@ AlgoliaSearchHelper.prototype.getIndex = function() { | ||
* Get the currently selected page | ||
* @return Number the current page | ||
* @return {number} the current page | ||
*/ | ||
@@ -341,2 +422,66 @@ AlgoliaSearchHelper.prototype.getCurrentPage = function() { | ||
/** | ||
* Get all the filtering tags | ||
* @return {string[]} | ||
*/ | ||
AlgoliaSearchHelper.prototype.getTags = function() { | ||
return this.state.tagRefinements; | ||
}; | ||
/** | ||
* Get a parameter of the search by its name | ||
* @param {string} parameterName the parameter name | ||
* @return {any} the parameter value | ||
*/ | ||
AlgoliaSearchHelper.prototype.getQueryParameter = function( parameterName ) { | ||
return this.state.getQueryParameter( parameterName ); | ||
}; | ||
/** | ||
* Get the list of refinements for a given attribute. | ||
* @param {string} facetName attribute name used for facetting | ||
* @return {Refinement[]} All Refinement are objects that contain a value, and a type. Numeric also contains an operator. | ||
*/ | ||
AlgoliaSearchHelper.prototype.getRefinements = function( facetName ) { | ||
var refinements = []; | ||
if( this.state.isConjunctiveFacet( facetName ) ) { | ||
var conjRefinements = this.state.getConjunctiveRefinements( facetName ); | ||
forEach( conjRefinements, function( r ) { | ||
refinements.push( { | ||
value : r, | ||
type : "conjunctive" | ||
} ); | ||
} ); | ||
} | ||
else if( this.state.isDisjunctiveFacet( facetName ) ) { | ||
var disjRefinements = this.state.getDisjunctiveRefinements( facetName ); | ||
forEach( disjRefinements, function( r ) { | ||
refinements.push( { | ||
value : r, | ||
type : "disjunctive" | ||
} ); | ||
} ); | ||
} | ||
var excludeRefinements = this.state.getExcludeRefinements( facetName ); | ||
forEach( excludeRefinements, function( r ) { | ||
refinements.push( { | ||
value : r, | ||
type : "exclude" | ||
} ); | ||
} ); | ||
var numericRefinements = this.state.getNumericRefinements( facetName ); | ||
forEach( numericRefinements, function( value, operator ) { | ||
refinements.push( { | ||
value : value, | ||
operator : operator, | ||
type : "numeric" | ||
} ); | ||
} ); | ||
return refinements; | ||
}; | ||
///////////// PRIVATE | ||
@@ -347,2 +492,3 @@ | ||
* @private | ||
* @return {undefined} | ||
*/ | ||
@@ -369,3 +515,7 @@ AlgoliaSearchHelper.prototype._search = function() { | ||
this.client.search( queries, bind( this._handleResponse, this, state ) ); | ||
this.client.search( queries, | ||
bind( this._handleResponse, | ||
this, | ||
state, | ||
this._queryId++ ) ); | ||
}; | ||
@@ -378,6 +528,15 @@ | ||
* @param {SearchParameters} state state used for to generate the request | ||
* @param {number} queryId id of the current request | ||
* @param {Error} err error if any, null otherwise | ||
* @param {object} content content of the response | ||
* @return {undefined} | ||
*/ | ||
AlgoliaSearchHelper.prototype._handleResponse = function( state, err, content ) { | ||
AlgoliaSearchHelper.prototype._handleResponse = function( state, queryId, err, content ) { | ||
if( queryId < this._lastQueryIdReceived ) { | ||
// Outdated answer | ||
return; | ||
} | ||
this._lastQueryIdReceived = queryId; | ||
if ( err ) { | ||
@@ -389,3 +548,2 @@ this.emit( "error", err ); | ||
var formattedResponse = this.lastResults = new SearchResults( state, content ); | ||
this.emit( "result", formattedResponse, state ); | ||
@@ -403,10 +561,15 @@ }; | ||
var numericFilters = this._getNumericFilters(); | ||
var tagFilters = this._getTagFilters(); | ||
var additionalParams = { | ||
facets : facets, | ||
distinct : false | ||
tagFilters : tagFilters, | ||
distinct : this.state.distinct || false | ||
}; | ||
if( !this.state.query && facetFilters.length === 0 && numericFilters.length === 0 && tagFilters.length === 0 ) { | ||
additionalParams.distinct = false; | ||
} | ||
if( facetFilters.length > 0 ) { | ||
additionalParams.facetFilters = facetFilters; | ||
additionalParams.distinct = this.state.distinct || false; | ||
} | ||
@@ -430,2 +593,3 @@ | ||
var numericFilters = this._getNumericFilters( facet ); | ||
var tagFilters = this._getTagFilters(); | ||
var additionalParams = { | ||
@@ -438,5 +602,10 @@ hitsPerPage : 1, | ||
facets : facet, | ||
distinct : false | ||
tagFilters : tagFilters, | ||
distinct : this.state.distinct || false | ||
}; | ||
if( !this.state.query && facetFilters.length === 0 && numericFilters.length === 0 && tagFilters.length === 0 ) { | ||
additionalParams.distinct = false; | ||
} | ||
if( numericFilters.length > 0 ) { | ||
@@ -448,3 +617,2 @@ additionalParams.numericFilters = numericFilters; | ||
additionalParams.facetFilters = facetFilters; | ||
additionalParams.distinct = this.state.distinct || false; | ||
} | ||
@@ -458,3 +626,4 @@ | ||
* @private | ||
* @return {array.<string>} the numeric filters in the algolia format | ||
* @param {string} [facetName] the name of the attribute for which the filters should be excluded | ||
* @return {string[]} the numeric filters in the algolia format | ||
*/ | ||
@@ -474,4 +643,19 @@ AlgoliaSearchHelper.prototype._getNumericFilters = function( facetName ) { | ||
/** | ||
* Return the tags filters depending | ||
* @private | ||
* @return {string} | ||
*/ | ||
AlgoliaSearchHelper.prototype._getTagFilters = function() { | ||
if( this.state.tagFilters ) { | ||
return this.state.tagFilters; | ||
} | ||
return this.state.tagRefinements.join( "," ); | ||
}; | ||
/** | ||
* Test if there are some disjunctive refinements on the facet | ||
* @private | ||
* @param {string} facet the attribute to test | ||
* @return {boolean} | ||
*/ | ||
@@ -487,3 +671,3 @@ AlgoliaSearchHelper.prototype._hasDisjunctiveRefinements = function( facet ) { | ||
* @private | ||
* @param {string} facet if set, the current disjunctive facet | ||
* @param {string} [facet] if set, the current disjunctive facet | ||
* @return {array.<string>} | ||
@@ -490,0 +674,0 @@ */ |
@@ -6,15 +6,23 @@ "use strict"; | ||
var reduce = require( "lodash/collection/reduce" ); | ||
var filter = require( "lodash/collection/filter" ); | ||
var omit = require( "lodash/object/omit" ); | ||
var isEmpty = require( "lodash/lang/isEmpty" ); | ||
var isUndefined = require( "lodash/lang/isUndefined" ); | ||
var isString = require( "lodash/lang/isString" ); | ||
var isFunction = require( "lodash/lang/isFunction" ); | ||
var extend = require( "../functions/extend" ); | ||
var deepFreeze = require( "../functions/deepFreeze" ); | ||
var RefinementList = require( "./RefinementList" ); | ||
/** | ||
* @typedef FacetList | ||
* @type {Array.<string>} | ||
* | ||
* @typedef OperatorList | ||
* @type {Object.<string, number>} | ||
* @typedef {string[]} SearchParameters.FacetList | ||
*/ | ||
/** | ||
* @typedef {Object.<string, number>} SearchParameters.OperatorList | ||
*/ | ||
/** | ||
* SearchParameters is the data structure that contains all the informations | ||
@@ -29,7 +37,12 @@ * usable for making a search to Algolia API. It doesn't do the search itself, | ||
* get it from events generated by the {Helper}. | ||
* If need be, instanciate the Helper from the factory function 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 | ||
*/ | ||
var SearchParameters = function( newParameters ) { | ||
var params = newParameters || {}; | ||
//Query | ||
@@ -41,2 +54,3 @@ /** | ||
this.query = params.query || ""; | ||
//Facets | ||
@@ -54,22 +68,37 @@ /** | ||
//Refinements | ||
/** @member {Object.<string, FacetList>}*/ | ||
/** @member {Object.<string, SearchParameters.FacetList>}*/ | ||
this.facetsRefinements = params.facetsRefinements || {}; | ||
/** @member {Object.<string, FacetList>}*/ | ||
/** @member {Object.<string, SearchParameters.FacetList>}*/ | ||
this.facetsExcludes = params.facetsExcludes || {}; | ||
/** @member {Object.<string, FacetList>}*/ | ||
/** @member {Object.<string, SearchParameters.FacetList>}*/ | ||
this.disjunctiveFacetsRefinements = params.disjunctiveFacetsRefinements || {}; | ||
/** | ||
* @member {Object.<string, OperatorList>} | ||
* @member {Object.<string, SearchParameters.OperatorList>} | ||
*/ | ||
this.numericRefinements = params.numericRefinements || {}; | ||
/** | ||
* Contains the tags used to refine the query | ||
* Associated property in the query : tagFilters | ||
* @see https://www.algolia.com/doc#tagFilters | ||
* @member {string[]} | ||
*/ | ||
this.tagRefinements = params.tagRefinements || []; | ||
/** | ||
* Contains the tag filters in the raw format of the Algolia API. Setting this | ||
* parameter is not compatible with the of the add/remove/toggle methods of the | ||
* tag api. | ||
* @member {string} | ||
*/ | ||
this.tagFilters = params.tagFilters; | ||
//Misc. parameters | ||
/** @member {number} */ | ||
this.hitsPerPage = params.hitsPerPage || 20; | ||
this.hitsPerPage = params.hitsPerPage; | ||
/** | ||
* @member {number} | ||
**/ | ||
this.maxValuesPerFacet = params.maxValuesPerFacet || 10; | ||
this.maxValuesPerFacet = params.maxValuesPerFacet; | ||
/** @member {number} */ | ||
this.page = params.page || 0; | ||
/** | ||
@@ -170,7 +199,2 @@ * Possible values : prefixAll, prefixLast, prefixNone | ||
/** | ||
* @see https://www.algolia.com/doc#tagFilters | ||
* @member {string} | ||
*/ | ||
this.tagFilters = params.tagFilters; | ||
/** | ||
* @see https://www.algolia.com/doc#distinct | ||
@@ -207,2 +231,39 @@ * @member {boolean} | ||
/** | ||
* 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 ); | ||
return deepFreeze( 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 || {}; | ||
var ks = keys( params ); | ||
var unknownKeys = filter( ks, function( k ) { | ||
return !currentState.hasOwnProperty( k ); | ||
} ); | ||
if( unknownKeys.length === 1 ) return new Error( "Property " + unknownKeys[0] + " is not defined on SearchParameters (see http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html )" ); | ||
if( unknownKeys.length > 1 ) return new Error( "Properties " + unknownKeys.join( " " ) + " are not defined on SearchParameters (see http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html )" ); | ||
if( currentState.tagFilters && params.tagRefinements && params.tagRefinements.length > 0 ) { | ||
return new Error( "[Tags] Can't switch from the managed tag API to the advanced API. It is probably an error, if it's really what you want, you should first clear the tags with clearTags method." ); | ||
} | ||
if( currentState.tagRefinements.length > 0 && params.tagFilters ) { | ||
return new Error( "[Tags] Can't switch from the advanced tag API to the managed API. It is probably an error, if it's not, you should first clear the tags with clearTags method." ); | ||
} | ||
return null; | ||
}; | ||
SearchParameters.prototype = { | ||
@@ -214,15 +275,32 @@ constructor : SearchParameters, | ||
* @method | ||
* @param {string} [name] - If given, name of the facet / attribute on which we want to remove all refinements | ||
* @return {AlgoliaSearchHelper} | ||
* @param {string|SearchParameters.clearCallback} [attribute] optionnal 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} | ||
*/ | ||
clearRefinements : function clearRefinements( name ) { | ||
return this.mutateMe( function( m ) { | ||
m.page = 0; | ||
m._clearNumericRefinements( name ); | ||
m._clearFacetRefinements( name ); | ||
m._clearExcludeRefinements( name ); | ||
m._clearDisjunctiveFacetRefinements( name ); | ||
clearRefinements : function clearRefinements( attribute ) { | ||
return this.setQueryParameters( { | ||
page : 0, | ||
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" ) | ||
} ); | ||
}, | ||
/** | ||
* Remove all the refined tags from the SearchParameters | ||
* @method | ||
* @return {SearchParameters} | ||
*/ | ||
clearTags : function clearTags() { | ||
if( this.tagFilters === undefined && this.tagRefinements.length === 0 ) return this; | ||
return this.setQueryParameters( { | ||
page : 0, | ||
tagFilters : undefined, | ||
tagRefinements : [] | ||
} ); | ||
}, | ||
/** | ||
* Query setter | ||
@@ -234,5 +312,7 @@ * @method | ||
setQuery : function setQuery( newQuery ) { | ||
return this.mutateMe( function( m ) { | ||
m.query = newQuery; | ||
m.page = 0; | ||
if( newQuery === this.query ) return this; | ||
return this.setQueryParameters( { | ||
query : newQuery, | ||
page : 0 | ||
} ); | ||
@@ -247,4 +327,6 @@ }, | ||
setPage : function setPage( newPage ) { | ||
return this.mutateMe( function( mutable ) { | ||
mutable.page = newPage; | ||
if( newPage === this.page ) return this; | ||
return this.setQueryParameters( { | ||
page : newPage | ||
} ); | ||
@@ -260,4 +342,4 @@ }, | ||
setFacets : function setFacets( facets ) { | ||
return this.mutateMe( function( m ) { | ||
m.facets = facets; | ||
return this.setQueryParameters( { | ||
facets : facets | ||
} ); | ||
@@ -273,4 +355,4 @@ }, | ||
setDisjunctiveFacets : function setDisjunctiveFacets( facets ) { | ||
return this.mutateMe( function( m ) { | ||
m.disjunctiveFacets = facets; | ||
return this.setQueryParameters( { | ||
disjunctiveFacets : facets | ||
} ); | ||
@@ -286,8 +368,9 @@ }, | ||
setHitsPerPage : function setHitsPerPage( n ) { | ||
return this.mutateMe( function( m ) { | ||
m.hitsPerPage = n; | ||
m.page = 0; | ||
if( this.hitsPerPage === n ) return this; | ||
return this.setQueryParameters( { | ||
hitsPerPage : n, | ||
page : 0 | ||
} ); | ||
}, | ||
/** | ||
@@ -297,9 +380,11 @@ * typoTolerance setter | ||
* @method | ||
* @param {string} s string new value of typoTolerance ("true", "false", "min" or "strict") | ||
* @param {string} typoTolerance new value of typoTolerance ("true", "false", "min" or "strict") | ||
* @return {SearchParameters} | ||
*/ | ||
setTypoTolerance : function setTypoTolerance( s ) { | ||
return this.mutateMe( function( m ) { | ||
m.typoTolerance = s; | ||
m.page = 0; | ||
setTypoTolerance : function setTypoTolerance( typoTolerance ) { | ||
if( this.typoTolerance === typoTolerance ) return this; | ||
return this.setQueryParameters( { | ||
typoTolerance : typoTolerance, | ||
page : 0 | ||
} ); | ||
@@ -316,13 +401,41 @@ }, | ||
* @param {number} value value of the filter | ||
* @return {SearchParameters} | ||
*/ | ||
addNumericRefinement : function( attribute, operator, value ) { | ||
return this.mutateMe( function( m ) { | ||
m.page = 0; | ||
if( !m.numericRefinements[ attribute ] ) { | ||
m.numericRefinements[ attribute ] = {}; | ||
} | ||
m.numericRefinements[ attribute ][ operator ] = value; | ||
if( this.isNumericRefined( attribute, operator, value ) ) return this; | ||
var mod = extend( {}, this.numericRefinements ); | ||
mod[ attribute ] = extend( {}, mod[ attribute ] ); | ||
mod[ attribute ][ operator ] = value; | ||
return this.setQueryParameters( { | ||
page : 0, | ||
numericRefinements : mod | ||
} ); | ||
}, | ||
/** | ||
* Get the list of conjunctive refinements for a single facet | ||
* @param {string} facetName name of the attribute used for facetting | ||
* @return {string[]} list of refinements | ||
*/ | ||
getConjunctiveRefinements : function( facetName ) { | ||
return this.facetsRefinements[ facetName ] || []; | ||
}, | ||
/** | ||
* Get the list of disjunctive refinements for a single facet | ||
* @param {string} facetName name of the attribute used for facetting | ||
* @return {string[]} list of refinements | ||
*/ | ||
getDisjunctiveRefinements : function( facetName ) { | ||
return this.disjunctiveFacetsRefinements[ facetName ] || []; | ||
}, | ||
/** | ||
* Get the list of exclude refinements for a single facet | ||
* @param {string} facetName name of the attribute used for facetting | ||
* @return {string[]} list of refinements | ||
*/ | ||
getExcludeRefinements : function( facetName ) { | ||
return this.facetsExcludes[ facetName ] || []; | ||
}, | ||
/** | ||
* Remove a numeric filter | ||
@@ -332,18 +445,23 @@ * @method | ||
* @param {string} operator operator of the filter ( possible values : =, >, >=, <, <=, != ) | ||
* @return {SearchParameters} | ||
*/ | ||
removeNumericRefinement : function( attribute, operator ) { | ||
return this.mutateMe( function( m ) { | ||
if( m.numericRefinements[ attribute ] ) { | ||
m.page = 0; | ||
var value = m.numericRefinements[ attribute ][ operator ]; | ||
if( !isUndefined( value ) ) { | ||
delete m.numericRefinements[ attribute ][ operator ]; | ||
if( isEmpty( m.numericRefinements[ attribute ] ) ) { | ||
delete m.numericRefinements[ attribute ]; | ||
} | ||
} | ||
} | ||
if( !this.isNumericRefined( attribute, operator ) ) return this; | ||
return this.setQueryParameters( { | ||
page : 0, | ||
numericRefinements : this._clearNumericRefinements( function( value, key ) { | ||
return key === attribute && value.op === operator; | ||
} ) | ||
} ); | ||
}, | ||
/** | ||
* Get the list of numeric refinements for a single facet | ||
* @param {string} facetName name of the attribute used for facetting | ||
* @return {SearchParameters.OperatorList[]} list of refinements | ||
*/ | ||
getNumericRefinements : function( facetName ) { | ||
return this.numericRefinements[ facetName ] || []; | ||
}, | ||
/** | ||
* Return the current refinement for the ( attribute, operator ) | ||
@@ -361,15 +479,25 @@ * @param {string} attribute of the record | ||
* @private | ||
* @param {string} [attribute] - | ||
* @param {string|SearchParameters.clearCallback} [attribute] optionnal 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>} | ||
*/ | ||
_clearNumericRefinements : function _clearNumericRefinements( attribute ) { | ||
if ( isUndefined( attribute ) ) { | ||
this.numericRefinements = {}; | ||
return {}; | ||
} | ||
else if ( isString( attribute ) ) { | ||
if ( !isUndefined( this.numericRefinements[ attribute ] ) ) { | ||
delete this.numericRefinements[ attribute ]; | ||
} | ||
return omit( this.numericRefinements, attribute ); | ||
} | ||
else if ( isFunction( attribute ) ) { | ||
return reduce( this.numericRefinements, function( memo, operators, key ) { | ||
var operatorList = omit( operators, function( value, operator ) { | ||
return attribute( { val : value, op : operator }, key, "numeric" ); | ||
} ); | ||
if( !isEmpty( operatorList ) ) memo[ key ] = operatorList; | ||
return memo; | ||
}, {} ); | ||
} | ||
}, | ||
@@ -384,12 +512,6 @@ /** | ||
addFacetRefinement : function addFacetRefinement( facet, value ) { | ||
if( this.isFacetRefined( facet, value ) ) { | ||
return this; | ||
} | ||
return this.mutateMe( function( m ) { | ||
m.page = 0; | ||
if( !m.facetsRefinements[ facet ] ) { | ||
m.facetsRefinements[ facet ] = []; | ||
} | ||
m.facetsRefinements[ facet ].push( value ); | ||
if( RefinementList.isRefined( this.facetsRefinements, facet, value ) ) return this; | ||
return this.setQueryParameters( { | ||
page : 0, | ||
facetsRefinements : RefinementList.addRefinement( this.facetsRefinements, facet, value ) | ||
} ); | ||
@@ -405,8 +527,6 @@ }, | ||
addExcludeRefinement : function addExcludeRefinement( facet, value ) { | ||
return this.mutateMe( function( m ) { | ||
m.page = 0; | ||
if( !m.facetsExcludes[ facet ] ) { | ||
m.facetsExcludes[ facet ] = []; | ||
} | ||
m.facetsExcludes[ facet ].push( value ); | ||
if( RefinementList.isRefined( this.facetsExcludes, facet, value ) ) return this; | ||
return this.setQueryParameters( { | ||
page : 0, | ||
facetsExcludes : RefinementList.addRefinement( this.facetsExcludes, facet, value ) | ||
} ); | ||
@@ -422,11 +542,24 @@ }, | ||
addDisjunctiveFacetRefinement : function addDisjunctiveFacetRefinement( facet, value ) { | ||
return this.mutateMe( function( m ) { | ||
m.page = 0; | ||
if( !m.disjunctiveFacetsRefinements[ facet ] ) { | ||
m.disjunctiveFacetsRefinements[ facet ] = []; | ||
} | ||
m.disjunctiveFacetsRefinements[ facet ].push( value ); | ||
if( RefinementList.isRefined( this.disjunctiveFacetsRefinements, facet, value ) ) return this; | ||
return this.setQueryParameters( { | ||
page : 0, | ||
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} | ||
*/ | ||
addTagRefinement : function addTagRefinement( tag ) { | ||
if( this.isTagRefined( tag ) ) return this; | ||
var modification = { | ||
page : 0, | ||
tagRefinements : this.tagRefinements.concat( tag ) | ||
}; | ||
return this.setQueryParameters( modification ); | ||
}, | ||
/** | ||
* Remove a refinement set on facet. If a value is provided, it will clear the | ||
@@ -436,21 +569,12 @@ * refinement for the given value, otherwise it will clear all the refinement | ||
* @method | ||
* @param {string} facet | ||
* @param {string} value | ||
* @param {string} facet name of the attribute used for facetting | ||
* @param {string} value value used to filter | ||
* @return {SearchParameters} | ||
*/ | ||
removeFacetRefinement : function removeFacetRefinement( facet, value ) { | ||
return this.mutateMe( function( m ) { | ||
m.page = 0; | ||
if( value ) { | ||
var idx = m.facetsRefinements[ facet ].indexOf( value ); | ||
if( idx > -1 ) { | ||
m.facetsRefinements[ facet ].splice( idx, 1 ); | ||
if( m.facetsRefinements[ facet ].length === 0 ) { | ||
delete m.facetsRefinements[ facet ]; | ||
} | ||
} | ||
} | ||
else { | ||
m._clearFacetRefinements( facet ); | ||
} | ||
if( !RefinementList.isRefined( this.facetsRefinements, facet, value ) ) return this; | ||
return this.setQueryParameters( { | ||
page : 0, | ||
facetsRefinements : RefinementList.removeRefinement( this.facetsRefinements, facet, value ) | ||
} ); | ||
@@ -461,18 +585,12 @@ }, | ||
* @method | ||
* @param {string} facet | ||
* @param {string} value | ||
* @param {string} facet name of the attribute used for facetting | ||
* @param {string} value value used to filter | ||
* @return {SearchParameters} | ||
*/ | ||
removeExcludeRefinement : function removeExcludeRefinement( facet, value ) { | ||
return this.mutateMe( function( m ) { | ||
if( m.facetsExcludes[ facet ] ) { | ||
m.page = 0; | ||
var idx = m.facetsExcludes[ facet ].indexOf( value ); | ||
if( idx > -1 ) { | ||
m.facetsExcludes[ facet ].splice( idx, 1 ); | ||
if( m.facetsExcludes[ facet ].length === 0 ) { | ||
delete m.facetsExcludes[ facet ]; | ||
} | ||
} | ||
} | ||
if( !RefinementList.isRefined( this.facetsExcludes, facet, value ) ) return this; | ||
return this.setQueryParameters( { | ||
page : 0, | ||
facetsExcludes : RefinementList.removeRefinement( this.facetsExcludes, facet, value ) | ||
} ); | ||
@@ -483,73 +601,55 @@ }, | ||
* @method | ||
* @param {string} facet | ||
* @param {string} value | ||
* @param {string} facet name of the attribute used for facetting | ||
* @param {string} value value used to filter | ||
* @return {SearchParameters} | ||
*/ | ||
removeDisjunctiveFacetRefinement : function removeDisjunctiveFacetRefinement( facet, value ) { | ||
return this.mutateMe( function( m ) { | ||
if( m.disjunctiveFacetsRefinements[ facet ] ) { | ||
m.page = 0; | ||
var idx = m.disjunctiveFacetsRefinements[ facet ].indexOf( value ); | ||
if( idx > -1 ) { | ||
m.disjunctiveFacetsRefinements[ facet ].splice( idx, 1 ); | ||
if( m.disjunctiveFacetsRefinements[facet].length === 0 ) { | ||
delete m.disjunctiveFacetsRefinements[ facet ]; | ||
} | ||
} | ||
} | ||
if( !RefinementList.isRefined( this.disjunctiveFacetsRefinements, facet, value ) ) return this; | ||
return this.setQueryParameters( { | ||
page : 0, | ||
disjunctiveFacetsRefinements : RefinementList.removeRefinement( this.disjunctiveFacetsRefinements, facet, value ) | ||
} ); | ||
}, | ||
/** | ||
* Clear the facet refinements | ||
* Remove a tag from the list of tag refinements | ||
* @method | ||
* @private | ||
* @param {string} [facet] - | ||
* - If not given, means to clear the refinement of all facets. | ||
* - If `string`, means to clear the refinement for the `facet` named facet. | ||
* @param {string} tag the tag to remove | ||
* @return {SearchParameters} | ||
*/ | ||
_clearFacetRefinements : function _clearFacetRefinements( facet ) { | ||
if ( isUndefined( facet ) ) { | ||
this.facetsRefinements = {}; | ||
} | ||
else if ( isString( facet ) ) { | ||
if ( !isUndefined( this.facetsRefinements[ facet ] ) ) { | ||
delete this.facetsRefinements[ facet ]; | ||
} | ||
} | ||
removeTagRefinement : function removeTagRefinement( tag ) { | ||
if( !this.isTagRefined( tag ) ) return this; | ||
var modification = { | ||
page : 0, | ||
tagRefinements : filter( this.tagRefinements, function( t ) { return t !== tag; } ) | ||
}; | ||
return this.setQueryParameters( modification ); | ||
}, | ||
/** | ||
* Clear the exclude refinements | ||
* Switch the refinement applied over a facet/value | ||
* @method | ||
* @private | ||
* @param {string} [facet] - | ||
* - If not given, means to clear all the excludes of all facets. | ||
* - If `string`, means to clear all the excludes for the `facet` named facet. | ||
* @param {string} facet name of the attribute used for facetting | ||
* @param {value} value value used for filtering | ||
* @return {SearchParameters} | ||
*/ | ||
_clearExcludeRefinements : function _clearExcludeRefinements( facet ) { | ||
if ( isUndefined( facet ) ) { | ||
this.facetsExcludes = {}; | ||
} | ||
else if ( isString( facet ) ) { | ||
if ( !isUndefined( this.facetsExcludes[ facet ] ) ) { | ||
delete this.facetsExcludes[ facet ]; | ||
} | ||
} | ||
toggleFacetRefinement : function toggleFacetRefinement( facet, value ) { | ||
return this.setQueryParameters( { | ||
page : 0, | ||
facetsRefinements : RefinementList.toggleRefinement( this.facetsRefinements, facet, value ) | ||
} ); | ||
}, | ||
/** | ||
* Clear the disjunctive refinements | ||
* Switch the refinement applied over a facet/value | ||
* @method | ||
* @private | ||
* @param {string} [facet] - | ||
* - If not given, means to clear all the refinements of all disjunctive facets. | ||
* - If `string`, means to clear all the refinements for the `facet` named facet. | ||
* @param {string} facet name of the attribute used for facetting | ||
* @param {value} value value used for filtering | ||
* @return {SearchParameters} | ||
*/ | ||
_clearDisjunctiveFacetRefinements : function _clearDisjunctiveFacetRefinements( facet ) { | ||
if ( isUndefined( facet ) ) { | ||
this.disjunctiveFacetsRefinements = {}; | ||
} | ||
else if ( isString( facet ) ) { | ||
if ( !isUndefined( this.disjunctiveFacetsRefinements[ facet ] ) ) { | ||
delete this.disjunctiveFacetsRefinements[ facet ]; | ||
} | ||
} | ||
toggleExcludeFacetRefinement : function toggleExcludeFacetRefinement( facet, value ) { | ||
return this.setQueryParameters( { | ||
page : 0, | ||
facetsExcludes : RefinementList.toggleRefinement( this.facetsExcludes, facet, value ) | ||
} ); | ||
}, | ||
@@ -559,85 +659,116 @@ /** | ||
* @method | ||
* @param {string} facet | ||
* @param {value} value | ||
* @param {string} facet name of the attribute used for facetting | ||
* @param {value} value value used for filtering | ||
* @return {SearchParameters} | ||
*/ | ||
toggleFacetRefinement : function toggleFacetRefinement( facet, value ) { | ||
if( this.isFacetRefined( facet, value ) ) { | ||
return this.removeFacetRefinement( facet, value ); | ||
} | ||
else { | ||
return this.addFacetRefinement( facet, value ); | ||
} | ||
toggleDisjunctiveFacetRefinement : function toggleDisjunctiveFacetRefinement( facet, value ) { | ||
return this.setQueryParameters( { | ||
page : 0, | ||
disjunctiveFacetsRefinements : RefinementList.toggleRefinement( this.disjunctiveFacetsRefinements, facet, value ) | ||
} ); | ||
}, | ||
/** | ||
* Switch the refinement applied over a facet/value | ||
* Switch the tag refinement | ||
* @method | ||
* @param {string} facet | ||
* @param {value} value | ||
* @param {string} tag the tag to remove or add | ||
* @return {SearchParameters} | ||
*/ | ||
toggleExcludeFacetRefinement : function toggleExcludeFacetRefinement( facet, value ) { | ||
if( this.isExcludeRefined( facet, value ) ) { | ||
return this.removeExcludeRefinement( facet, value ); | ||
toggleTagRefinement : function toggleTagRefinement( tag ) { | ||
if( this.isTagRefined( tag ) ) { | ||
return this.removeTagRefinement( tag ); | ||
} | ||
else { | ||
return this.addExcludeRefinement( facet, value ); | ||
return this.addTagRefinement( tag ); | ||
} | ||
}, | ||
/** | ||
* Switch the refinement applied over a facet/value | ||
* Test if the facet name is from one of the disjunctive facets | ||
* @method | ||
* @param {string} facet | ||
* @param {value} value | ||
* @return {SearchParameters} | ||
* @param {string} facet facet name to test | ||
* @return {boolean} | ||
*/ | ||
toggleDisjunctiveFacetRefinement : function toggleDisjunctiveFacetRefinement( facet, value ) { | ||
if( this.isDisjunctiveFacetRefined( facet, value ) ) { | ||
return this.removeDisjunctiveFacetRefinement( facet, value ); | ||
} | ||
else { | ||
return this.addDisjunctiveFacetRefinement( facet, value ); | ||
} | ||
isDisjunctiveFacet : function( facet ) { | ||
return this.disjunctiveFacets.indexOf( facet ) > -1; | ||
}, | ||
/** | ||
* Returns true if the couple (facet, value) is refined | ||
* Test if the facet name is from one of the conjunctive/normal facets | ||
* @method | ||
* @param {string} facet | ||
* @param {string} value | ||
* @param {string} facet facet name to test | ||
* @return {boolean} | ||
*/ | ||
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 facetting | ||
* @param {string} value, optionnal value. If passed will test that this value | ||
* is filtering the given facet. | ||
* @return {boolean} returns true if refined | ||
*/ | ||
isFacetRefined : function isFacetRefined( facet, value ) { | ||
return this.facetsRefinements[ facet ] && | ||
this.facetsRefinements[ facet ].indexOf( value ) !== -1; | ||
return RefinementList.isRefined( this.facetsRefinements, facet, value ); | ||
}, | ||
/** | ||
* Returns true if the couple (facet, value) is excluded | ||
* Returns true if the facet contains exclusions or if a specific value is | ||
* excluded | ||
* @method | ||
* @param {string} facet | ||
* @param {string} value | ||
* @return {boolean} | ||
* @param {string} facet name of the attribute for used for facetting | ||
* @param {string} value, optionnal value. If passed will test that this value | ||
* is filtering the given facet. | ||
* @return {boolean} returns true if refined | ||
*/ | ||
isExcludeRefined : function isExcludeRefined( facet, value ) { | ||
return this.facetsExcludes[ facet ] && | ||
this.facetsExcludes[ facet ].indexOf( value ) !== -1; | ||
return RefinementList.isRefined( this.facetsExcludes, facet, value ); | ||
}, | ||
/** | ||
* Returns true if the couple (facet, value) is refined | ||
* Returns true if the facet contains a refinement, or if a value passed is a | ||
* refinement for the facet. | ||
* @method | ||
* @param {string} facet | ||
* @param {string} value | ||
* @param {string} facet name of the attribute for used for facetting | ||
* @param {string} value optionnal, will test if the value is used for refinement | ||
* if there is one, otherwise will test if the facet contains any refinement | ||
* @return {boolean} | ||
*/ | ||
isDisjunctiveFacetRefined : function isDisjunctiveFacetRefined( facet, value ) { | ||
return this.disjunctiveFacetsRefinements[ facet ] && | ||
this.disjunctiveFacetsRefinements[ facet ].indexOf( value ) !== -1; | ||
return RefinementList.isRefined( this.disjunctiveFacetsRefinements, facet, value ); | ||
}, | ||
/** | ||
* Test if the triple attribute operator value is already refined. | ||
* @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( isUndefined( value ) ) { | ||
return this.numericRefinements[ attribute ] && | ||
!isUndefined( this.numericRefinements[ attribute ][ operator ] ); | ||
} | ||
return this.numericRefinements[ attribute ] && | ||
!( isUndefined( this.numericRefinements[ attribute ][ operator ] ) ) && | ||
this.numericRefinements[ attribute ][ operator ] === value; | ||
}, | ||
/** | ||
* Returns true if the tag refined, false otherwise | ||
* @method | ||
* @param {string} tag the tag to check | ||
* @return {boolean} | ||
*/ | ||
isTagRefined : function isTagRefined( tag ) { | ||
return this.tagRefinements.indexOf( tag ) !== -1; | ||
}, | ||
/** | ||
* Returns the list of all disjunctive facets refined | ||
* @method | ||
* @param {string} facet | ||
* @param {value} value | ||
* @param {string} facet name of the attribute used for facetting | ||
* @param {value} value value used for filtering | ||
* @return {string[]} | ||
*/ | ||
getRefinedDisjunctiveFacets : function getRefinedDisjunctiveFacets() { | ||
// attributes used for numeric filter can also be disjunctive | ||
var disjunctiveNumericRefinedFacets = intersection( | ||
@@ -655,10 +786,6 @@ keys( this.numericRefinements ), | ||
getUnrefinedDisjunctiveFacets : function() { | ||
var unrefinedFacets = []; | ||
var refinedFacets = this.getRefinedDisjunctiveFacets(); | ||
forEach( this.disjunctiveFacets, function( f ) { | ||
if( refinedFacets.indexOf( f ) === -1 ) { | ||
unrefinedFacets.push( f ); | ||
} | ||
return filter( this.disjunctiveFacets, function( f ) { | ||
return refinedFacets.indexOf( f ) === -1; | ||
} ); | ||
return unrefinedFacets; | ||
}, | ||
@@ -668,3 +795,3 @@ managedParameters : [ | ||
"facetsExcludes", "disjunctiveFacetsRefinements", | ||
"numericRefinements" | ||
"numericRefinements", "tagRefinements" | ||
], | ||
@@ -682,13 +809,72 @@ getQueryParams : function getQueryParams() { | ||
/** | ||
* Let the user retrieve any parameter value from the SearchParameters | ||
* @param {string} paramName name of the parameter | ||
* @return {any} the value of the parameter | ||
*/ | ||
getQueryParameter : function getQueryParameter( paramName ) { | ||
if( !this.hasOwnProperty( paramName ) ) throw new Error( "Parameter '" + paramName + "' is not an attribute of SearchParameters (http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html)" ); | ||
return this[ paramName ]; | ||
}, | ||
/** | ||
* 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. | ||
* It won't let the user define custom properties. | ||
* @method | ||
* @param {object} params all the keys and the values to be updated | ||
* @return {SearchParameters} a new updated instance | ||
*/ | ||
setQueryParameters : function setQueryParameters( params ) { | ||
var error = SearchParameters.validate( this, params ); | ||
if( error ) { | ||
throw error; | ||
} | ||
return this.mutateMe( function merge( newInstance ) { | ||
var ks = keys( params ); | ||
forEach( ks, function( k ) { | ||
newInstance[ k ] = params[ k ]; | ||
} ); | ||
return newInstance; | ||
} ); | ||
}, | ||
/** | ||
* Helper function to make it easier to build new instances from a mutating | ||
* function | ||
* @private | ||
* @param {function} fn newMutableState -> previousState -> () function that will | ||
* change the value of the newMutable to the desired state | ||
* @return {SearchParameters} a new instance with the specified modifications applied | ||
*/ | ||
mutateMe : function mutateMe( fn ) { | ||
var newState = new ( this.constructor )( this ); | ||
fn( newState ); | ||
return Object.freeze( newState ); | ||
fn( newState, this ); | ||
return deepFreeze( newState ); | ||
} | ||
}; | ||
/** | ||
* Callback used for clearRefinement method | ||
* @callback SearchParameters.clearCallback | ||
* @param {OperatorList|FacetList} value | ||
* @param {string} key | ||
* @param {string} type numeric, disjunctiveFacet, conjunctiveFacet or exclude | ||
* depending on the type of facet | ||
* @return {boolean} | ||
*/ | ||
module.exports = SearchParameters; |
"use strict"; | ||
var forEach = require( "lodash/collection/forEach" ); | ||
var compact = require( "lodash/array/compact" ); | ||
var sum = require( "lodash/collection/sum" ); | ||
var find = require( "lodash/collection/find" ); | ||
@@ -9,3 +10,3 @@ | ||
/** | ||
* @typedef Facet | ||
* @typedef SearchResults.Facet | ||
* @type {object} | ||
@@ -79,3 +80,3 @@ * @property {string} name name of the attribute in the record | ||
*/ | ||
this.processingTimeMS = mainSubResponse.processingTimeMS; | ||
this.processingTimeMS = sum( algoliaResponse.results, "processingTimeMS" ); | ||
/** | ||
@@ -173,3 +174,3 @@ * disjunctive facets results | ||
* @param {string} name name of the attribute facetted | ||
* @return {Facet} the facet object | ||
* @return {SearchResults.Facet} the facet object | ||
*/ | ||
@@ -176,0 +177,0 @@ SearchResults.prototype.getFacetByName = function( name ) { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1879784
62
2584
16
1
79
+ Addedlodash@3.9.3(transitive)
- Removedlodash@3.5.0(transitive)
Updatedlodash@3.9.x