/*! 1.4.9 | © Algolia | github.com/algolia/places */
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["places"] = factory();
else
root["places"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _places = __webpack_require__(1);
var _places2 = _interopRequireDefault(_places);
var _version = __webpack_require__(63);
var _version2 = _interopRequireDefault(_version);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// must use module.exports to be commonJS compatible
// we need to export using commonjs for ease of usage in all
// JavaScript environments
/* eslint-disable import/no-commonjs */
module.exports = _places2.default;
module.exports.version = _version2.default;
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.default = places;
var _events = __webpack_require__(2);
var _events2 = _interopRequireDefault(_events);
var _algoliasearchLite = __webpack_require__(3);
var _algoliasearchLite2 = _interopRequireDefault(_algoliasearchLite);
var _autocomplete = __webpack_require__(35);
var _autocomplete2 = _interopRequireDefault(_autocomplete);
__webpack_require__(57);
var _createAutocompleteDataset = __webpack_require__(58);
var _createAutocompleteDataset2 = _interopRequireDefault(_createAutocompleteDataset);
var _clear = __webpack_require__(76);
var _clear2 = _interopRequireDefault(_clear);
var _address = __webpack_require__(67);
var _address2 = _interopRequireDefault(_address);
var _places = __webpack_require__(77);
var _places2 = _interopRequireDefault(_places);
var _insertCss = __webpack_require__(78);
var _insertCss2 = _interopRequireDefault(_insertCss);
var _errors = __webpack_require__(79);
var _errors2 = _interopRequireDefault(_errors);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
(0, _insertCss2.default)(_places2.default, { prepend: true });
function places(options) {
var container = options.container,
style = options.style,
_options$autocomplete = options.autocompleteOptions,
userAutocompleteOptions = _options$autocomplete === undefined ? {} : _options$autocomplete;
// multiple DOM elements targeted
if (container instanceof NodeList) {
if (container.length > 1) {
throw new Error(_errors2.default.multiContainers);
}
// if single node NodeList received, resolve to the first one
return places(_extends({}, options, { container: container[0] }));
}
// container sent as a string, resolve it for multiple DOM elements issue
if (typeof container === 'string') {
var resolvedContainer = document.querySelectorAll(container);
return places(_extends({}, options, { container: resolvedContainer }));
}
// if not an , error
if (!(container instanceof HTMLInputElement)) {
throw new Error(_errors2.default.badContainer);
}
var placesInstance = new _events2.default();
var prefix = 'ap' + (style === false ? '-nostyle' : '');
var autocompleteOptions = _extends({
autoselect: true,
hint: false,
cssClasses: {
root: 'algolia-places' + (style === false ? '-nostyle' : ''),
prefix: prefix
},
debug: ("production") === 'development'
}, userAutocompleteOptions);
var autocompleteDataset = (0, _createAutocompleteDataset2.default)(_extends({}, options, {
algoliasearch: _algoliasearchLite2.default,
onHits: function onHits(_ref) {
var hits = _ref.hits,
rawAnswer = _ref.rawAnswer,
query = _ref.query;
return placesInstance.emit('suggestions', {
rawAnswer: rawAnswer,
query: query,
suggestions: hits
});
},
onError: function onError(e) {
return placesInstance.emit('error', e);
},
onRateLimitReached: function onRateLimitReached() {
var listeners = placesInstance.listenerCount('limit');
if (listeners === 0) {
console.log(_errors2.default.rateLimitReached); // eslint-disable-line
return;
}
placesInstance.emit('limit', { message: _errors2.default.rateLimitReached });
},
container: undefined
}));
var autocompleteInstance = (0, _autocomplete2.default)(container, autocompleteOptions, autocompleteDataset);
var autocompleteContainer = container.parentNode;
var autocompleteChangeEvents = ['selected', 'autocompleted'];
autocompleteChangeEvents.forEach(function (eventName) {
autocompleteInstance.on('autocomplete:' + eventName, function (_, suggestion) {
placesInstance.emit('change', {
rawAnswer: suggestion.rawAnswer,
query: suggestion.query,
suggestion: suggestion,
suggestionIndex: suggestion.hitIndex
});
});
});
autocompleteInstance.on('autocomplete:cursorchanged', function (_, suggestion) {
placesInstance.emit('cursorchanged', {
rawAnswer: suggestion.rawAnswer,
query: suggestion.query,
suggestion: suggestion,
suggestionIndex: suggestion.hitIndex
});
});
var clear = document.createElement('button');
clear.setAttribute('type', 'button');
clear.classList.add(prefix + '-input-icon');
clear.classList.add(prefix + '-icon-clear');
clear.innerHTML = _clear2.default;
autocompleteContainer.appendChild(clear);
clear.style.display = 'none';
var pin = document.createElement('button');
pin.setAttribute('type', 'button');
pin.classList.add(prefix + '-input-icon');
pin.classList.add(prefix + '-icon-pin');
pin.innerHTML = _address2.default;
autocompleteContainer.appendChild(pin);
pin.addEventListener('click', function () {
return autocompleteInstance.focus();
});
clear.addEventListener('click', function () {
autocompleteInstance.autocomplete.setVal('');
autocompleteInstance.focus();
clear.style.display = 'none';
pin.style.display = '';
placesInstance.emit('clear');
});
var previousQuery = '';
var inputListener = function inputListener() {
var query = autocompleteInstance.val();
if (query === '') {
pin.style.display = '';
clear.style.display = 'none';
if (previousQuery !== query) {
placesInstance.emit('clear');
}
} else {
clear.style.display = '';
pin.style.display = 'none';
}
previousQuery = query;
};
autocompleteContainer.querySelector('.' + prefix + '-input').addEventListener('input', inputListener);
var autocompleteMethods = ['open', 'close', 'getVal', 'setVal', 'destroy'];
autocompleteMethods.forEach(function (methodName) {
placesInstance[methodName] = function () {
var _autocompleteInstance;
if (methodName === 'destroy') {
// this is the only event we need to manually remove because the input will still be here
autocompleteContainer.querySelector('.' + prefix + '-input').removeEventListener('input', inputListener);
}
(_autocompleteInstance = autocompleteInstance.autocomplete)[methodName].apply(_autocompleteInstance, arguments);
};
});
placesInstance.autocomplete = autocompleteInstance;
return placesInstance;
}
/***/ },
/* 2 */
/***/ function(module, exports) {
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
args = Array.prototype.slice.call(arguments, 1);
handler.apply(this, args);
}
} else if (isObject(handler)) {
args = Array.prototype.slice.call(arguments, 1);
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.prototype.listenerCount = function(type) {
if (this._events) {
var evlistener = this._events[type];
if (isFunction(evlistener))
return 1;
else if (evlistener)
return evlistener.length;
}
return 0;
};
EventEmitter.listenerCount = function(emitter, type) {
return emitter.listenerCount(type);
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var AlgoliaSearchCore = __webpack_require__(4);
var createAlgoliasearch = __webpack_require__(25);
module.exports = createAlgoliasearch(AlgoliaSearchCore, '(lite) ');
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
module.exports = AlgoliaSearchCore;
var errors = __webpack_require__(5);
var exitPromise = __webpack_require__(8);
var IndexCore = __webpack_require__(9);
var store = __webpack_require__(20);
// We will always put the API KEY in the JSON body in case of too long API KEY,
// to avoid query string being too long and failing in various conditions (our server limit, browser limit,
// proxies limit)
var MAX_API_KEY_LENGTH = 500;
var RESET_APP_DATA_TIMER =
({"NODE_ENV":"production"}).RESET_APP_DATA_TIMER && parseInt(({"NODE_ENV":"production"}).RESET_APP_DATA_TIMER, 10) ||
60 * 2 * 1000; // after 2 minutes reset to first host
/*
* Algolia Search library initialization
* https://www.algolia.com/
*
* @param {string} applicationID - Your applicationID, found in your dashboard
* @param {string} apiKey - Your API key, found in your dashboard
* @param {Object} [opts]
* @param {number} [opts.timeout=2000] - The request timeout set in milliseconds,
* another request will be issued after this timeout
* @param {string} [opts.protocol='http:'] - The protocol used to query Algolia Search API.
* Set to 'https:' to force using https.
* Default to document.location.protocol in browsers
* @param {Object|Array} [opts.hosts={
* read: [this.applicationID + '-dsn.algolia.net'].concat([
* this.applicationID + '-1.algolianet.com',
* this.applicationID + '-2.algolianet.com',
* this.applicationID + '-3.algolianet.com']
* ]),
* write: [this.applicationID + '.algolia.net'].concat([
* this.applicationID + '-1.algolianet.com',
* this.applicationID + '-2.algolianet.com',
* this.applicationID + '-3.algolianet.com']
* ]) - The hosts to use for Algolia Search API.
* If you provide them, you will less benefit from our HA implementation
*/
function AlgoliaSearchCore(applicationID, apiKey, opts) {
var debug = __webpack_require__(21)('algoliasearch');
var clone = __webpack_require__(14);
var isArray = __webpack_require__(18);
var map = __webpack_require__(19);
var usage = 'Usage: algoliasearch(applicationID, apiKey, opts)';
if (opts._allowEmptyCredentials !== true && !applicationID) {
throw new errors.AlgoliaSearchError('Please provide an application ID. ' + usage);
}
if (opts._allowEmptyCredentials !== true && !apiKey) {
throw new errors.AlgoliaSearchError('Please provide an API key. ' + usage);
}
this.applicationID = applicationID;
this.apiKey = apiKey;
this.hosts = {
read: [],
write: []
};
opts = opts || {};
var protocol = opts.protocol || 'https:';
this._timeouts = opts.timeouts || {
connect: 1 * 1000, // 500ms connect is GPRS latency
read: 2 * 1000,
write: 30 * 1000
};
// backward compat, if opts.timeout is passed, we use it to configure all timeouts like before
if (opts.timeout) {
this._timeouts.connect = this._timeouts.read = this._timeouts.write = opts.timeout;
}
// while we advocate for colon-at-the-end values: 'http:' for `opts.protocol`
// we also accept `http` and `https`. It's a common error.
if (!/:$/.test(protocol)) {
protocol = protocol + ':';
}
if (opts.protocol !== 'http:' && opts.protocol !== 'https:') {
throw new errors.AlgoliaSearchError('protocol must be `http:` or `https:` (was `' + opts.protocol + '`)');
}
this._checkAppIdData();
if (!opts.hosts) {
var defaultHosts = map(this._shuffleResult, function(hostNumber) {
return applicationID + '-' + hostNumber + '.algolianet.com';
});
// no hosts given, compute defaults
this.hosts.read = [this.applicationID + '-dsn.algolia.net'].concat(defaultHosts);
this.hosts.write = [this.applicationID + '.algolia.net'].concat(defaultHosts);
} else if (isArray(opts.hosts)) {
// when passing custom hosts, we need to have a different host index if the number
// of write/read hosts are different.
this.hosts.read = clone(opts.hosts);
this.hosts.write = clone(opts.hosts);
} else {
this.hosts.read = clone(opts.hosts.read);
this.hosts.write = clone(opts.hosts.write);
}
// add protocol and lowercase hosts
this.hosts.read = map(this.hosts.read, prepareHost(protocol));
this.hosts.write = map(this.hosts.write, prepareHost(protocol));
this.extraHeaders = [];
// In some situations you might want to warm the cache
this.cache = opts._cache || {};
this._ua = opts._ua;
this._useCache = opts._useCache === undefined || opts._cache ? true : opts._useCache;
this._useFallback = opts.useFallback === undefined ? true : opts.useFallback;
this._setTimeout = opts._setTimeout;
debug('init done, %j', this);
}
/*
* Get the index object initialized
*
* @param indexName the name of index
* @param callback the result callback with one argument (the Index instance)
*/
AlgoliaSearchCore.prototype.initIndex = function(indexName) {
return new IndexCore(this, indexName);
};
/**
* Add an extra field to the HTTP request
*
* @param name the header field name
* @param value the header field value
*/
AlgoliaSearchCore.prototype.setExtraHeader = function(name, value) {
this.extraHeaders.push({
name: name.toLowerCase(), value: value
});
};
/**
* Augment sent x-algolia-agent with more data, each agent part
* is automatically separated from the others by a semicolon;
*
* @param algoliaAgent the agent to add
*/
AlgoliaSearchCore.prototype.addAlgoliaAgent = function(algoliaAgent) {
if (this._ua.indexOf(';' + algoliaAgent) === -1) {
this._ua += ';' + algoliaAgent;
}
};
/*
* Wrapper that try all hosts to maximize the quality of service
*/
AlgoliaSearchCore.prototype._jsonRequest = function(initialOpts) {
this._checkAppIdData();
var requestDebug = __webpack_require__(21)('algoliasearch:' + initialOpts.url);
var body;
var cache = initialOpts.cache;
var client = this;
var tries = 0;
var usingFallback = false;
var hasFallback = client._useFallback && client._request.fallback && initialOpts.fallback;
var headers;
if (
this.apiKey.length > MAX_API_KEY_LENGTH &&
initialOpts.body !== undefined &&
(initialOpts.body.params !== undefined || // index.search()
initialOpts.body.requests !== undefined) // client.search()
) {
initialOpts.body.apiKey = this.apiKey;
headers = this._computeRequestHeaders(false);
} else {
headers = this._computeRequestHeaders();
}
if (initialOpts.body !== undefined) {
body = safeJSONStringify(initialOpts.body);
}
requestDebug('request start');
var debugData = [];
function doRequest(requester, reqOpts) {
client._checkAppIdData();
var startTime = new Date();
var cacheID;
if (client._useCache) {
cacheID = initialOpts.url;
}
// as we sometime use POST requests to pass parameters (like query='aa'),
// the cacheID must also include the body to be different between calls
if (client._useCache && body) {
cacheID += '_body_' + reqOpts.body;
}
// handle cache existence
if (client._useCache && cache && cache[cacheID] !== undefined) {
requestDebug('serving response from cache');
return client._promise.resolve(JSON.parse(cache[cacheID]));
}
// if we reached max tries
if (tries >= client.hosts[initialOpts.hostType].length) {
if (!hasFallback || usingFallback) {
requestDebug('could not get any response');
// then stop
return client._promise.reject(new errors.AlgoliaSearchError(
'Cannot connect to the AlgoliaSearch API.' +
' Send an email to support@algolia.com to report and resolve the issue.' +
' Application id was: ' + client.applicationID, {debugData: debugData}
));
}
requestDebug('switching to fallback');
// let's try the fallback starting from here
tries = 0;
// method, url and body are fallback dependent
reqOpts.method = initialOpts.fallback.method;
reqOpts.url = initialOpts.fallback.url;
reqOpts.jsonBody = initialOpts.fallback.body;
if (reqOpts.jsonBody) {
reqOpts.body = safeJSONStringify(reqOpts.jsonBody);
}
// re-compute headers, they could be omitting the API KEY
headers = client._computeRequestHeaders();
reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType);
client._setHostIndexByType(0, initialOpts.hostType);
usingFallback = true; // the current request is now using fallback
return doRequest(client._request.fallback, reqOpts);
}
var currentHost = client._getHostByType(initialOpts.hostType);
var url = currentHost + reqOpts.url;
var options = {
body: reqOpts.body,
jsonBody: reqOpts.jsonBody,
method: reqOpts.method,
headers: headers,
timeouts: reqOpts.timeouts,
debug: requestDebug
};
requestDebug('method: %s, url: %s, headers: %j, timeouts: %d',
options.method, url, options.headers, options.timeouts);
if (requester === client._request.fallback) {
requestDebug('using fallback');
}
// `requester` is any of this._request or this._request.fallback
// thus it needs to be called using the client as context
return requester.call(client, url, options).then(success, tryFallback);
function success(httpResponse) {
// compute the status of the response,
//
// When in browser mode, using XDR or JSONP, we have no statusCode available
// So we rely on our API response `status` property.
// But `waitTask` can set a `status` property which is not the statusCode (it's the task status)
// So we check if there's a `message` along `status` and it means it's an error
//
// That's the only case where we have a response.status that's not the http statusCode
var status = httpResponse && httpResponse.body && httpResponse.body.message && httpResponse.body.status ||
// this is important to check the request statusCode AFTER the body eventual
// statusCode because some implementations (jQuery XDomainRequest transport) may
// send statusCode 200 while we had an error
httpResponse.statusCode ||
// When in browser mode, using XDR or JSONP
// we default to success when no error (no response.status && response.message)
// If there was a JSON.parse() error then body is null and it fails
httpResponse && httpResponse.body && 200;
requestDebug('received response: statusCode: %s, computed statusCode: %d, headers: %j',
httpResponse.statusCode, status, httpResponse.headers);
var httpResponseOk = Math.floor(status / 100) === 2;
var endTime = new Date();
debugData.push({
currentHost: currentHost,
headers: removeCredentials(headers),
content: body || null,
contentLength: body !== undefined ? body.length : null,
method: reqOpts.method,
timeouts: reqOpts.timeouts,
url: reqOpts.url,
startTime: startTime,
endTime: endTime,
duration: endTime - startTime,
statusCode: status
});
if (httpResponseOk) {
if (client._useCache && cache) {
cache[cacheID] = httpResponse.responseText;
}
return httpResponse.body;
}
var shouldRetry = Math.floor(status / 100) !== 4;
if (shouldRetry) {
tries += 1;
return retryRequest();
}
requestDebug('unrecoverable error');
// no success and no retry => fail
var unrecoverableError = new errors.AlgoliaSearchError(
httpResponse.body && httpResponse.body.message, {debugData: debugData, statusCode: status}
);
return client._promise.reject(unrecoverableError);
}
function tryFallback(err) {
// error cases:
// While not in fallback mode:
// - CORS not supported
// - network error
// While in fallback mode:
// - timeout
// - network error
// - badly formatted JSONP (script loaded, did not call our callback)
// In both cases:
// - uncaught exception occurs (TypeError)
requestDebug('error: %s, stack: %s', err.message, err.stack);
var endTime = new Date();
debugData.push({
currentHost: currentHost,
headers: removeCredentials(headers),
content: body || null,
contentLength: body !== undefined ? body.length : null,
method: reqOpts.method,
timeouts: reqOpts.timeouts,
url: reqOpts.url,
startTime: startTime,
endTime: endTime,
duration: endTime - startTime
});
if (!(err instanceof errors.AlgoliaSearchError)) {
err = new errors.Unknown(err && err.message, err);
}
tries += 1;
// stop the request implementation when:
if (
// we did not generate this error,
// it comes from a throw in some other piece of code
err instanceof errors.Unknown ||
// server sent unparsable JSON
err instanceof errors.UnparsableJSON ||
// max tries and already using fallback or no fallback
tries >= client.hosts[initialOpts.hostType].length &&
(usingFallback || !hasFallback)) {
// stop request implementation for this command
err.debugData = debugData;
return client._promise.reject(err);
}
// When a timeout occured, retry by raising timeout
if (err instanceof errors.RequestTimeout) {
return retryRequestWithHigherTimeout();
}
return retryRequest();
}
function retryRequest() {
requestDebug('retrying request');
client._incrementHostIndex(initialOpts.hostType);
return doRequest(requester, reqOpts);
}
function retryRequestWithHigherTimeout() {
requestDebug('retrying request with higher timeout');
client._incrementHostIndex(initialOpts.hostType);
client._incrementTimeoutMultipler();
reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType);
return doRequest(requester, reqOpts);
}
}
var promise = doRequest(
client._request, {
url: initialOpts.url,
method: initialOpts.method,
body: body,
jsonBody: initialOpts.body,
timeouts: client._getTimeoutsForRequest(initialOpts.hostType)
}
);
// either we have a callback
// either we are using promises
if (initialOpts.callback) {
promise.then(function okCb(content) {
exitPromise(function() {
initialOpts.callback(null, content);
}, client._setTimeout || setTimeout);
}, function nookCb(err) {
exitPromise(function() {
initialOpts.callback(err);
}, client._setTimeout || setTimeout);
});
} else {
return promise;
}
};
/*
* Transform search param object in query string
*/
AlgoliaSearchCore.prototype._getSearchParams = function(args, params) {
if (args === undefined || args === null) {
return params;
}
for (var key in args) {
if (key !== null && args[key] !== undefined && args.hasOwnProperty(key)) {
params += params === '' ? '' : '&';
params += key + '=' + encodeURIComponent(Object.prototype.toString.call(args[key]) === '[object Array]' ? safeJSONStringify(args[key]) : args[key]);
}
}
return params;
};
AlgoliaSearchCore.prototype._computeRequestHeaders = function(withAPIKey) {
var forEach = __webpack_require__(7);
var requestHeaders = {
'x-algolia-agent': this._ua,
'x-algolia-application-id': this.applicationID
};
// browser will inline headers in the url, node.js will use http headers
// but in some situations, the API KEY will be too long (big secured API keys)
// so if the request is a POST and the KEY is very long, we will be asked to not put
// it into headers but in the JSON body
if (withAPIKey !== false) {
requestHeaders['x-algolia-api-key'] = this.apiKey;
}
if (this.userToken) {
requestHeaders['x-algolia-usertoken'] = this.userToken;
}
if (this.securityTags) {
requestHeaders['x-algolia-tagfilters'] = this.securityTags;
}
if (this.extraHeaders) {
forEach(this.extraHeaders, function addToRequestHeaders(header) {
requestHeaders[header.name] = header.value;
});
}
return requestHeaders;
};
/**
* Search through multiple indices at the same time
* @param {Object[]} queries An array of queries you want to run.
* @param {string} queries[].indexName The index name you want to target
* @param {string} [queries[].query] The query to issue on this index. Can also be passed into `params`
* @param {Object} queries[].params Any search param like hitsPerPage, ..
* @param {Function} callback Callback to be called
* @return {Promise|undefined} Returns a promise if no callback given
*/
AlgoliaSearchCore.prototype.search = function(queries, opts, callback) {
var isArray = __webpack_require__(18);
var map = __webpack_require__(19);
var usage = 'Usage: client.search(arrayOfQueries[, callback])';
if (!isArray(queries)) {
throw new Error(usage);
}
if (typeof opts === 'function') {
callback = opts;
opts = {};
} else if (opts === undefined) {
opts = {};
}
var client = this;
var postObj = {
requests: map(queries, function prepareRequest(query) {
var params = '';
// allow query.query
// so we are mimicing the index.search(query, params) method
// {indexName:, query:, params:}
if (query.query !== undefined) {
params += 'query=' + encodeURIComponent(query.query);
}
return {
indexName: query.indexName,
params: client._getSearchParams(query.params, params)
};
})
};
var JSONPParams = map(postObj.requests, function prepareJSONPParams(request, requestId) {
return requestId + '=' +
encodeURIComponent(
'/1/indexes/' + encodeURIComponent(request.indexName) + '?' +
request.params
);
}).join('&');
var url = '/1/indexes/*/queries';
if (opts.strategy !== undefined) {
url += '?strategy=' + opts.strategy;
}
return this._jsonRequest({
cache: this.cache,
method: 'POST',
url: url,
body: postObj,
hostType: 'read',
fallback: {
method: 'GET',
url: '/1/indexes/*',
body: {
params: JSONPParams
}
},
callback: callback
});
};
/**
* Set the extra security tagFilters header
* @param {string|array} tags The list of tags defining the current security filters
*/
AlgoliaSearchCore.prototype.setSecurityTags = function(tags) {
if (Object.prototype.toString.call(tags) === '[object Array]') {
var strTags = [];
for (var i = 0; i < tags.length; ++i) {
if (Object.prototype.toString.call(tags[i]) === '[object Array]') {
var oredTags = [];
for (var j = 0; j < tags[i].length; ++j) {
oredTags.push(tags[i][j]);
}
strTags.push('(' + oredTags.join(',') + ')');
} else {
strTags.push(tags[i]);
}
}
tags = strTags.join(',');
}
this.securityTags = tags;
};
/**
* Set the extra user token header
* @param {string} userToken The token identifying a uniq user (used to apply rate limits)
*/
AlgoliaSearchCore.prototype.setUserToken = function(userToken) {
this.userToken = userToken;
};
/**
* Clear all queries in client's cache
* @return undefined
*/
AlgoliaSearchCore.prototype.clearCache = function() {
this.cache = {};
};
/**
* Set the number of milliseconds a request can take before automatically being terminated.
* @deprecated
* @param {Number} milliseconds
*/
AlgoliaSearchCore.prototype.setRequestTimeout = function(milliseconds) {
if (milliseconds) {
this._timeouts.connect = this._timeouts.read = this._timeouts.write = milliseconds;
}
};
/**
* Set the three different (connect, read, write) timeouts to be used when requesting
* @param {Object} timeouts
*/
AlgoliaSearchCore.prototype.setTimeouts = function(timeouts) {
this._timeouts = timeouts;
};
/**
* Get the three different (connect, read, write) timeouts to be used when requesting
* @param {Object} timeouts
*/
AlgoliaSearchCore.prototype.getTimeouts = function() {
return this._timeouts;
};
AlgoliaSearchCore.prototype._getAppIdData = function() {
var data = store.get(this.applicationID);
if (data !== null) this._cacheAppIdData(data);
return data;
};
AlgoliaSearchCore.prototype._setAppIdData = function(data) {
data.lastChange = (new Date()).getTime();
this._cacheAppIdData(data);
return store.set(this.applicationID, data);
};
AlgoliaSearchCore.prototype._checkAppIdData = function() {
var data = this._getAppIdData();
var now = (new Date()).getTime();
if (data === null || now - data.lastChange > RESET_APP_DATA_TIMER) {
return this._resetInitialAppIdData(data);
}
return data;
};
AlgoliaSearchCore.prototype._resetInitialAppIdData = function(data) {
var newData = data || {};
newData.hostIndexes = {read: 0, write: 0};
newData.timeoutMultiplier = 1;
newData.shuffleResult = newData.shuffleResult || shuffle([1, 2, 3]);
return this._setAppIdData(newData);
};
AlgoliaSearchCore.prototype._cacheAppIdData = function(data) {
this._hostIndexes = data.hostIndexes;
this._timeoutMultiplier = data.timeoutMultiplier;
this._shuffleResult = data.shuffleResult;
};
AlgoliaSearchCore.prototype._partialAppIdDataUpdate = function(newData) {
var foreach = __webpack_require__(7);
var currentData = this._getAppIdData();
foreach(newData, function(value, key) {
currentData[key] = value;
});
return this._setAppIdData(currentData);
};
AlgoliaSearchCore.prototype._getHostByType = function(hostType) {
return this.hosts[hostType][this._getHostIndexByType(hostType)];
};
AlgoliaSearchCore.prototype._getTimeoutMultiplier = function() {
return this._timeoutMultiplier;
};
AlgoliaSearchCore.prototype._getHostIndexByType = function(hostType) {
return this._hostIndexes[hostType];
};
AlgoliaSearchCore.prototype._setHostIndexByType = function(hostIndex, hostType) {
var clone = __webpack_require__(14);
var newHostIndexes = clone(this._hostIndexes);
newHostIndexes[hostType] = hostIndex;
this._partialAppIdDataUpdate({hostIndexes: newHostIndexes});
return hostIndex;
};
AlgoliaSearchCore.prototype._incrementHostIndex = function(hostType) {
return this._setHostIndexByType(
(this._getHostIndexByType(hostType) + 1) % this.hosts[hostType].length, hostType
);
};
AlgoliaSearchCore.prototype._incrementTimeoutMultipler = function() {
var timeoutMultiplier = Math.max(this._timeoutMultiplier + 1, 4);
return this._partialAppIdDataUpdate({timeoutMultiplier: timeoutMultiplier});
};
AlgoliaSearchCore.prototype._getTimeoutsForRequest = function(hostType) {
return {
connect: this._timeouts.connect * this._timeoutMultiplier,
complete: this._timeouts[hostType] * this._timeoutMultiplier
};
};
function prepareHost(protocol) {
return function prepare(host) {
return protocol + '//' + host.toLowerCase();
};
}
// Prototype.js < 1.7, a widely used library, defines a weird
// Array.prototype.toJSON function that will fail to stringify our content
// appropriately
// refs:
// - https://groups.google.com/forum/#!topic/prototype-core/E-SAVvV_V9Q
// - https://github.com/sstephenson/prototype/commit/038a2985a70593c1a86c230fadbdfe2e4898a48c
// - http://stackoverflow.com/a/3148441/147079
function safeJSONStringify(obj) {
/* eslint no-extend-native:0 */
if (Array.prototype.toJSON === undefined) {
return JSON.stringify(obj);
}
var toJSON = Array.prototype.toJSON;
delete Array.prototype.toJSON;
var out = JSON.stringify(obj);
Array.prototype.toJSON = toJSON;
return out;
}
function shuffle(array) {
var currentIndex = array.length;
var temporaryValue;
var randomIndex;
// While there remain elements to shuffle...
while (currentIndex !== 0) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
function removeCredentials(headers) {
var newHeaders = {};
for (var headerName in headers) {
if (Object.prototype.hasOwnProperty.call(headers, headerName)) {
var value;
if (headerName === 'x-algolia-api-key' || headerName === 'x-algolia-application-id') {
value = '**hidden for security purposes**';
} else {
value = headers[headerName];
}
newHeaders[headerName] = value;
}
}
return newHeaders;
}
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
// This file hosts our error definitions
// We use custom error "types" so that we can act on them when we need it
// e.g.: if error instanceof errors.UnparsableJSON then..
var inherits = __webpack_require__(6);
function AlgoliaSearchError(message, extraProperties) {
var forEach = __webpack_require__(7);
var error = this;
// try to get a stacktrace
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
error.stack = (new Error()).stack || 'Cannot get a stacktrace, browser is too old';
}
this.name = 'AlgoliaSearchError';
this.message = message || 'Unknown error';
if (extraProperties) {
forEach(extraProperties, function addToErrorObject(value, key) {
error[key] = value;
});
}
}
inherits(AlgoliaSearchError, Error);
function createCustomError(name, message) {
function AlgoliaSearchCustomError() {
var args = Array.prototype.slice.call(arguments, 0);
// custom message not set, use default
if (typeof args[0] !== 'string') {
args.unshift(message);
}
AlgoliaSearchError.apply(this, args);
this.name = 'AlgoliaSearch' + name + 'Error';
}
inherits(AlgoliaSearchCustomError, AlgoliaSearchError);
return AlgoliaSearchCustomError;
}
// late exports to let various fn defs and inherits take place
module.exports = {
AlgoliaSearchError: AlgoliaSearchError,
UnparsableJSON: createCustomError(
'UnparsableJSON',
'Could not parse the incoming response as JSON, see err.more for details'
),
RequestTimeout: createCustomError(
'RequestTimeout',
'Request timedout before getting a response'
),
Network: createCustomError(
'Network',
'Network issue, see err.more for details'
),
JSONPScriptFail: createCustomError(
'JSONPScriptFail',
'