New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

doofinder

Package Overview
Dependencies
Maintainers
1
Versions
198
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

doofinder

Javascript Library for Doofinder Search API

  • 5.2.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
128
increased by141.51%
Maintainers
1
Weekly downloads
 
Created
Source

Build Status

Doofinder Library

A.K.A. js-doofinder, or just doofinder, this library makes easy to perform requests to Doofinder's search service and customize the way you present results.

Installation

The library can be installed via package managers or directly pointing to a file in jsDelivr's CDN.

The package offers simple CSS you can obtain from the dist directory. It will help you to build a scaffolding of your project with little effort.

NPM

$ npm install doofinder

Bower

$ bower install doofinder

CDN

You can include the library directly in your website:

<!-- Javascript -->
<script src="//cdn.jsdelivr.net/npm/doofinder@latest/dist/doofinder.min.js"></script>
<!-- CSS -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/doofinder@latest/dist/doofinder.css">

TL;DR

If you only want to know how this is structured, without the details, here we go.

The library provides:

  • A Client class to perform requests to the Doofinder service.
  • A Controller class which provides an easy-to-use wrapper for the client and holds Widget instances that will process the response from the service.
  • A collection of widgets which render HTML somewhere given a JSON search response, and provide a user interface to present results or refine search.
  • A collection of utilities, like DOM manipulation, introspection, throttling… and that kind of stuff.

Quick Start

The project includes a demo you can use as inspiration. To take a look and see things you can do with it:

  1. Download the entire project from Github.
  2. Install Grunt if not previously installed.
  3. From the root of the project:
    1. install dependencies with $ npm install.
    2. Run the demo server with $ grunt serve.
  4. Open http://localhost:8008 in your browser.

The demo markup is inside index.html and the related Javascript code can be found at demo/demo.js.

NOTICE: The demo uses a test search engine but you can use a different one, just change the value of the HASHID variable you will find inside index.html.

IMPORTANT: Doofinder protects API calls with CORS. If you change the HASHID variable defined in index.html you will have to allow localhost for your search engine in Doofinder Admin.

Client Reference

FOR THE SAKE OF SIMPLICITY THIS REFERENCE ONLY DESCRIBES CHANGES FOR CHILD CLASSES.

doofinder.Client

This class just make requests to Doofinder's Search API.

constructor

The client needs to know the search engine to use (hashid, the first parameter), and the search zone to use.

If you are using the client in a browser, your requests are protected by CORS so you will use the zone parameter only.

var client = new doofinder.Client("dd485e41f1758def296e1bc7377f8ea7", {
  zone: "eu1"
});

However, if your requests are made server to server, you will have to authenticate requests with an API key which contains both the zone and a secret. In that case you can use the apiKey option and omit the zone.

var client = new doofinder.Client("dd485e41f1758def296e1bc7377f8ea7", {
  apiKey: "eu1-4d186321c1a7f0f354b297e8914ab240"
});

To learn more about authentication read the Search API documentation.

Arguments
ArgumentRequiredTypeDescription
hashidYesString32-char, unique id of a search engine.
optionsYesObject
Options

One of zone and apiKey options are required. If both are set, search zone is extracted from apiKey.

OptionRequiredTypeValuesDefaultDescription
zoneYes*Stringeu1
us1
Search zone.
apiKeyYes*StringSecret to authenticate requests.
addressNoStringSearch server address.
For development purposes.
versionNoString"5"Search API version.
For development purposes.
Client.request()

Performs a HTTP(S) GET request to the given resource of the Doofinder search API and passes any error or response to the provided callback function.

client.request("/5/search?query=something", function(err, res){
  return (err ? processError(err) : processResponse(res));
});
Arguments
ArgumentRequiredTypeDescription
resourceYesStringAPI endpoint. Parameters are sent in the URL.
callbackYesFunctionCallback to be called.
Client.search()

Performs a search request to the Doofinder search API and passes any error or response to the provided callback function.

Can be called with 2 or 3 arguments:

client.search("something", processResponse);
client.search("something", {page: 2}, processResponse);
Arguments
ArgumentRequiredTypeDescriptionSample
queryYesStringSearch terms
paramsNoObjectParameters sent in the URL.{page: 1, rpp: 20}
callbackYesFunctionCallback to be called.

Read the Search API reference to learn more about available parameters.

Client.options()

Performs a request to get preferences for the search engine from the Doofinder server.

Can be called with 1 or 2 arguments:

client.options(processOptions);
client.options("localhost", processOptions);
Arguments
ArgumentRequiredTypeDescriptionSample
suffixNoStringOptional suffix to add to the request URL, like the domain of the current page.localhost
callbackYesFunctionCallback to be called.
Client.stats()

Performs a request to submit stats events to Doofinder.

// usage sample
client.stats("click", {
  dfid: "4d186321c1a7f0f354b297e8914ab240@product@437b930db84b8079c2dd804a71936b5f",
  session_id: "21d6f40cfb511982e4424e0e250a9557",
  query: "something"
}, processResponse);

NOTICE: You may want to use the stats wrapper included in the library instead of calling this method directly.

Arguments

| Argument | Required | Type | Description | | :--- | :---: | :---: | :--- | :--- | | eventName | Yes | String | Name of the event you want to send. | | params | Yes* | Object | Parameters sent in the URL.
Most events need parameters but it depends on the event. | | callback | No | Function | Callback to be called. |

Read the Search API reference to learn more about computing stats.

Controller Reference

doofinder.Controller

This class is aimed to easily search and display search results in a browser, managing search status and providing search results pagination capabilities.

Search status includes:

  • Current page: Is always 1 when a fresh search is done.
  • Last page available for the current query.
  • Query name: Name of the query that Doofinder found that gave the best results so retrieving subsequent pages of results will use the same query.
  • Query counter: to keep track of the requests made and maintain order.
  • Request done: Whether a search request has been made or not.
constructor

This class uses a Client to retrieve search results, and some widgets to paint results in the user interface.

Can be instantiated with a Client instance:

controller = new doofinder.Controller(client);

But you can also pass extra parameters that will be sent in search requests:

controller = new doofinder.Controller(client, {rpp: 20});
Arguments
ArgumentRequiredTypeDescription
clientYesdoofinder.ClientSearch client instance.
paramsNoObjectParameters to be added to all requests by default.

Read the Search API reference to learn more about available parameters.

Controller.hashid

Shortcut property that returns the hashid of the search engine being used.

controller.hashid // "dd485e41f1758def296e1bc7377f8ea7"
Controller.isFirstPage

Returns a boolean indicating if the last search performed by the controller was for the first page of results (false if no request was done).

controller.isFirstPage // true, false
Controller.isLastPage

Returns a boolean indicating if the last search performed by the controller was for the last page of results (false if no request was done). If true, there's no next page of results for the current set of search parameters.

controller.isLastPage // true, false
Controller.lastPage

Number of the last page available for the current search status. If no search was done returns null.

Controller.search()

Performs a new search request, removing any non-default parameters and resetting parameters to the defaults (like the page number, reset to 1).

controller.search("shirt", {filter: {brand: "NIKE"}});
Arguments
ArgumentRequiredTypeDescriptionSample
queryYesStringSearch terms
paramsNoObjectParameters sent in the URL.{page: 1, rpp: 20}

Read the Search API reference to learn more about available parameters.

Controller.getNextPage()

Given that a previous search request was done, performs a new search request to get the next page of results for the current status. Useful for infinite scroll behavior.

Controller.getPage()

Given that a previous search request was done, performs a new search request to get certain page of results for the current status. Useful for page by page pagination.

Arguments
ArgumentRequiredTypeDescription
pageYesIntegerNumber of the page of results to fetch.
Controller.refresh()

Given that a previous search request was done, performs a new search request to get the first page of results for the current status. Useful to start over again the current search.

Controller.reset()

Resets status and optionally forces search query terms and parameters to be set. Because it is a reset aimed to perform a new search, page has always value 1 when executing this.

Arguments
ArgumentRequiredTypeDescriptionSample
queryNoStringSearch terms"something"
paramsNoObjectParameters sent in the URL.{page: 1, rpp: 20}

Read the Search API reference to learn more about available parameters.

Controller.getParam()

Returns the value of a parameter from the status.

controller.getParam("transformer");
Arguments
ArgumentRequiredTypeDescription
keyYesStringName of the parameter to retrieve.
Controller.setParam()

Sets the value of a parameter in the status hash.

controller.setParam("transformer", null);
Arguments
ArgumentRequiredTypeDescription
keyYesStringName of the parameter to set.
valueYes*Value of the parameter to set.
Can be anything serializable in a URL querystring.
Controller.removeParam()

Removes a parameter from the status hash.

controller.removeParam("transformer");
Arguments
ArgumentRequiredTypeDescription
keyYesStringName of the parameter to remove.
Controller.getFilter()

Retrieves the value of a filter or undefined if not defined.

controller.getFilter("brand");
Arguments
ArgumentRequiredTypeDescription
keyYesStringFilter name.
paramNameNoStringName of the parameter that will hold the filters.
"filter" by default.
Controller.setFilter()

Sets the value of a filter, replacing any existing value.

// terms
controller.setFilter("brand", "NIKE"); // ["NIKE"]
controller.setFilter("brand", ["ADIDAS", "PUMA"]) // ["ADIDAS", "PUMA"]
// range
controller.setFilter("price", {gte: 10})
Arguments
ArgumentRequiredTypeDescription
keyYesStringFilter name.
valueYes*If is a string, it's added as a one-item array.
Otherwise, it's added with no modifications.
paramNameNoStringName of the parameter that will hold the filters.
"filter" by default.
Controller.addFilter()

Extends the current value of a filter with the provided value.

This means:

  • If the filter does not already exist, the value is added like in Controller.setFilter().
  • If the filter already exists and is an array:
    • If the value is a single value, it is added to the array if not already there.
    • If the value is an array, only items not already in the filter are added.
  • If the filter already exists, is a plain object and the value is also a plain object, new value is merged taking care of range incompatibilities.
  • In any other case the new value replaces the existing one.
controller.addFilter("brand", "NIKE"); // ["NIKE"]
controller.addFilter("brand", ["NIKE", "ADIDAS"]);  // ["NIKE", "ADIDAS"]
controller.addFilter("brand", "PUMA");  // ["NIKE", "ADIDAS", "PUMA"]

controller.addFilter("price", {gt: 10}); // {gt: 10}
controller.addFilter("price", {gte: 10, lte: 100}); // {gte: 10, lte: 100}

controller.addFilter("price", "ASICS"); // ["ASICS"]
Arguments
ArgumentRequiredTypeDescription
keyYesStringFilter name.
valueYes*Value to be added to the filter.
paramNameNoStringName of the parameter that will hold the filters.
"filter" by default.
Controller.removeFilter()

Removes a value from a filter or the entire filter if no value was provided.

  • If filter is currently stored in an array:
    • If a single value is provided, it is removed from the filter if it is in the array.
    • If an array is provided, all matching values are removed from the filter.
    • Passing an object is a wrong use case, don't do it.
  • If values are stored in a plain Object:
    • If a single value is provided, it is considered an existing key of the filter object, and it is removed.
    • If a plain object is provided, common keys are removed from the filter.
    • Passing an array is a wrong use case, don't do it.
  • If no value is passed, the entire filter is removed.
  • In any other case, if the value matches the value of the filter, the entire filter is removed.
  • Not found values have no effect.

NOTICE: If after removing a value/key, an array/object filter become empty, then the entire filter is removed from the filters list.

controller.setFilter("brand", ["NIKE", "ADIDAS", "PUMA"]);
controller.removeFilter("brand"); // REMOVED

controller.setFilter("brand", ["NIKE", "ADIDAS", "PUMA"]);
controller.removeFilter("brand", "NIKE"); // ["ADIDAS", "PUMA"]
controller.removeFilter("brand", ["ADIDAS", "PUMA"]); // REMOVED

controller.setFilter("price", {gte: 10, lte: 100});
controller.removeFilter("price", "gte"); // {lte: 100}
controller.removeFilter("price", {lte: 100}); // REMOVED
Arguments
ArgumentRequiredTypeDescription
keyYesStringField name.
valueNo*
paramNameNoStringName of the parameter that will hold the filters.
"filter" by default.
Controller.getExclusion()

Works the same as Controller.getFilter() but for filters that explicitly exclude results (negative filters).

Controller.setExclusion()

Works the same as Controller.setFilter() but for filters that explicitly exclude results (negative filters).

Controller.addExclusion()

Works the same as Controller.addFilter() but for filters that explicitly exclude results (negative filters).

Controller.removeExclusion()

Works the same as Controller.removeFilter() but for filters that explicitly exclude results (negative filters).

Controller.registerWidget()

Registers a widget in the current controller instance.

controller.registerWidget(myWidget);

NOTICE: Widget registration is a two-way binding. The widget gets registered in the controller and the controller gets registered in the widget.

Arguments
ArgumentRequiredTypeDescription
widgetYesWidgetAn instance of Widget (or any of its subclasses).
Controller.registerWidgets()

Registers multiple widgets at the same time in the current controller instance.

controller.registerWidgets([myInputWidget, myResultsWidget]);

NOTICE: Widget registration is a two-way binding. The widget gets registered in the controller and the controller gets registered in the widget.

Arguments
ArgumentRequiredTypeDescriptionSample
widgetsYesArrayAn array of Widget (or any of its subclasses) instances.
Controller.renderWidgets()

Makes registered widgets render themselves with the provided search response.

controller.renderWidgets(response);

NOTICE: Triggers a df:controller:renderWidgets event on the controller when the render() method of all widgets has been executed.

Arguments

| Argument | Required | Type | Description | | :--- | :---: | :---: | :--- | :--- | | response | Yes | Object | A search response from Doofinder service. |

Controller.cleanWidgets()

Makes registered widgets clean themselves.

controller.cleanWidgets();

NOTICE: Triggers a df:controller:cleanWidgets event on the controller when the clean() method of all widgets has been executed.

Controller.clean()

Resets status and clean widgets at the same time.

controller.clean();

// The same as:
controller.reset();
controller.cleanWidgets();
Controller.serializeStatus()

Returns the current status of the controller as a URL querystring. Useful to save it somewhere and recover later.

controller.serializeStatus();
// "query=running&query_name=match_and
// &filter%5Bcategories%5D%5B0%5D=Cardio&filter%5Bbrand%5D%5B0%5D=BH"
Controller.loadStatus()

Changes the status of the controller based on the value of the parameter provided, and performs a search request.

controller.loadStatus(
  "query=running&query_name=match_and" +
  "&filter%5Bcategories%5D%5B0%5D=Cardio" +
  "&filter%5Bbrand%5D%5B0%5D=BH"
);
/*
{
  filter: {
    brand: ["BH"],
    categories: ["Cardio"]
  },
  query: "running",
  query_name: "match_and"
}
*/
Arguments
ArgumentRequiredTypeDescription
statusYesStringController status obtained from serializeStatus
Controller.on()

Registers a function that is executed when certain event is triggered on the controller.

controller.on("df:controller:renderWidgets", myHandlerFn);
controller.on("event1 event2", myHandlerFn);
Arguments
ArgumentRequiredTypeDescription
eventNameYesStringEvent name (or multiple events, space separated).
handlerYesFunctionThe callback function.
Controller.one()

Registers a function that is executed when certain event is triggered on the controller the first time after this function is executed.

controller.one("df:controller:renderWidgets", myHandlerFn);
controller.one("event1 event2", myHandlerFn);
Arguments
ArgumentRequiredTypeDescription
eventNameYesStringEvent name (or multiple events, space separated).
handlerYesFunctionThe callback function.
Controller.off()

Unregisters an event handler of this controller.

  • If no handler is provided, all event handlers for the event name provided are unregistered for the current controller.
  • If no handler and no event name are provided, all event handlers are unregistered for the current controller.
controller.off("df:controller:renderWidgets", myHandlerFn);
controller.off("df:controller:renderWidgets");
controller.off();
Arguments
ArgumentRequiredTypeDescription
eventNameNoStringEvent name (or multiple events, space separated).
handlerNoFunctionThe callback function.
Controller.trigger()

Triggers an event in the current controller.

ArgumentRequiredTypeDescription
eventNameYesStringEvent name (or multiple events, space separated).
argsNoArrayArray of arguments to pass to the event handler.
Events

You can listen and trigger several events on a Controller instance, here's a summary of them.

df:search

Triggered when a new search is done.

| Argument | Type | Description | | : --- | : --- : | : --- | | query | String | Search terms for the current search. | | params | Object | Search parameters defined in the controller for the new search. |

df:search:page

Triggered when a new page for the current search is requested.

| Argument | Type | Description | | : --- | : --- : | : --- | | query | String | Search terms for the current search. | | params | Object | Search parameters defined in the controller for the current search. |

df:refresh

Triggered when the current search is refreshed to get the first page again.

| Argument | Type | Description | | : --- | : --- : | : --- | | query | String | Search terms for the current search. | | params | Object | Search parameters defined in the controller for the current search. |

df:results:success

Triggered when a successful search response is received. This event is triggered after the response has been processed.

| Argument | Type | Description | | : --- | : --- : | : --- | | response | Object | Valid response from the Doofinder service. |

df:results:error

Triggered when there is an error in the search request.

| Argument | Type | Description | | : --- | : --- : | : --- | | error | Object | See below for details. |

Errors coming from the Doofinder servers

When the error comes from the server, it has a status code and, optionally, a message explaining the error.

{
    statusCode: 400,
    error: "Invalid hashid"
}
Errors during the request

Errors occurred during the request phase have an error key containing the instance of Error thrown.

{
   error: new Error("Whatever");
}
df:results:end

Triggered when a successful search response for the last page of the current search is received. This event is triggered after the response has been processed.

| Argument | Type | Description | | : --- | : --- : | : --- | | response | Object | Valid response from the Doofinder service. |

df:controller:renderWidgets

Triggered when the controller called the render() method of all widgets.

df:controller:cleanWidgets

Triggered when the controller called the clean() method of all widgets.

Widgets Reference

doofinder.widgets.Widget

This class provides the scaffolding of any widget, all widgets inherit from this class.

A widget is linked to:

  • A DOM element.
  • A Controller.

Widgets make extensive use of a DOM manipulation mini-library included in this package and called dfdom.

References to a widget's DOM element are stored as an instance of DfDomElement.

constructor

The constructor receives a reference to a DOM element and an Object with options.

var widget = new doofinder.widgets.Widget("#element", {});

NOTICE: Constructor signature and options may vary from a Widget subclass to another. Consult the reference of each class to know the proper values of the constructor and options object.

Arguments
ArgumentRequiredTypeDescriptionSample
elementYesStringCSS Selector."#widget"
NodeDirect reference to a DOM Node.document.querySelector('#widget')
DfDomElementReference to a DOM node via dfdom.dfdom('#widget')
optionsNoObjectOptions object.
Widget.setElement()

This method is responsible of configuring the element passed to the constructor as the element attribute of the Widget.

widget.setElement("#widget");

99.9% of time this method is used as is but can be customized to assign a different container element to the widget.

Arguments
ArgumentRequiredTypeDescriptionSample
elementYesStringCSS Selector."#widget"
NodeDirect reference to a DOM Node.document.querySelector('#widget')
DfDomElementReference to a DOM node via dfdom.dfdom('#widget')
Widget.setController()

Assigns a controller to the widget, so the widget can get access to the status of the search or directly manipulate the search through the controller, if needed.

This method is called by the Controller when a widget is registered. Usually a widget is only registered in one controller but you can extend this method to change this behavior.

Arguments
ArgumentRequiredTypeDescriptionSample
controllerYesController
Widget.init()

Initializes the widget. Intended to be extended in child classes, this method should be executed only once. This is enforced by the initialized attribute. You will want to add your own event handlers inside this method.

This method is called as part of the widget registration process that happens in the Controller.

Widget.render()

This method is responsible of the rendering of the widget with the search response received from the server.

The Widget base class does not have visual representation by default so this method just triggers the df:widget:render event.

Arguments
ArgumentRequiredTypeDescription
responseYesObjectValid response from the Doofinder service.
Widget.clean()

This method is responsible of the cleaning the HTML of the widget.

The Widget base class does not have visual representation by default so this method just triggers the df:widget:clean event.

Widget.on()

Registers a function that is executed when certain event is triggered on the widget.

Arguments
ArgumentRequiredTypeDescription
eventNameYesStringEvent name (or multiple events, space separated).
handlerYesFunctionThe callback function.
Widget.one()

Registers a function that is executed when certain event is triggered on the widget the first time after this function is executed.

Arguments
ArgumentRequiredTypeDescription
eventNameYesStringEvent name (or multiple events, space separated).
handlerYesFunctionThe callback function.
Widget.off()

Unregisters an event handler of a widget.

  • If no handler is provided, all event handlers for the event name provided are unregistered for the current widget.
  • If no handler and no event name are provided, all event handlers are unregistered for the current widget.
Arguments
ArgumentRequiredTypeDescription
eventNameNoStringEvent name (or multiple events, space separated).
handlerNoFunctionThe callback function.
Widget.trigger()

Triggers an event on the widget.

ArgumentRequiredTypeDescription
eventNameYesStringEvent name (or multiple events, space separated).
argsNoArrayArray of arguments to pass to the event handler.
Events
df:widget:init

Triggered when the widget has ended its initialization (init() method called). The event handler receives no arguments.

df:widget:render

Triggered when the widget has finished rendering itself with the provided search response.

widget.on("df:widget:render", function(response){
  // do something with the response
});
Arguments
ArgumentRequiredTypeDescription
responseYesObjectA search response from Doofinder service.
df:widget:clean

Triggered when the widget has finished rendering itself. The event handler receives no arguments.


doofinder.widgets.QueryInput

Widget < QueryInput

This is a special widget. It is linked to a HTML text input control and listens the input event so, when value changes due to user input, it uses its value to perform a new search via its registered controller(s).

This widget can be registered in multiple controllers at the same time so you could share the same text input and perform the same search in different search engines.

constructor
var queryInput = new doofinder.widgets.QueryInput('#search', {
    captureLength: 4
});
Options
OptionRequiredTypeValuesDefaultDescription
cleanNoBooleantrueIf true the input is cleared when the widget is cleaned.
captureLengthNoNumber3Minimum number of characters to type to perform a search request.
typingTimeoutNoNumber1000Time in milliseconds the widget waits before triggering the df:input:stop event.
waitNoNumber42Time in milliseconds the widget waits before checking input to decide whether to perform a search or not.
High values (400) reduce the number of requests sent.
Events
df:input:submit

This event is triggered when the user types ENTER on the search input control.

NOTICE: This event is not triggered for TEXTAREA controls.

queryInput.on("df:input:submit", function(value){
  // do something with value
});
Arguments
ArgumentRequiredTypeDescription
valueYesStringValue of the input control.
df:input:stop

This event is triggered after some time determined by the value typingTimeout in the widget options, when the user stops typing.

queryInput.on("df:input:stop", function(value){
  // do something with value
});
Arguments
ArgumentRequiredTypeDescription
valueYesStringValue of the input control.
df:input:none

This event is triggered during the value checking process, if the input changed from having a value to being empty. The event handler receives no arguments.

queryInput.on("df:input:none", function(){
  // hide results?
});

doofinder.widgets.Display

Widget < Display

This is a widget with actual rendering capabilities:

  • It renders HTML inside its element node given a search response. Rendering is done with the Mustache engine.
  • It populates variables and helpers (default and custom) to be used in the template.
  • It cleans its element from unnecessary HTML code when the widget itself is cleaned.
constructor

Constructor now accepts options for templating.

<script type="text/x-mustache-template" id="myTemplate">
  <ul>
    <li>{{#translate}}Hello!{{/translate}}</li>
    <li>Meaning of life is {{meaningOfLife}}!</li>
  {{#results}}
    <li>{{#bold}}{{title}}{{/bold}}</li>
  {{/results}}
  </ul>
</script>
var display = new doofinder.widgets.Display("#myDiv", {
  template: document.getElementById('myTemplate').innerHTML,
  templateFunctions: {
    bold: function() {
      return function(text, render) {
        return "<b>" + render(text) + "</b>";
      }
    }
  },
  templateVars: {
    meaningOfLife: 42
  },
  translations: {
    "Hello!": "Hola!"
  }
});
Options
OptionRequiredTypeDefaultDescription
templateYesStringHTML template to render the search response.
templateFunctionsNoString{}An Object whose keys are the name of Mustache template helpers.
templateVarsNoString{}An Object whose keys are the name of Mustache variables.
translationsNoString{}An Object mapping strings to be replaced by other values when found inside the default translate helper.
Default Template
{{#results}}
  <a href="{{link}}" class="df-card">{{title}}</a>
{{/results}}
Default Template Variables

Some template variables are included by default in the rendering context:

| Variable | Type | Description | | : --- | : --- : | : --- | | is_first | Boolean | Indicates if the response being rendered is for the first page of a search. | | is_last | Boolean | Indicates if the response being rendered is for the last page of a search. |

Default Template Functions

Some template functions are included by default in the rendering context:

| Function | Description | | : --- | : --- | | translate | If a match is found in the translations dictionary of the widget, the text inside the helper is replaced by its translation. |


doofinder.widgets.ScrollDisplay

Widget < Display < ScrollDisplay

You can use this class to render subsequent responses for the same search one after another by appending HTML instead of replacing it. HTML is replaced for the first page of a search only.

When the user performs scrolling and reaches the end of the results, a new search page is automatically requested.

IMPORTANT: Scrolling content inside a <div> (or similar node) requires width / height being restricted so the content overflows the container instead of the latter adapts to its content. Also, setting overflow-x and overflow-y properties in CSS will enforce these rules.

constructor
<style>
.container {
  width: 400px;
  height: 600px;
  overflow-x: hidden;
  overflow-y: auto;
}
</style>
<div class="container" id="scroller">
  <div class="container-header">Search Results</div>
  <ul class="container-content"></ul>
</div>
<script type="text/x-mustache-template" id="scroller-template">
  {{#results}}
    <li><a href="{{link}}" class="df-card">{{title}}</a></li>
  {{/results}}
</script>
var resultsWidget = new doofinder.widgets.ScrollDisplay("#scroller", {
  contentElement: ".container-content",
  template: document.getElementById('scroller-template').innerHTML
});
Options

This widgets receives the same options as Display, plus:

| Option | Required | Type |Default | Description | | :--- | :---: | :---: | | :--- | | contentElement | No | String | null | Reference to a child node of the widget's element. By default the widget's element node contains the HTML rendered by the widget. | | offset | No | Number | 300 | Distance in pixels to the bottom of the content. As soon as the scrolled content reaches this value, a new results page is requested. | | throttle | No | Number | 16 | Time in milliseconds to wait between scroll checks. This value limits calculations associated to the scroll event. | | horizontal | No | Boolean | false | If true, scroll calculations are done for horizontal scrolling. By default calculations are done for vertical scrolling. |

IMPORTANT: Don't rely on the widget's element attribute to do stuff with the container, if you use the contentElement option, that node will internally become the element node. To access the container always use the container attribute.

Events
df:widget:scroll

This event is triggered each time scrolling calculations are made.

resultsContainer.on("df:widget:scroll", function(scrollTop, direction){
  // Do something with scrollTop and direction.
});

| Argument | Type | Values |Description | | : --- | : --- : | : --- : | : --- | | scrollTop | Number || The number of pixels the content is scrolled vertically. | | direction | String | "up", "down" | The direction of the scrolling. |


doofinder.widgets.TermsFacet

Widget < Display < TermsFacet

This widget allows filtering search results by certain text values of a field. When a term is clicked, the widget forces its controller to perform a new search filtered by the value of the facet.

constructor
var facet = new doofinder.widgets.TermsFacet("#brandFilter", "brand");
ArgumentRequiredTypeDescription
elementYesStringCSS Selector.
NodeDirect reference to a DOM Node.
DfDomElementReference to a DOM node via dfdom.
facetYesStringName of the facet as returned by the server in the facet specification.
optionsNoObjectOptions object.
Default Templates
template

This is the default template of the widget.

{{#terms}}
  <div class="df-term" data-facet="{{name}}" data-value="{{key}}"
      {{#selected}}data-selected{{/selected}}>
    <span class="df-term__value">{{key}}</span>
    <span class="df-term__count">{{doc_count}}</span>
  </div>
{{/terms}}

There're some data attributes that must be present for the widget to work properly:

| Attribute | Description | | : --- | : --- | | data-facet | Holds the name of the current facet as defined in Doofinder. | | data-value | Holds the value of the term. | | data-selected | Indicates whether the term is selected or not. |

The variables available for each term are:

| Variable | Description | | : --- | : --- | | name | Holds the name of the current facet as defined in Doofinder. | | key | Holds the value of the term. | | selected | Indicates whether the term is selected or not. | | doc_count | Indicates the number of results when filtering the current search results by this term. |


doofinder.widgets.CollapsibleTermsFacet

Widget < Display < TermsFacet < CollapsibleTermsFacet

This is a TermsFacet widget that provides a collapsing feature out of the box so, if you receive 20 terms to filter, you can display 10 and hide the rest until the user choose to display them by pressing a button.

Check out the advanced example in the Demo to see how it works.

NOTICE: Collapsing feature is handled in HTML and CSS via HTML data attributes. If you change the template and want to preserve this behavior, remember to use specific CSS found in doofinder.css and attributes defined in the default templates.

constructor
var facet = new doofinder.widgets.CollapsibleTermsFacet("#brandFilter", "brand", {
    size: 5,
    startCollapsed: false,
    templateVars: {
        viewMoreLabel: "Expand",
        viewLessLabel: "Collapse"
    }
});
Options
OptionRequiredTypeDefaultDescription
sizeNoNumber10Maximum number of terms visible when the widget is collapsed.
startCollapsedNoBooleantrueDetermines whether the widget's default status is being collapsed or not.
buttonTemplateYesStringSee Default Templates below.
Default Templates

WARNING: Behavior is a bit complex and is recommended to limit modifications to CSS classes and minor stuff.

template

Default template of the widget.

{{#terms}}
  <div class="df-term" data-facet="{{name}}" data-value="{{key}}"
      {{#extra-content}}{{index}}{{/extra-content}}
      {{#selected}}data-selected{{/selected}}>
    <span class="df-term__value">{{key}}</span>
    <span class="df-term__count">{{doc_count}}</span>
  </div>
{{/terms}}
{{#show-more-button}}{{terms.length}}{{/show-more-button}}

This is basically the same template as in the TermsFacet class, but adds a couple of template helpers to mark terms as extra content (terms that will be hidden when the widget is collapsed), and paint the collapse toggle button.

| Function | Description | | : --- | : --- | | extra-content | Receives the index of the result in the list of results and marks the term as extra content if needed. | | show-more-button | Paints the button if there're more terms than should be visible when the widget is collapsed (uses the size option). |

Apart from those inherited from TermFacet, there're some data attributes that must be present for the widget to work properly:

| Attribute | Description | | : --- | : --- | | data-extra-content | Terms that are considered extra content get this attribute added. | | data-view-extra-content | This attribute is dynamically assigned to the widget container to indicate whether the hidden terms must be visible or not. |

buttonTemplate

Default template for the visibility toggle button.

<button type="button" data-toggle-extra-content
    data-text-normal="{{#translate}}{{viewMoreLabel}}{{/translate}}"
    data-text-toggle="{{#translate}}{{viewLessLabel}}{{/translate}}">
  {{#collapsed}}{{#translate}}{{viewMoreLabel}}{{/translate}}{{/collapsed}}
  {{^collapsed}}{{#translate}}{{viewLessLabel}}{{/translate}}{{/collapsed}}
</button>

A couple of template variables are included by default in the rendering context:

| Variable | Type | Default | Description | | : --- | : --- : | : --- : | : --- | | viewMoreLabel | String | "View more…" | Text to be rendered as the toggle button text when facets are collapsed. | | viewLessLabel | String | "View less…" | Text to be rendered as the toggle button text when all facets are visible. |

You can change them by passing different values in the options object.

There's also a data attribute that must be present for the widget to work properly:

| Attribute | Description | | : --- | : --- | | data-toggle-extra-content | Used to identify the button as the terms visibility toggle |

Events

Apart from the default events, this widget triggers the following events.

df:term:click

Triggered when a term is clicked for the current widget.

widget.on("df:term:click", function(facetName, facetValue, isSelected){
  // Do something with data
});

| Argument | Type | Description | | : --- | : --- : | : --- | | facetName | String | Name of the facet as defined in Doofinder. | | facetValue | String | Value of the term. | | isSelected | Boolean | Indicates whether the facet is selected or not. |


doofinder.widgets.RangeFacet

Widget < Display < RangeFacet

This widget provides an interface to filter results by a numeric value through a slider control.

NOTICE: Slider is managed by the excelent noUiSlider library but not all options are supported.

NOTICE: Slider needs doofinder.css to work.

constructor
var rangeWidget = new doofinder.widgets.RangeFacet("#price", {
    format: formatCurrency
});
Options
OptionRequiredTypeValuesDefaultDescription
pipsNoundefinedundefinedundefinedMakes the widget render its own pips due to a buggy behavior in noUiSlider.
BooleanfalseDisables pips.
Object
formatNoFunctionFunction to format numeric values as strings.
Default Templates

NOTICE: If you change the df-slider CSS class, remember to update CSS to match the new one.

<div class="df-slider" data-facet="{{name}}"></div>

| Variable | Type | Description | | : --- | : --- : | : --- | | name | String | Name of the facet as defined in Doofinder. |

RangeFacet.get

Gets the current range selected in the slider.

var r = rangeWidget.get();
var start = r[0];
var end = r[1];
RangeFacet.set

Sets the range selected in the slider.

rangeWidget.set([10, 100]);
Arguments
ArgumentRequiredTypeDescriptionSample
rangeYesArray2-item array of numbers.[10, 100]
Events

Apart from the default events, this widget triggers the following events.

df:range:change

Triggered when the range set in the slider changed by user input.

// min [-----------|start|------------------|end|-------] max
widget.on("df:range:change", function(value, range){
  console.log(value.start);
  console.log(value.end);
  console.log(range.min);
  console.log(range.max);
});

| Argument | Type | Description | | : --- | : --- : | : --- | | value | Object | Current selected range. | | range | Object | Valid range. |


doofinder.widgets.Panel

Widget < Display < Panel

This is a special widget. It's not used to filter anything, just as a presentational container for another widget. Useful when you want to separate widgets in sections (like facet widgets) with a label but you iterate them dynamically.

constructor
// assume facet variable obtained from the server
var panel = new doofinder.widgets.Panel("#aside", function(panel){
  var widget = new doofinder.widgets.TermsFacet(panel.contentElement, facet.name);
  widget.on("df:widget:render", function(response){
    var suffix = this.selectedTerms > 0 ? ' (' + this.selectedTerms + ')' : '';
    panel.labelElement.html(facet.label + suffix);
  });
  return widget;
}, {
  label: facet.label
});
Arguments
ArgumentRequiredTypeDescription
elementYesStringCSS Selector.
NodeDirect reference to a DOM Node.
DfDomElementReference to a DOM node via dfdom.
getFacetYesFunctionFunction that receives the panel widget instance and returns an instance of a widget that will be rendered inside the panel.
optionsNoObjectOptions object.
Options
OptionRequiredTypeValuesDefaultDescription
labelNoStringnullLabel used in the panel header. If not provided, no header will be rendered by default (unless you modify the default template).
insertionMethodYesStringappendappendHow to insert the panel inside its container. It's appended by default.
prepend
before
after
htmlThis replaces the container content and usually is not used.
Default Template
<div class="df-panel" id="{{panelElement}}">
  {{#label}}
  <div class="df-panel__label" id="{{labelElement}}">{{label}}</div>
  {{/label}}
  <div class="df-panel__content" id="{{contentElement}}"></div>
</div>

Some template variables are included by default in the rendering context:

| Variable | Type | Default | Description | | : --- | : --- : | : --- : | : --- | | panelElement | String | "df-<random>" | id of the panel container. | | labelElement | String | "df-<random>" | id of the label container. | | contentElement | String | "df-<random>" | id of the content container. |

The getFacet() Function

Used to obtain the widget in the precise moment it can be rendered (the panel must be rendered first), gives access to the panel instance, so you can make use of cached references to the panel elements:

| Variable | Description | | : --- | : --- | | panelElement | The panel node. | | labelElement | The label node. | | contentElement | The content node. |

This way you can use events of the contained widget to alter the panel itself, for instance its label.

Events

Apart from the default events, this widget triggers the following events.

df:widget:renderContent

Triggered when the widget contained on the panel has been rendered.

panel.on("df:widget:renderContent", function(widget){
  // widget is ready to use
});

| Argument | Type | Description | | : --- | : --- : | : --- | | widget | Widget | Widget contained in the panel. |


doofinder.widgets.CollapsiblePanel

Widget < Display < Panel < CollapsiblePanel

This widget is a variant of Panel. It provides collapsing features so a user can collapse the panel by clicking on its header.

constructor
// assume facet variable obtained from the server
var panel = new doofinder.widgets.CollapsiblePanel(
  "#aside", 
  function(panel){ 
    /* ... */
  }, 
  {
    label: facet.label,
    startCollapsed: true
  }
);
Options

Apart from the Panel options, this widget provides:

OptionRequiredTypeDefaultDescription
startCollapsedNoBooleanfalseIndicates whether the panel is rendered collapsed by default or not.
CollapsiblePanel.collapse()

This method collapses the panel.

panel.collapse();
CollapsiblePanel.expand()

This method expands the panel.

panel.expand();
CollapsiblePanel.toggle()

This method toggles the panel status; if collapsed it expands and vice versa.

panel.toggle();
CollapsiblePanel.reset()

This method resets the panel collapse status based on the value of the startCollapsed option.

panel.reset();
Events

Apart from the default events, this widget triggers the following events:

df:collapse:change

Triggered when the panel collapse status change.

panel.on("df:collapse:change", function(collapsed) {
  if (collapsed) {
    // ...
  }
});

| Argument | Type | Description | | : --- | : --- : | : --- | | collapsed | Boolean | Whether the panel is collapsed or not. |

Session Reference

A Session is used to store user data. User (session) data may be persisted or not, depending on the store class being used.

Store classes must implement ISessionStore so Session instances know how to work with them.

doofinder.session.ISessionStore

Interface that all storage classes must implement. See Session.

It provides some public methods:

MethodDescription
get(key)Gets the value for the specified key from the storage.
set(key, value)Sets the value for the specified key in the storage.
del(key)Deletes the specified key from the storage.

And requires some protected methods to be implemented:

MethodDescription
__getData()Gets the current data obj from the underlying storage and ensures that a session_id is created if it doesn't exist, like a signature that all session data must have.
__setData(dataObj)Saves the current data obj into the underlying storage.
clean()Deletes all data from the underlying storage.
exists()Checks whether the session exists or not.

doofinder.session.ObjectSessionStore

Store to hold session data as a plain Object.

constructor
var store = new doofinder.session.ObjectSessionStore({
  key: "value"
});
Arguments
ArgumentRequiredTypeDescription
dataNoObjectInitial data.

doofinder.session.CookieSessionStore

Store that holds session data in a browser cookie.

constructor
var store = new doofinder.session.CookieSessionStore(cookieName, {
  expiry: 1
});
Arguments
ArgumentRequiredTypeDescription
cookieNameYesStringA name for the cookie.
optionsNoObjectOptions object.
Options
OptionRequiredTypeDefaultDescription
prefixNoString""Prefix to be added to the cookie name.
expiryYesNumber1/24Duration of the cookie in days. 1 hour by default.

doofinder.session.Session

Class that represents a user session persisted somewhere.

constructor
var session = new doofinder.session.Session(
  new doofinder.session.CookieSessionStore("myCookie")
);
Arguments
ArgumentRequiredTypeDescription
storeYesISessionStoreA valid storage instance.

Stats Reference

doofinder.Stats

Helper class to wrap calls to the Doofinder stats API endpoint using the Client and Session classes.

constructor
var stats = new doofinder.Stats(client, session);
Arguments
ArgumentRequiredTypeDescription
clientYesClientAn instance of Client.
sessionYesSessionAn instance of Session.
Stats.setCurrentQuery()

Sets current search terms in the search session.

stats.setCurrentQuery("red car");
ArgumentRequiredTypeDescription
queryYesStringSearch terms.

WARNING: This should be called ONLY if the user has performed a search. That's why this is usually called when the user has stopped typing in the search box.

Stats.registerSession()

Registers the session in Doofinder stats if not already registered. It marks the session as registered synchronously to short-circuit other attempts while the request is in progress. If an error occurs in the stats request the session is marked as unregistered again.

var registered = stats.registerSession(function(err, res){
  // Do something in case of error or successful response
});

This method returns a Boolean value saying if the session was registered or not (for instance if it was already registered).

WARNING: This should be called ONLY if the user has performed a search. That's why this is usually called when the user has stopped typing in the search box.

ArgumentRequiredTypeDescription
callbackNoFunctionMethod to be called when the response or an error is received.
Stats.registerClick()

Registers a click on a search result for the specified search query.

stats.registerClick("abcd3434...", "red car", function(err, res){
  // Do something in case of error or successful response
});
stats.registerClick("abcd3434...", null, function(err, res){
  // Do something in case of error or successful response
});
stats.registerClick("abcd3434...");
ArgumentRequiredTypeDescription
dfidYesStringInternal id of the result in Doofinder
queryNoStringSearch terms. If not defined, is obtained from the session.
callbackNoFunctionMethod to be called when the response or an error is received.
Stats.registerCheckout()

Registers a checkout if session exists. This method returns a Boolean to determine whether the checkout was registered or not.

var registered = stats.registerCheckout(function(err, res){
  // Do something in case of error or successful response
});
ArgumentRequiredTypeDescription
callbackNoFunctionMethod to be called when the response or an error is received.
Stats.registerBannerEvent()

Registers an event for a banner.

stats.registerBannerEvent("display", 1234, function(err, res){});
stats.registerBannerEvent("click", 1234, function(err, res){});
ArgumentRequiredTypeValuesDescription
eventNameYesStringdisplay Use to register the event of a banner being displayed to the user.
click Used to register the click of a user on a banner.
bannerIdYesNumber Id of the banner in Doofinder.
callbackNoFunctionMethod to be called when the response or an error is received.

How To

Configure facet widgets dynamically

Facets defined in Doofinder for a search engine can be easily retrieved by requesting the search engine's options through an instance of Client.

For each terms facet you will get something like this:

{
  "visible": true,
  "type": "terms",
  "size": 20,
  "name": "brand",
  "label": "brand",
  "field": "brand.facet",
  "es_definition": {
    "terms": {
      "size": 20,
      "field": "brand.facet"
    }
  }
}

When dealing with the options response to dynamicly configure facets, you will only have to take some fields into account:

FieldTypeValuesDescription
nameStringMachine name of the facet.
typeString"terms"For terms facet this value is fixed.
sizeNumberMaximum number of terms the server will return for this facet.
labelStringHumanized name of the facet.
visibleBooleanIndicates whether this filter should be available for the user or is for your app's internal use only.

For instance, you could do this:

<div id="brand"></div>
client.options(function(err, options){
  options.facets.forEach(function(facet){
    if (facet.type === 'terms') {
      var elementId = "#" +  facet.name; // "#brand", for instance
      controller.registerWidget(
        new doofinder.widgets.TermsFacet(elementId, facet.name)
      );
    }
  });
});

For a range facet you would get something like this:

{
  "visible": true,
  "type": "range",
  "ranges": [{
    "from": 0
  }],
  "name": "best_price",
  "label": "Price",
  "field": "best_price",
  "es_definition": {
    "range": {
      "ranges": [{
          "from": 0
      }],
      "field": "best_price"
    }
  }
}

Keywords

FAQs

Package last updated on 18 Jan 2018

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc