mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 00:52:02 +00:00
10138 lines
288 KiB
JavaScript
10138 lines
288 KiB
JavaScript
/*! docsearch 2.6.3 | © Algolia | github.com/algolia/docsearch */
|
||
(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["docsearch"] = factory();
|
||
else
|
||
root["docsearch"] = factory();
|
||
})(typeof self !== 'undefined' ? self : 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] = {
|
||
/******/ i: moduleId,
|
||
/******/ l: false,
|
||
/******/ exports: {}
|
||
/******/ };
|
||
/******/
|
||
/******/ // Execute the module function
|
||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||
/******/
|
||
/******/ // Flag the module as loaded
|
||
/******/ module.l = 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;
|
||
/******/
|
||
/******/ // define getter function for harmony exports
|
||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||
/******/ Object.defineProperty(exports, name, {
|
||
/******/ configurable: false,
|
||
/******/ enumerable: true,
|
||
/******/ get: getter
|
||
/******/ });
|
||
/******/ }
|
||
/******/ };
|
||
/******/
|
||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||
/******/ __webpack_require__.n = function(module) {
|
||
/******/ var getter = module && module.__esModule ?
|
||
/******/ function getDefault() { return module['default']; } :
|
||
/******/ function getModuleExports() { return module; };
|
||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||
/******/ return getter;
|
||
/******/ };
|
||
/******/
|
||
/******/ // Object.prototype.hasOwnProperty.call
|
||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||
/******/
|
||
/******/ // __webpack_public_path__
|
||
/******/ __webpack_require__.p = "";
|
||
/******/
|
||
/******/ // Load entry module and return exports
|
||
/******/ return __webpack_require__(__webpack_require__.s = 22);
|
||
/******/ })
|
||
/************************************************************************/
|
||
/******/ ([
|
||
/* 0 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var DOM = __webpack_require__(1);
|
||
|
||
function escapeRegExp(str) {
|
||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
||
}
|
||
|
||
module.exports = {
|
||
// those methods are implemented differently
|
||
// depending on which build it is, using
|
||
// $... or angular... or Zepto... or require(...)
|
||
isArray: null,
|
||
isFunction: null,
|
||
isObject: null,
|
||
bind: null,
|
||
each: null,
|
||
map: null,
|
||
mixin: null,
|
||
|
||
isMsie: function(agentString) {
|
||
if (agentString === undefined) { agentString = navigator.userAgent; }
|
||
// from https://github.com/ded/bowser/blob/master/bowser.js
|
||
if ((/(msie|trident)/i).test(agentString)) {
|
||
var match = agentString.match(/(msie |rv:)(\d+(.\d+)?)/i);
|
||
if (match) { return match[2]; }
|
||
}
|
||
return false;
|
||
},
|
||
|
||
// http://stackoverflow.com/a/6969486
|
||
escapeRegExChars: function(str) {
|
||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
||
},
|
||
|
||
isNumber: function(obj) { return typeof obj === 'number'; },
|
||
|
||
toStr: function toStr(s) {
|
||
return s === undefined || s === null ? '' : s + '';
|
||
},
|
||
|
||
cloneDeep: function cloneDeep(obj) {
|
||
var clone = this.mixin({}, obj);
|
||
var self = this;
|
||
this.each(clone, function(value, key) {
|
||
if (value) {
|
||
if (self.isArray(value)) {
|
||
clone[key] = [].concat(value);
|
||
} else if (self.isObject(value)) {
|
||
clone[key] = self.cloneDeep(value);
|
||
}
|
||
}
|
||
});
|
||
return clone;
|
||
},
|
||
|
||
error: function(msg) {
|
||
throw new Error(msg);
|
||
},
|
||
|
||
every: function(obj, test) {
|
||
var result = true;
|
||
if (!obj) {
|
||
return result;
|
||
}
|
||
this.each(obj, function(val, key) {
|
||
if (result) {
|
||
result = test.call(null, val, key, obj) && result;
|
||
}
|
||
});
|
||
return !!result;
|
||
},
|
||
|
||
any: function(obj, test) {
|
||
var found = false;
|
||
if (!obj) {
|
||
return found;
|
||
}
|
||
this.each(obj, function(val, key) {
|
||
if (test.call(null, val, key, obj)) {
|
||
found = true;
|
||
return false;
|
||
}
|
||
});
|
||
return found;
|
||
},
|
||
|
||
getUniqueId: (function() {
|
||
var counter = 0;
|
||
return function() { return counter++; };
|
||
})(),
|
||
|
||
templatify: function templatify(obj) {
|
||
if (this.isFunction(obj)) {
|
||
return obj;
|
||
}
|
||
var $template = DOM.element(obj);
|
||
if ($template.prop('tagName') === 'SCRIPT') {
|
||
return function template() { return $template.text(); };
|
||
}
|
||
return function template() { return String(obj); };
|
||
},
|
||
|
||
defer: function(fn) { setTimeout(fn, 0); },
|
||
|
||
noop: function() {},
|
||
|
||
formatPrefix: function(prefix, noPrefix) {
|
||
return noPrefix ? '' : prefix + '-';
|
||
},
|
||
|
||
className: function(prefix, clazz, skipDot) {
|
||
return (skipDot ? '' : '.') + prefix + clazz;
|
||
},
|
||
|
||
escapeHighlightedString: function(str, highlightPreTag, highlightPostTag) {
|
||
highlightPreTag = highlightPreTag || '<em>';
|
||
var pre = document.createElement('div');
|
||
pre.appendChild(document.createTextNode(highlightPreTag));
|
||
|
||
highlightPostTag = highlightPostTag || '</em>';
|
||
var post = document.createElement('div');
|
||
post.appendChild(document.createTextNode(highlightPostTag));
|
||
|
||
var div = document.createElement('div');
|
||
div.appendChild(document.createTextNode(str));
|
||
return div.innerHTML
|
||
.replace(RegExp(escapeRegExp(pre.innerHTML), 'g'), highlightPreTag)
|
||
.replace(RegExp(escapeRegExp(post.innerHTML), 'g'), highlightPostTag);
|
||
}
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 1 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
module.exports = {
|
||
element: null
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 2 */
|
||
/***/ (function(module, exports) {
|
||
|
||
|
||
var hasOwn = Object.prototype.hasOwnProperty;
|
||
var toString = Object.prototype.toString;
|
||
|
||
module.exports = function forEach (obj, fn, ctx) {
|
||
if (toString.call(fn) !== '[object Function]') {
|
||
throw new TypeError('iterator must be a function');
|
||
}
|
||
var l = obj.length;
|
||
if (l === +l) {
|
||
for (var i = 0; i < l; i++) {
|
||
fn.call(ctx, obj[i], i, obj);
|
||
}
|
||
} else {
|
||
for (var k in obj) {
|
||
if (hasOwn.call(obj, k)) {
|
||
fn.call(ctx, obj[k], k, obj);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
|
||
/***/ }),
|
||
/* 3 */
|
||
/***/ (function(module, exports) {
|
||
|
||
module.exports = function clone(obj) {
|
||
return JSON.parse(JSON.stringify(obj));
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 4 */
|
||
/***/ (function(module, exports) {
|
||
|
||
var g;
|
||
|
||
// This works in non-strict mode
|
||
g = (function() {
|
||
return this;
|
||
})();
|
||
|
||
try {
|
||
// This works if eval is allowed (see CSP)
|
||
g = g || Function("return this")() || (1,eval)("this");
|
||
} catch(e) {
|
||
// This works if the window reference is available
|
||
if(typeof window === "object")
|
||
g = window;
|
||
}
|
||
|
||
// g can still be undefined, but nothing to do about it...
|
||
// We return undefined, instead of nothing here, so it's
|
||
// easier to handle this case. if(!global) { ...}
|
||
|
||
module.exports = g;
|
||
|
||
|
||
/***/ }),
|
||
/* 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__(12);
|
||
|
||
function AlgoliaSearchError(message, extraProperties) {
|
||
var forEach = __webpack_require__(2);
|
||
|
||
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',
|
||
'<script> was loaded but did not call our provided callback'
|
||
),
|
||
JSONPScriptError: createCustomError(
|
||
'JSONPScriptError',
|
||
'<script> unable to load due to an `error` event on it'
|
||
),
|
||
Unknown: createCustomError(
|
||
'Unknown',
|
||
'Unknown error occured'
|
||
)
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 6 */
|
||
/***/ (function(module, exports) {
|
||
|
||
var toString = {}.toString;
|
||
|
||
module.exports = Array.isArray || function (arr) {
|
||
return toString.call(arr) == '[object Array]';
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 7 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
var foreach = __webpack_require__(2);
|
||
|
||
module.exports = function map(arr, fn) {
|
||
var newArr = [];
|
||
foreach(arr, function(item, itemIndex) {
|
||
newArr.push(fn(item, itemIndex, arr));
|
||
});
|
||
return newArr;
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 8 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(process) {/**
|
||
* This is the web browser implementation of `debug()`.
|
||
*
|
||
* Expose `debug()` as the module.
|
||
*/
|
||
|
||
exports = module.exports = __webpack_require__(39);
|
||
exports.log = log;
|
||
exports.formatArgs = formatArgs;
|
||
exports.save = save;
|
||
exports.load = load;
|
||
exports.useColors = useColors;
|
||
exports.storage = 'undefined' != typeof chrome
|
||
&& 'undefined' != typeof chrome.storage
|
||
? chrome.storage.local
|
||
: localstorage();
|
||
|
||
/**
|
||
* Colors.
|
||
*/
|
||
|
||
exports.colors = [
|
||
'lightseagreen',
|
||
'forestgreen',
|
||
'goldenrod',
|
||
'dodgerblue',
|
||
'darkorchid',
|
||
'crimson'
|
||
];
|
||
|
||
/**
|
||
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
|
||
* and the Firebug extension (any Firefox version) are known
|
||
* to support "%c" CSS customizations.
|
||
*
|
||
* TODO: add a `localStorage` variable to explicitly enable/disable colors
|
||
*/
|
||
|
||
function useColors() {
|
||
// NB: In an Electron preload script, document will be defined but not fully
|
||
// initialized. Since we know we're in Chrome, we'll just detect this case
|
||
// explicitly
|
||
if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') {
|
||
return true;
|
||
}
|
||
|
||
// is webkit? http://stackoverflow.com/a/16459606/376773
|
||
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
|
||
return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
|
||
// is firebug? http://stackoverflow.com/a/398120/376773
|
||
(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
|
||
// is firefox >= v31?
|
||
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
|
||
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
|
||
// double check webkit in userAgent just in case we are in a worker
|
||
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
|
||
}
|
||
|
||
/**
|
||
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
|
||
*/
|
||
|
||
exports.formatters.j = function(v) {
|
||
try {
|
||
return JSON.stringify(v);
|
||
} catch (err) {
|
||
return '[UnexpectedJSONParseError]: ' + err.message;
|
||
}
|
||
};
|
||
|
||
|
||
/**
|
||
* Colorize log arguments if enabled.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function formatArgs(args) {
|
||
var useColors = this.useColors;
|
||
|
||
args[0] = (useColors ? '%c' : '')
|
||
+ this.namespace
|
||
+ (useColors ? ' %c' : ' ')
|
||
+ args[0]
|
||
+ (useColors ? '%c ' : ' ')
|
||
+ '+' + exports.humanize(this.diff);
|
||
|
||
if (!useColors) return;
|
||
|
||
var c = 'color: ' + this.color;
|
||
args.splice(1, 0, c, 'color: inherit')
|
||
|
||
// the final "%c" is somewhat tricky, because there could be other
|
||
// arguments passed either before or after the %c, so we need to
|
||
// figure out the correct index to insert the CSS into
|
||
var index = 0;
|
||
var lastC = 0;
|
||
args[0].replace(/%[a-zA-Z%]/g, function(match) {
|
||
if ('%%' === match) return;
|
||
index++;
|
||
if ('%c' === match) {
|
||
// we only are interested in the *last* %c
|
||
// (the user may have provided their own)
|
||
lastC = index;
|
||
}
|
||
});
|
||
|
||
args.splice(lastC, 0, c);
|
||
}
|
||
|
||
/**
|
||
* Invokes `console.log()` when available.
|
||
* No-op when `console.log` is not a "function".
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function log() {
|
||
// this hackery is required for IE8/9, where
|
||
// the `console.log` function doesn't have 'apply'
|
||
return 'object' === typeof console
|
||
&& console.log
|
||
&& Function.prototype.apply.call(console.log, console, arguments);
|
||
}
|
||
|
||
/**
|
||
* Save `namespaces`.
|
||
*
|
||
* @param {String} namespaces
|
||
* @api private
|
||
*/
|
||
|
||
function save(namespaces) {
|
||
try {
|
||
if (null == namespaces) {
|
||
exports.storage.removeItem('debug');
|
||
} else {
|
||
exports.storage.debug = namespaces;
|
||
}
|
||
} catch(e) {}
|
||
}
|
||
|
||
/**
|
||
* Load `namespaces`.
|
||
*
|
||
* @return {String} returns the previously persisted debug modes
|
||
* @api private
|
||
*/
|
||
|
||
function load() {
|
||
var r;
|
||
try {
|
||
r = exports.storage.debug;
|
||
} catch(e) {}
|
||
|
||
// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
|
||
if (!r && typeof process !== 'undefined' && 'env' in process) {
|
||
r = Object({"NODE_ENV":"production"}).DEBUG;
|
||
}
|
||
|
||
return r;
|
||
}
|
||
|
||
/**
|
||
* Enable namespaces listed in `localStorage.debug` initially.
|
||
*/
|
||
|
||
exports.enable(load());
|
||
|
||
/**
|
||
* Localstorage attempts to return the localstorage.
|
||
*
|
||
* This is necessary because safari throws
|
||
* when a user disables cookies/localstorage
|
||
* and you attempt to access it.
|
||
*
|
||
* @return {LocalStorage}
|
||
* @api private
|
||
*/
|
||
|
||
function localstorage() {
|
||
try {
|
||
return window.localStorage;
|
||
} catch (e) {}
|
||
}
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9)))
|
||
|
||
/***/ }),
|
||
/* 9 */
|
||
/***/ (function(module, exports) {
|
||
|
||
// shim for using process in browser
|
||
var process = module.exports = {};
|
||
|
||
// cached from whatever global is present so that test runners that stub it
|
||
// don't break things. But we need to wrap it in a try catch in case it is
|
||
// wrapped in strict mode code which doesn't define any globals. It's inside a
|
||
// function because try/catches deoptimize in certain engines.
|
||
|
||
var cachedSetTimeout;
|
||
var cachedClearTimeout;
|
||
|
||
function defaultSetTimout() {
|
||
throw new Error('setTimeout has not been defined');
|
||
}
|
||
function defaultClearTimeout () {
|
||
throw new Error('clearTimeout has not been defined');
|
||
}
|
||
(function () {
|
||
try {
|
||
if (typeof setTimeout === 'function') {
|
||
cachedSetTimeout = setTimeout;
|
||
} else {
|
||
cachedSetTimeout = defaultSetTimout;
|
||
}
|
||
} catch (e) {
|
||
cachedSetTimeout = defaultSetTimout;
|
||
}
|
||
try {
|
||
if (typeof clearTimeout === 'function') {
|
||
cachedClearTimeout = clearTimeout;
|
||
} else {
|
||
cachedClearTimeout = defaultClearTimeout;
|
||
}
|
||
} catch (e) {
|
||
cachedClearTimeout = defaultClearTimeout;
|
||
}
|
||
} ())
|
||
function runTimeout(fun) {
|
||
if (cachedSetTimeout === setTimeout) {
|
||
//normal enviroments in sane situations
|
||
return setTimeout(fun, 0);
|
||
}
|
||
// if setTimeout wasn't available but was latter defined
|
||
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
||
cachedSetTimeout = setTimeout;
|
||
return setTimeout(fun, 0);
|
||
}
|
||
try {
|
||
// when when somebody has screwed with setTimeout but no I.E. maddness
|
||
return cachedSetTimeout(fun, 0);
|
||
} catch(e){
|
||
try {
|
||
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
||
return cachedSetTimeout.call(null, fun, 0);
|
||
} catch(e){
|
||
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
|
||
return cachedSetTimeout.call(this, fun, 0);
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
function runClearTimeout(marker) {
|
||
if (cachedClearTimeout === clearTimeout) {
|
||
//normal enviroments in sane situations
|
||
return clearTimeout(marker);
|
||
}
|
||
// if clearTimeout wasn't available but was latter defined
|
||
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
||
cachedClearTimeout = clearTimeout;
|
||
return clearTimeout(marker);
|
||
}
|
||
try {
|
||
// when when somebody has screwed with setTimeout but no I.E. maddness
|
||
return cachedClearTimeout(marker);
|
||
} catch (e){
|
||
try {
|
||
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
||
return cachedClearTimeout.call(null, marker);
|
||
} catch (e){
|
||
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
|
||
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
|
||
return cachedClearTimeout.call(this, marker);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
}
|
||
var queue = [];
|
||
var draining = false;
|
||
var currentQueue;
|
||
var queueIndex = -1;
|
||
|
||
function cleanUpNextTick() {
|
||
if (!draining || !currentQueue) {
|
||
return;
|
||
}
|
||
draining = false;
|
||
if (currentQueue.length) {
|
||
queue = currentQueue.concat(queue);
|
||
} else {
|
||
queueIndex = -1;
|
||
}
|
||
if (queue.length) {
|
||
drainQueue();
|
||
}
|
||
}
|
||
|
||
function drainQueue() {
|
||
if (draining) {
|
||
return;
|
||
}
|
||
var timeout = runTimeout(cleanUpNextTick);
|
||
draining = true;
|
||
|
||
var len = queue.length;
|
||
while(len) {
|
||
currentQueue = queue;
|
||
queue = [];
|
||
while (++queueIndex < len) {
|
||
if (currentQueue) {
|
||
currentQueue[queueIndex].run();
|
||
}
|
||
}
|
||
queueIndex = -1;
|
||
len = queue.length;
|
||
}
|
||
currentQueue = null;
|
||
draining = false;
|
||
runClearTimeout(timeout);
|
||
}
|
||
|
||
process.nextTick = function (fun) {
|
||
var args = new Array(arguments.length - 1);
|
||
if (arguments.length > 1) {
|
||
for (var i = 1; i < arguments.length; i++) {
|
||
args[i - 1] = arguments[i];
|
||
}
|
||
}
|
||
queue.push(new Item(fun, args));
|
||
if (queue.length === 1 && !draining) {
|
||
runTimeout(drainQueue);
|
||
}
|
||
};
|
||
|
||
// v8 likes predictible objects
|
||
function Item(fun, array) {
|
||
this.fun = fun;
|
||
this.array = array;
|
||
}
|
||
Item.prototype.run = function () {
|
||
this.fun.apply(null, this.array);
|
||
};
|
||
process.title = 'browser';
|
||
process.browser = true;
|
||
process.env = {};
|
||
process.argv = [];
|
||
process.version = ''; // empty string to avoid regexp issues
|
||
process.versions = {};
|
||
|
||
function noop() {}
|
||
|
||
process.on = noop;
|
||
process.addListener = noop;
|
||
process.once = noop;
|
||
process.off = noop;
|
||
process.removeListener = noop;
|
||
process.removeAllListeners = noop;
|
||
process.emit = noop;
|
||
process.prependListener = noop;
|
||
process.prependOnceListener = noop;
|
||
|
||
process.listeners = function (name) { return [] }
|
||
|
||
process.binding = function (name) {
|
||
throw new Error('process.binding is not supported');
|
||
};
|
||
|
||
process.cwd = function () { return '/' };
|
||
process.chdir = function (dir) {
|
||
throw new Error('process.chdir is not supported');
|
||
};
|
||
process.umask = function() { return 0; };
|
||
|
||
|
||
/***/ }),
|
||
/* 10 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var immediate = __webpack_require__(53);
|
||
var splitter = /\s+/;
|
||
|
||
module.exports = {
|
||
onSync: onSync,
|
||
onAsync: onAsync,
|
||
off: off,
|
||
trigger: trigger
|
||
};
|
||
|
||
function on(method, types, cb, context) {
|
||
var type;
|
||
|
||
if (!cb) {
|
||
return this;
|
||
}
|
||
|
||
types = types.split(splitter);
|
||
cb = context ? bindContext(cb, context) : cb;
|
||
|
||
this._callbacks = this._callbacks || {};
|
||
|
||
while (type = types.shift()) {
|
||
this._callbacks[type] = this._callbacks[type] || {sync: [], async: []};
|
||
this._callbacks[type][method].push(cb);
|
||
}
|
||
|
||
return this;
|
||
}
|
||
|
||
function onAsync(types, cb, context) {
|
||
return on.call(this, 'async', types, cb, context);
|
||
}
|
||
|
||
function onSync(types, cb, context) {
|
||
return on.call(this, 'sync', types, cb, context);
|
||
}
|
||
|
||
function off(types) {
|
||
var type;
|
||
|
||
if (!this._callbacks) {
|
||
return this;
|
||
}
|
||
|
||
types = types.split(splitter);
|
||
|
||
while (type = types.shift()) {
|
||
delete this._callbacks[type];
|
||
}
|
||
|
||
return this;
|
||
}
|
||
|
||
function trigger(types) {
|
||
var type;
|
||
var callbacks;
|
||
var args;
|
||
var syncFlush;
|
||
var asyncFlush;
|
||
|
||
if (!this._callbacks) {
|
||
return this;
|
||
}
|
||
|
||
types = types.split(splitter);
|
||
args = [].slice.call(arguments, 1);
|
||
|
||
while ((type = types.shift()) && (callbacks = this._callbacks[type])) { // eslint-disable-line
|
||
syncFlush = getFlush(callbacks.sync, this, [type].concat(args));
|
||
asyncFlush = getFlush(callbacks.async, this, [type].concat(args));
|
||
|
||
if (syncFlush()) {
|
||
immediate(asyncFlush);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
}
|
||
|
||
function getFlush(callbacks, context, args) {
|
||
return flush;
|
||
|
||
function flush() {
|
||
var cancelled;
|
||
|
||
for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
|
||
// only cancel if the callback explicitly returns false
|
||
cancelled = callbacks[i].apply(context, args) === false;
|
||
}
|
||
|
||
return !cancelled;
|
||
}
|
||
}
|
||
|
||
function bindContext(fn, context) {
|
||
return fn.bind ?
|
||
fn.bind(context) :
|
||
function() { fn.apply(context, [].slice.call(arguments, 0)); };
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 11 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var _ = __webpack_require__(0);
|
||
|
||
var css = {
|
||
wrapper: {
|
||
position: 'relative',
|
||
display: 'inline-block'
|
||
},
|
||
hint: {
|
||
position: 'absolute',
|
||
top: '0',
|
||
left: '0',
|
||
borderColor: 'transparent',
|
||
boxShadow: 'none',
|
||
// #741: fix hint opacity issue on iOS
|
||
opacity: '1'
|
||
},
|
||
input: {
|
||
position: 'relative',
|
||
verticalAlign: 'top',
|
||
backgroundColor: 'transparent'
|
||
},
|
||
inputWithNoHint: {
|
||
position: 'relative',
|
||
verticalAlign: 'top'
|
||
},
|
||
dropdown: {
|
||
position: 'absolute',
|
||
top: '100%',
|
||
left: '0',
|
||
zIndex: '100',
|
||
display: 'none'
|
||
},
|
||
suggestions: {
|
||
display: 'block'
|
||
},
|
||
suggestion: {
|
||
whiteSpace: 'nowrap',
|
||
cursor: 'pointer'
|
||
},
|
||
suggestionChild: {
|
||
whiteSpace: 'normal'
|
||
},
|
||
ltr: {
|
||
left: '0',
|
||
right: 'auto'
|
||
},
|
||
rtl: {
|
||
left: 'auto',
|
||
right: '0'
|
||
},
|
||
defaultClasses: {
|
||
root: 'algolia-autocomplete',
|
||
prefix: 'aa',
|
||
noPrefix: false,
|
||
dropdownMenu: 'dropdown-menu',
|
||
input: 'input',
|
||
hint: 'hint',
|
||
suggestions: 'suggestions',
|
||
suggestion: 'suggestion',
|
||
cursor: 'cursor',
|
||
dataset: 'dataset',
|
||
empty: 'empty'
|
||
},
|
||
// will be merged with the default ones if appendTo is used
|
||
appendTo: {
|
||
wrapper: {
|
||
position: 'absolute',
|
||
zIndex: '100',
|
||
display: 'none'
|
||
},
|
||
input: {},
|
||
inputWithNoHint: {},
|
||
dropdown: {
|
||
display: 'block'
|
||
}
|
||
}
|
||
};
|
||
|
||
// ie specific styling
|
||
if (_.isMsie()) {
|
||
// ie6-8 (and 9?) doesn't fire hover and click events for elements with
|
||
// transparent backgrounds, for a workaround, use 1x1 transparent gif
|
||
_.mixin(css.input, {
|
||
backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)'
|
||
});
|
||
}
|
||
|
||
// ie7 and under specific styling
|
||
if (_.isMsie() && _.isMsie() <= 7) {
|
||
// if someone can tell me why this is necessary to align
|
||
// the hint with the query in ie7, i'll send you $5 - @JakeHarding
|
||
_.mixin(css.input, {marginTop: '-1px'});
|
||
}
|
||
|
||
module.exports = css;
|
||
|
||
|
||
/***/ }),
|
||
/* 12 */
|
||
/***/ (function(module, exports) {
|
||
|
||
if (typeof Object.create === 'function') {
|
||
// implementation from standard node.js 'util' module
|
||
module.exports = function inherits(ctor, superCtor) {
|
||
ctor.super_ = superCtor
|
||
ctor.prototype = Object.create(superCtor.prototype, {
|
||
constructor: {
|
||
value: ctor,
|
||
enumerable: false,
|
||
writable: true,
|
||
configurable: true
|
||
}
|
||
});
|
||
};
|
||
} else {
|
||
// old school shim for old browsers
|
||
module.exports = function inherits(ctor, superCtor) {
|
||
ctor.super_ = superCtor
|
||
var TempCtor = function () {}
|
||
TempCtor.prototype = superCtor.prototype
|
||
ctor.prototype = new TempCtor()
|
||
ctor.prototype.constructor = ctor
|
||
}
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 13 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = buildSearchMethod;
|
||
|
||
var errors = __webpack_require__(5);
|
||
|
||
/**
|
||
* Creates a search method to be used in clients
|
||
* @param {string} queryParam the name of the attribute used for the query
|
||
* @param {string} url the url
|
||
* @return {function} the search method
|
||
*/
|
||
function buildSearchMethod(queryParam, url) {
|
||
/**
|
||
* The search method. Prepares the data and send the query to Algolia.
|
||
* @param {string} query the string used for query search
|
||
* @param {object} args additional parameters to send with the search
|
||
* @param {function} [callback] the callback to be called with the client gets the answer
|
||
* @return {undefined|Promise} If the callback is not provided then this methods returns a Promise
|
||
*/
|
||
return function search(query, args, callback) {
|
||
// warn V2 users on how to search
|
||
if (typeof query === 'function' && typeof args === 'object' ||
|
||
typeof callback === 'object') {
|
||
// .search(query, params, cb)
|
||
// .search(cb, params)
|
||
throw new errors.AlgoliaSearchError('index.search usage is index.search(query, params, cb)');
|
||
}
|
||
|
||
// Normalizing the function signature
|
||
if (arguments.length === 0 || typeof query === 'function') {
|
||
// Usage : .search(), .search(cb)
|
||
callback = query;
|
||
query = '';
|
||
} else if (arguments.length === 1 || typeof args === 'function') {
|
||
// Usage : .search(query/args), .search(query, cb)
|
||
callback = args;
|
||
args = undefined;
|
||
}
|
||
// At this point we have 3 arguments with values
|
||
|
||
// Usage : .search(args) // careful: typeof null === 'object'
|
||
if (typeof query === 'object' && query !== null) {
|
||
args = query;
|
||
query = undefined;
|
||
} else if (query === undefined || query === null) { // .search(undefined/null)
|
||
query = '';
|
||
}
|
||
|
||
var params = '';
|
||
|
||
if (query !== undefined) {
|
||
params += queryParam + '=' + encodeURIComponent(query);
|
||
}
|
||
|
||
var additionalUA;
|
||
if (args !== undefined) {
|
||
if (args.additionalUA) {
|
||
additionalUA = args.additionalUA;
|
||
delete args.additionalUA;
|
||
}
|
||
// `_getSearchParams` will augment params, do not be fooled by the = versus += from previous if
|
||
params = this.as._getSearchParams(args, params);
|
||
}
|
||
|
||
|
||
return this._search(params, url, callback, additionalUA);
|
||
};
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 14 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = function omit(obj, test) {
|
||
var keys = __webpack_require__(36);
|
||
var foreach = __webpack_require__(2);
|
||
|
||
var filtered = {};
|
||
|
||
foreach(keys(obj), function doFilter(keyName) {
|
||
if (test(keyName) !== true) {
|
||
filtered[keyName] = obj[keyName];
|
||
}
|
||
});
|
||
|
||
return filtered;
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 15 */
|
||
/***/ (function(module, exports) {
|
||
|
||
/* istanbul ignore next */
|
||
/* Zepto v1.2.0 - zepto event assets data - zeptojs.com/license */
|
||
(function(global, factory) {
|
||
module.exports = factory(global);
|
||
}(/* this ##### UPDATED: here we want to use window/global instead of this which is the current file context ##### */ window, function(window) {
|
||
var Zepto = (function() {
|
||
var undefined, key, $, classList, emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter, slice = emptyArray.slice,
|
||
document = window.document,
|
||
elementDisplay = {}, classCache = {},
|
||
cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 },
|
||
fragmentRE = /^\s*<(\w+|!)[^>]*>/,
|
||
singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
|
||
tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
|
||
rootNodeRE = /^(?:body|html)$/i,
|
||
capitalRE = /([A-Z])/g,
|
||
|
||
// special attributes that should be get/set via method calls
|
||
methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'],
|
||
|
||
adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ],
|
||
table = document.createElement('table'),
|
||
tableRow = document.createElement('tr'),
|
||
containers = {
|
||
'tr': document.createElement('tbody'),
|
||
'tbody': table, 'thead': table, 'tfoot': table,
|
||
'td': tableRow, 'th': tableRow,
|
||
'*': document.createElement('div')
|
||
},
|
||
readyRE = /complete|loaded|interactive/,
|
||
simpleSelectorRE = /^[\w-]*$/,
|
||
class2type = {},
|
||
toString = class2type.toString,
|
||
zepto = {},
|
||
camelize, uniq,
|
||
tempParent = document.createElement('div'),
|
||
propMap = {
|
||
'tabindex': 'tabIndex',
|
||
'readonly': 'readOnly',
|
||
'for': 'htmlFor',
|
||
'class': 'className',
|
||
'maxlength': 'maxLength',
|
||
'cellspacing': 'cellSpacing',
|
||
'cellpadding': 'cellPadding',
|
||
'rowspan': 'rowSpan',
|
||
'colspan': 'colSpan',
|
||
'usemap': 'useMap',
|
||
'frameborder': 'frameBorder',
|
||
'contenteditable': 'contentEditable'
|
||
},
|
||
isArray = Array.isArray ||
|
||
function(object){ return object instanceof Array }
|
||
|
||
zepto.matches = function(element, selector) {
|
||
if (!selector || !element || element.nodeType !== 1) return false
|
||
var matchesSelector = element.matches || element.webkitMatchesSelector ||
|
||
element.mozMatchesSelector || element.oMatchesSelector ||
|
||
element.matchesSelector
|
||
if (matchesSelector) return matchesSelector.call(element, selector)
|
||
// fall back to performing a selector:
|
||
var match, parent = element.parentNode, temp = !parent
|
||
if (temp) (parent = tempParent).appendChild(element)
|
||
match = ~zepto.qsa(parent, selector).indexOf(element)
|
||
temp && tempParent.removeChild(element)
|
||
return match
|
||
}
|
||
|
||
function type(obj) {
|
||
return obj == null ? String(obj) :
|
||
class2type[toString.call(obj)] || "object"
|
||
}
|
||
|
||
function isFunction(value) { return type(value) == "function" }
|
||
function isWindow(obj) { return obj != null && obj == obj.window }
|
||
function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE }
|
||
function isObject(obj) { return type(obj) == "object" }
|
||
function isPlainObject(obj) {
|
||
return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype
|
||
}
|
||
|
||
function likeArray(obj) {
|
||
var length = !!obj && 'length' in obj && obj.length,
|
||
type = $.type(obj)
|
||
|
||
return 'function' != type && !isWindow(obj) && (
|
||
'array' == type || length === 0 ||
|
||
(typeof length == 'number' && length > 0 && (length - 1) in obj)
|
||
)
|
||
}
|
||
|
||
function compact(array) { return filter.call(array, function(item){ return item != null }) }
|
||
function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array }
|
||
camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }
|
||
function dasherize(str) {
|
||
return str.replace(/::/g, '/')
|
||
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
|
||
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
|
||
.replace(/_/g, '-')
|
||
.toLowerCase()
|
||
}
|
||
uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) }
|
||
|
||
function classRE(name) {
|
||
return name in classCache ?
|
||
classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'))
|
||
}
|
||
|
||
function maybeAddPx(name, value) {
|
||
return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value
|
||
}
|
||
|
||
function defaultDisplay(nodeName) {
|
||
var element, display
|
||
if (!elementDisplay[nodeName]) {
|
||
element = document.createElement(nodeName)
|
||
document.body.appendChild(element)
|
||
display = getComputedStyle(element, '').getPropertyValue("display")
|
||
element.parentNode.removeChild(element)
|
||
display == "none" && (display = "block")
|
||
elementDisplay[nodeName] = display
|
||
}
|
||
return elementDisplay[nodeName]
|
||
}
|
||
|
||
function children(element) {
|
||
return 'children' in element ?
|
||
slice.call(element.children) :
|
||
$.map(element.childNodes, function(node){ if (node.nodeType == 1) return node })
|
||
}
|
||
|
||
function Z(dom, selector) {
|
||
var i, len = dom ? dom.length : 0
|
||
for (i = 0; i < len; i++) this[i] = dom[i]
|
||
this.length = len
|
||
this.selector = selector || ''
|
||
}
|
||
|
||
// `$.zepto.fragment` takes a html string and an optional tag name
|
||
// to generate DOM nodes from the given html string.
|
||
// The generated DOM nodes are returned as an array.
|
||
// This function can be overridden in plugins for example to make
|
||
// it compatible with browsers that don't support the DOM fully.
|
||
zepto.fragment = function(html, name, properties) {
|
||
var dom, nodes, container
|
||
|
||
// A special case optimization for a single tag
|
||
if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))
|
||
|
||
if (!dom) {
|
||
if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>")
|
||
if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
|
||
if (!(name in containers)) name = '*'
|
||
|
||
container = containers[name]
|
||
container.innerHTML = '' + html
|
||
dom = $.each(slice.call(container.childNodes), function(){
|
||
container.removeChild(this)
|
||
})
|
||
}
|
||
|
||
if (isPlainObject(properties)) {
|
||
nodes = $(dom)
|
||
$.each(properties, function(key, value) {
|
||
if (methodAttributes.indexOf(key) > -1) nodes[key](value)
|
||
else nodes.attr(key, value)
|
||
})
|
||
}
|
||
|
||
return dom
|
||
}
|
||
|
||
// `$.zepto.Z` swaps out the prototype of the given `dom` array
|
||
// of nodes with `$.fn` and thus supplying all the Zepto functions
|
||
// to the array. This method can be overridden in plugins.
|
||
zepto.Z = function(dom, selector) {
|
||
return new Z(dom, selector)
|
||
}
|
||
|
||
// `$.zepto.isZ` should return `true` if the given object is a Zepto
|
||
// collection. This method can be overridden in plugins.
|
||
zepto.isZ = function(object) {
|
||
return object instanceof zepto.Z
|
||
}
|
||
|
||
// `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and
|
||
// takes a CSS selector and an optional context (and handles various
|
||
// special cases).
|
||
// This method can be overridden in plugins.
|
||
zepto.init = function(selector, context) {
|
||
var dom
|
||
// If nothing given, return an empty Zepto collection
|
||
if (!selector) return zepto.Z()
|
||
// Optimize for string selectors
|
||
else if (typeof selector == 'string') {
|
||
selector = selector.trim()
|
||
// If it's a html fragment, create nodes from it
|
||
// Note: In both Chrome 21 and Firefox 15, DOM error 12
|
||
// is thrown if the fragment doesn't begin with <
|
||
if (selector[0] == '<' && fragmentRE.test(selector))
|
||
dom = zepto.fragment(selector, RegExp.$1, context), selector = null
|
||
// If there's a context, create a collection on that context first, and select
|
||
// nodes from there
|
||
else if (context !== undefined) return $(context).find(selector)
|
||
// If it's a CSS selector, use it to select nodes.
|
||
else dom = zepto.qsa(document, selector)
|
||
}
|
||
// If a function is given, call it when the DOM is ready
|
||
else if (isFunction(selector)) return $(document).ready(selector)
|
||
// If a Zepto collection is given, just return it
|
||
else if (zepto.isZ(selector)) return selector
|
||
else {
|
||
// normalize array if an array of nodes is given
|
||
if (isArray(selector)) dom = compact(selector)
|
||
// Wrap DOM nodes.
|
||
else if (isObject(selector))
|
||
dom = [selector], selector = null
|
||
// If it's a html fragment, create nodes from it
|
||
else if (fragmentRE.test(selector))
|
||
dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
|
||
// If there's a context, create a collection on that context first, and select
|
||
// nodes from there
|
||
else if (context !== undefined) return $(context).find(selector)
|
||
// And last but no least, if it's a CSS selector, use it to select nodes.
|
||
else dom = zepto.qsa(document, selector)
|
||
}
|
||
// create a new Zepto collection from the nodes found
|
||
return zepto.Z(dom, selector)
|
||
}
|
||
|
||
// `$` will be the base `Zepto` object. When calling this
|
||
// function just call `$.zepto.init, which makes the implementation
|
||
// details of selecting nodes and creating Zepto collections
|
||
// patchable in plugins.
|
||
$ = function(selector, context){
|
||
return zepto.init(selector, context)
|
||
}
|
||
|
||
function extend(target, source, deep) {
|
||
for (key in source)
|
||
if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
|
||
if (isPlainObject(source[key]) && !isPlainObject(target[key]))
|
||
target[key] = {}
|
||
if (isArray(source[key]) && !isArray(target[key]))
|
||
target[key] = []
|
||
extend(target[key], source[key], deep)
|
||
}
|
||
else if (source[key] !== undefined) target[key] = source[key]
|
||
}
|
||
|
||
// Copy all but undefined properties from one or more
|
||
// objects to the `target` object.
|
||
$.extend = function(target){
|
||
var deep, args = slice.call(arguments, 1)
|
||
if (typeof target == 'boolean') {
|
||
deep = target
|
||
target = args.shift()
|
||
}
|
||
args.forEach(function(arg){ extend(target, arg, deep) })
|
||
return target
|
||
}
|
||
|
||
// `$.zepto.qsa` is Zepto's CSS selector implementation which
|
||
// uses `document.querySelectorAll` and optimizes for some special cases, like `#id`.
|
||
// This method can be overridden in plugins.
|
||
zepto.qsa = function(element, selector){
|
||
var found,
|
||
maybeID = selector[0] == '#',
|
||
maybeClass = !maybeID && selector[0] == '.',
|
||
nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
|
||
isSimple = simpleSelectorRE.test(nameOnly)
|
||
return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById
|
||
( (found = element.getElementById(nameOnly)) ? [found] : [] ) :
|
||
(element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] :
|
||
slice.call(
|
||
isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName
|
||
maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class
|
||
element.getElementsByTagName(selector) : // Or a tag
|
||
element.querySelectorAll(selector) // Or it's not simple, and we need to query all
|
||
)
|
||
}
|
||
|
||
function filtered(nodes, selector) {
|
||
return selector == null ? $(nodes) : $(nodes).filter(selector)
|
||
}
|
||
|
||
$.contains = document.documentElement.contains ?
|
||
function(parent, node) {
|
||
return parent !== node && parent.contains(node)
|
||
} :
|
||
function(parent, node) {
|
||
while (node && (node = node.parentNode))
|
||
if (node === parent) return true
|
||
return false
|
||
}
|
||
|
||
function funcArg(context, arg, idx, payload) {
|
||
return isFunction(arg) ? arg.call(context, idx, payload) : arg
|
||
}
|
||
|
||
function setAttribute(node, name, value) {
|
||
value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
|
||
}
|
||
|
||
// access className property while respecting SVGAnimatedString
|
||
function className(node, value){
|
||
var klass = node.className || '',
|
||
svg = klass && klass.baseVal !== undefined
|
||
|
||
if (value === undefined) return svg ? klass.baseVal : klass
|
||
svg ? (klass.baseVal = value) : (node.className = value)
|
||
}
|
||
|
||
// "true" => true
|
||
// "false" => false
|
||
// "null" => null
|
||
// "42" => 42
|
||
// "42.5" => 42.5
|
||
// "08" => "08"
|
||
// JSON => parse if valid
|
||
// String => self
|
||
function deserializeValue(value) {
|
||
try {
|
||
return value ?
|
||
value == "true" ||
|
||
( value == "false" ? false :
|
||
value == "null" ? null :
|
||
+value + "" == value ? +value :
|
||
/^[\[\{]/.test(value) ? $.parseJSON(value) :
|
||
value )
|
||
: value
|
||
} catch(e) {
|
||
return value
|
||
}
|
||
}
|
||
|
||
$.type = type
|
||
$.isFunction = isFunction
|
||
$.isWindow = isWindow
|
||
$.isArray = isArray
|
||
$.isPlainObject = isPlainObject
|
||
|
||
$.isEmptyObject = function(obj) {
|
||
var name
|
||
for (name in obj) return false
|
||
return true
|
||
}
|
||
|
||
$.isNumeric = function(val) {
|
||
var num = Number(val), type = typeof val
|
||
return val != null && type != 'boolean' &&
|
||
(type != 'string' || val.length) &&
|
||
!isNaN(num) && isFinite(num) || false
|
||
}
|
||
|
||
$.inArray = function(elem, array, i){
|
||
return emptyArray.indexOf.call(array, elem, i)
|
||
}
|
||
|
||
$.camelCase = camelize
|
||
$.trim = function(str) {
|
||
return str == null ? "" : String.prototype.trim.call(str)
|
||
}
|
||
|
||
// plugin compatibility
|
||
$.uuid = 0
|
||
$.support = { }
|
||
$.expr = { }
|
||
$.noop = function() {}
|
||
|
||
$.map = function(elements, callback){
|
||
var value, values = [], i, key
|
||
if (likeArray(elements))
|
||
for (i = 0; i < elements.length; i++) {
|
||
value = callback(elements[i], i)
|
||
if (value != null) values.push(value)
|
||
}
|
||
else
|
||
for (key in elements) {
|
||
value = callback(elements[key], key)
|
||
if (value != null) values.push(value)
|
||
}
|
||
return flatten(values)
|
||
}
|
||
|
||
$.each = function(elements, callback){
|
||
var i, key
|
||
if (likeArray(elements)) {
|
||
for (i = 0; i < elements.length; i++)
|
||
if (callback.call(elements[i], i, elements[i]) === false) return elements
|
||
} else {
|
||
for (key in elements)
|
||
if (callback.call(elements[key], key, elements[key]) === false) return elements
|
||
}
|
||
|
||
return elements
|
||
}
|
||
|
||
$.grep = function(elements, callback){
|
||
return filter.call(elements, callback)
|
||
}
|
||
|
||
if (window.JSON) $.parseJSON = JSON.parse
|
||
|
||
// Populate the class2type map
|
||
$.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
|
||
class2type[ "[object " + name + "]" ] = name.toLowerCase()
|
||
})
|
||
|
||
// Define methods that will be available on all
|
||
// Zepto collections
|
||
$.fn = {
|
||
constructor: zepto.Z,
|
||
length: 0,
|
||
|
||
// Because a collection acts like an array
|
||
// copy over these useful array functions.
|
||
forEach: emptyArray.forEach,
|
||
reduce: emptyArray.reduce,
|
||
push: emptyArray.push,
|
||
sort: emptyArray.sort,
|
||
splice: emptyArray.splice,
|
||
indexOf: emptyArray.indexOf,
|
||
concat: function(){
|
||
var i, value, args = []
|
||
for (i = 0; i < arguments.length; i++) {
|
||
value = arguments[i]
|
||
args[i] = zepto.isZ(value) ? value.toArray() : value
|
||
}
|
||
return concat.apply(zepto.isZ(this) ? this.toArray() : this, args)
|
||
},
|
||
|
||
// `map` and `slice` in the jQuery API work differently
|
||
// from their array counterparts
|
||
map: function(fn){
|
||
return $($.map(this, function(el, i){ return fn.call(el, i, el) }))
|
||
},
|
||
slice: function(){
|
||
return $(slice.apply(this, arguments))
|
||
},
|
||
|
||
ready: function(callback){
|
||
// need to check if document.body exists for IE as that browser reports
|
||
// document ready when it hasn't yet created the body element
|
||
if (readyRE.test(document.readyState) && document.body) callback($)
|
||
else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
|
||
return this
|
||
},
|
||
get: function(idx){
|
||
return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
|
||
},
|
||
toArray: function(){ return this.get() },
|
||
size: function(){
|
||
return this.length
|
||
},
|
||
remove: function(){
|
||
return this.each(function(){
|
||
if (this.parentNode != null)
|
||
this.parentNode.removeChild(this)
|
||
})
|
||
},
|
||
each: function(callback){
|
||
emptyArray.every.call(this, function(el, idx){
|
||
return callback.call(el, idx, el) !== false
|
||
})
|
||
return this
|
||
},
|
||
filter: function(selector){
|
||
if (isFunction(selector)) return this.not(this.not(selector))
|
||
return $(filter.call(this, function(element){
|
||
return zepto.matches(element, selector)
|
||
}))
|
||
},
|
||
add: function(selector,context){
|
||
return $(uniq(this.concat($(selector,context))))
|
||
},
|
||
is: function(selector){
|
||
return this.length > 0 && zepto.matches(this[0], selector)
|
||
},
|
||
not: function(selector){
|
||
var nodes=[]
|
||
if (isFunction(selector) && selector.call !== undefined)
|
||
this.each(function(idx){
|
||
if (!selector.call(this,idx)) nodes.push(this)
|
||
})
|
||
else {
|
||
var excludes = typeof selector == 'string' ? this.filter(selector) :
|
||
(likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
|
||
this.forEach(function(el){
|
||
if (excludes.indexOf(el) < 0) nodes.push(el)
|
||
})
|
||
}
|
||
return $(nodes)
|
||
},
|
||
has: function(selector){
|
||
return this.filter(function(){
|
||
return isObject(selector) ?
|
||
$.contains(this, selector) :
|
||
$(this).find(selector).size()
|
||
})
|
||
},
|
||
eq: function(idx){
|
||
return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1)
|
||
},
|
||
first: function(){
|
||
var el = this[0]
|
||
return el && !isObject(el) ? el : $(el)
|
||
},
|
||
last: function(){
|
||
var el = this[this.length - 1]
|
||
return el && !isObject(el) ? el : $(el)
|
||
},
|
||
find: function(selector){
|
||
var result, $this = this
|
||
if (!selector) result = $()
|
||
else if (typeof selector == 'object')
|
||
result = $(selector).filter(function(){
|
||
var node = this
|
||
return emptyArray.some.call($this, function(parent){
|
||
return $.contains(parent, node)
|
||
})
|
||
})
|
||
else if (this.length == 1) result = $(zepto.qsa(this[0], selector))
|
||
else result = this.map(function(){ return zepto.qsa(this, selector) })
|
||
return result
|
||
},
|
||
closest: function(selector, context){
|
||
var nodes = [], collection = typeof selector == 'object' && $(selector)
|
||
this.each(function(_, node){
|
||
while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector)))
|
||
node = node !== context && !isDocument(node) && node.parentNode
|
||
if (node && nodes.indexOf(node) < 0) nodes.push(node)
|
||
})
|
||
return $(nodes)
|
||
},
|
||
parents: function(selector){
|
||
var ancestors = [], nodes = this
|
||
while (nodes.length > 0)
|
||
nodes = $.map(nodes, function(node){
|
||
if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) {
|
||
ancestors.push(node)
|
||
return node
|
||
}
|
||
})
|
||
return filtered(ancestors, selector)
|
||
},
|
||
parent: function(selector){
|
||
return filtered(uniq(this.pluck('parentNode')), selector)
|
||
},
|
||
children: function(selector){
|
||
return filtered(this.map(function(){ return children(this) }), selector)
|
||
},
|
||
contents: function() {
|
||
return this.map(function() { return this.contentDocument || slice.call(this.childNodes) })
|
||
},
|
||
siblings: function(selector){
|
||
return filtered(this.map(function(i, el){
|
||
return filter.call(children(el.parentNode), function(child){ return child!==el })
|
||
}), selector)
|
||
},
|
||
empty: function(){
|
||
return this.each(function(){ this.innerHTML = '' })
|
||
},
|
||
// `pluck` is borrowed from Prototype.js
|
||
pluck: function(property){
|
||
return $.map(this, function(el){ return el[property] })
|
||
},
|
||
show: function(){
|
||
return this.each(function(){
|
||
this.style.display == "none" && (this.style.display = '')
|
||
if (getComputedStyle(this, '').getPropertyValue("display") == "none")
|
||
this.style.display = defaultDisplay(this.nodeName)
|
||
})
|
||
},
|
||
replaceWith: function(newContent){
|
||
return this.before(newContent).remove()
|
||
},
|
||
wrap: function(structure){
|
||
var func = isFunction(structure)
|
||
if (this[0] && !func)
|
||
var dom = $(structure).get(0),
|
||
clone = dom.parentNode || this.length > 1
|
||
|
||
return this.each(function(index){
|
||
$(this).wrapAll(
|
||
func ? structure.call(this, index) :
|
||
clone ? dom.cloneNode(true) : dom
|
||
)
|
||
})
|
||
},
|
||
wrapAll: function(structure){
|
||
if (this[0]) {
|
||
$(this[0]).before(structure = $(structure))
|
||
var children
|
||
// drill down to the inmost element
|
||
while ((children = structure.children()).length) structure = children.first()
|
||
$(structure).append(this)
|
||
}
|
||
return this
|
||
},
|
||
wrapInner: function(structure){
|
||
var func = isFunction(structure)
|
||
return this.each(function(index){
|
||
var self = $(this), contents = self.contents(),
|
||
dom = func ? structure.call(this, index) : structure
|
||
contents.length ? contents.wrapAll(dom) : self.append(dom)
|
||
})
|
||
},
|
||
unwrap: function(){
|
||
this.parent().each(function(){
|
||
$(this).replaceWith($(this).children())
|
||
})
|
||
return this
|
||
},
|
||
clone: function(){
|
||
return this.map(function(){ return this.cloneNode(true) })
|
||
},
|
||
hide: function(){
|
||
return this.css("display", "none")
|
||
},
|
||
toggle: function(setting){
|
||
return this.each(function(){
|
||
var el = $(this)
|
||
;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide()
|
||
})
|
||
},
|
||
prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') },
|
||
next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') },
|
||
html: function(html){
|
||
return 0 in arguments ?
|
||
this.each(function(idx){
|
||
var originHtml = this.innerHTML
|
||
$(this).empty().append( funcArg(this, html, idx, originHtml) )
|
||
}) :
|
||
(0 in this ? this[0].innerHTML : null)
|
||
},
|
||
text: function(text){
|
||
return 0 in arguments ?
|
||
this.each(function(idx){
|
||
var newText = funcArg(this, text, idx, this.textContent)
|
||
this.textContent = newText == null ? '' : ''+newText
|
||
}) :
|
||
(0 in this ? this.pluck('textContent').join("") : null)
|
||
},
|
||
attr: function(name, value){
|
||
var result
|
||
return (typeof name == 'string' && !(1 in arguments)) ?
|
||
(0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) :
|
||
this.each(function(idx){
|
||
if (this.nodeType !== 1) return
|
||
if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
|
||
else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
|
||
})
|
||
},
|
||
removeAttr: function(name){
|
||
return this.each(function(){ this.nodeType === 1 && name.split(' ').forEach(function(attribute){
|
||
setAttribute(this, attribute)
|
||
}, this)})
|
||
},
|
||
prop: function(name, value){
|
||
name = propMap[name] || name
|
||
return (1 in arguments) ?
|
||
this.each(function(idx){
|
||
this[name] = funcArg(this, value, idx, this[name])
|
||
}) :
|
||
(this[0] && this[0][name])
|
||
},
|
||
removeProp: function(name){
|
||
name = propMap[name] || name
|
||
return this.each(function(){ delete this[name] })
|
||
},
|
||
data: function(name, value){
|
||
var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase()
|
||
|
||
var data = (1 in arguments) ?
|
||
this.attr(attrName, value) :
|
||
this.attr(attrName)
|
||
|
||
return data !== null ? deserializeValue(data) : undefined
|
||
},
|
||
val: function(value){
|
||
if (0 in arguments) {
|
||
if (value == null) value = ""
|
||
return this.each(function(idx){
|
||
this.value = funcArg(this, value, idx, this.value)
|
||
})
|
||
} else {
|
||
return this[0] && (this[0].multiple ?
|
||
$(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') :
|
||
this[0].value)
|
||
}
|
||
},
|
||
offset: function(coordinates){
|
||
if (coordinates) return this.each(function(index){
|
||
var $this = $(this),
|
||
coords = funcArg(this, coordinates, index, $this.offset()),
|
||
parentOffset = $this.offsetParent().offset(),
|
||
props = {
|
||
top: coords.top - parentOffset.top,
|
||
left: coords.left - parentOffset.left
|
||
}
|
||
|
||
if ($this.css('position') == 'static') props['position'] = 'relative'
|
||
$this.css(props)
|
||
})
|
||
if (!this.length) return null
|
||
if (document.documentElement !== this[0] && !$.contains(document.documentElement, this[0]))
|
||
return {top: 0, left: 0}
|
||
var obj = this[0].getBoundingClientRect()
|
||
return {
|
||
left: obj.left + window.pageXOffset,
|
||
top: obj.top + window.pageYOffset,
|
||
width: Math.round(obj.width),
|
||
height: Math.round(obj.height)
|
||
}
|
||
},
|
||
css: function(property, value){
|
||
if (arguments.length < 2) {
|
||
var element = this[0]
|
||
if (typeof property == 'string') {
|
||
if (!element) return
|
||
return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property)
|
||
} else if (isArray(property)) {
|
||
if (!element) return
|
||
var props = {}
|
||
var computedStyle = getComputedStyle(element, '')
|
||
$.each(property, function(_, prop){
|
||
props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))
|
||
})
|
||
return props
|
||
}
|
||
}
|
||
|
||
var css = ''
|
||
if (type(property) == 'string') {
|
||
if (!value && value !== 0)
|
||
this.each(function(){ this.style.removeProperty(dasherize(property)) })
|
||
else
|
||
css = dasherize(property) + ":" + maybeAddPx(property, value)
|
||
} else {
|
||
for (key in property)
|
||
if (!property[key] && property[key] !== 0)
|
||
this.each(function(){ this.style.removeProperty(dasherize(key)) })
|
||
else
|
||
css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'
|
||
}
|
||
|
||
return this.each(function(){ this.style.cssText += ';' + css })
|
||
},
|
||
index: function(element){
|
||
return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])
|
||
},
|
||
hasClass: function(name){
|
||
if (!name) return false
|
||
return emptyArray.some.call(this, function(el){
|
||
return this.test(className(el))
|
||
}, classRE(name))
|
||
},
|
||
addClass: function(name){
|
||
if (!name) return this
|
||
return this.each(function(idx){
|
||
if (!('className' in this)) return
|
||
classList = []
|
||
var cls = className(this), newName = funcArg(this, name, idx, cls)
|
||
newName.split(/\s+/g).forEach(function(klass){
|
||
if (!$(this).hasClass(klass)) classList.push(klass)
|
||
}, this)
|
||
classList.length && className(this, cls + (cls ? " " : "") + classList.join(" "))
|
||
})
|
||
},
|
||
removeClass: function(name){
|
||
return this.each(function(idx){
|
||
if (!('className' in this)) return
|
||
if (name === undefined) return className(this, '')
|
||
classList = className(this)
|
||
funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){
|
||
classList = classList.replace(classRE(klass), " ")
|
||
})
|
||
className(this, classList.trim())
|
||
})
|
||
},
|
||
toggleClass: function(name, when){
|
||
if (!name) return this
|
||
return this.each(function(idx){
|
||
var $this = $(this), names = funcArg(this, name, idx, className(this))
|
||
names.split(/\s+/g).forEach(function(klass){
|
||
(when === undefined ? !$this.hasClass(klass) : when) ?
|
||
$this.addClass(klass) : $this.removeClass(klass)
|
||
})
|
||
})
|
||
},
|
||
scrollTop: function(value){
|
||
if (!this.length) return
|
||
var hasScrollTop = 'scrollTop' in this[0]
|
||
if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset
|
||
return this.each(hasScrollTop ?
|
||
function(){ this.scrollTop = value } :
|
||
function(){ this.scrollTo(this.scrollX, value) })
|
||
},
|
||
scrollLeft: function(value){
|
||
if (!this.length) return
|
||
var hasScrollLeft = 'scrollLeft' in this[0]
|
||
if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset
|
||
return this.each(hasScrollLeft ?
|
||
function(){ this.scrollLeft = value } :
|
||
function(){ this.scrollTo(value, this.scrollY) })
|
||
},
|
||
position: function() {
|
||
if (!this.length) return
|
||
|
||
var elem = this[0],
|
||
// Get *real* offsetParent
|
||
offsetParent = this.offsetParent(),
|
||
// Get correct offsets
|
||
offset = this.offset(),
|
||
parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset()
|
||
|
||
// Subtract element margins
|
||
// note: when an element has margin: auto the offsetLeft and marginLeft
|
||
// are the same in Safari causing offset.left to incorrectly be 0
|
||
offset.top -= parseFloat( $(elem).css('margin-top') ) || 0
|
||
offset.left -= parseFloat( $(elem).css('margin-left') ) || 0
|
||
|
||
// Add offsetParent borders
|
||
parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0
|
||
parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0
|
||
|
||
// Subtract the two offsets
|
||
return {
|
||
top: offset.top - parentOffset.top,
|
||
left: offset.left - parentOffset.left
|
||
}
|
||
},
|
||
offsetParent: function() {
|
||
return this.map(function(){
|
||
var parent = this.offsetParent || document.body
|
||
while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static")
|
||
parent = parent.offsetParent
|
||
return parent
|
||
})
|
||
}
|
||
}
|
||
|
||
// for now
|
||
$.fn.detach = $.fn.remove
|
||
|
||
// Generate the `width` and `height` functions
|
||
;['width', 'height'].forEach(function(dimension){
|
||
var dimensionProperty =
|
||
dimension.replace(/./, function(m){ return m[0].toUpperCase() })
|
||
|
||
$.fn[dimension] = function(value){
|
||
var offset, el = this[0]
|
||
if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] :
|
||
isDocument(el) ? el.documentElement['scroll' + dimensionProperty] :
|
||
(offset = this.offset()) && offset[dimension]
|
||
else return this.each(function(idx){
|
||
el = $(this)
|
||
el.css(dimension, funcArg(this, value, idx, el[dimension]()))
|
||
})
|
||
}
|
||
})
|
||
|
||
function traverseNode(node, fun) {
|
||
fun(node)
|
||
for (var i = 0, len = node.childNodes.length; i < len; i++)
|
||
traverseNode(node.childNodes[i], fun)
|
||
}
|
||
|
||
// Generate the `after`, `prepend`, `before`, `append`,
|
||
// `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.
|
||
adjacencyOperators.forEach(function(operator, operatorIndex) {
|
||
var inside = operatorIndex % 2 //=> prepend, append
|
||
|
||
$.fn[operator] = function(){
|
||
// arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
|
||
var argType, nodes = $.map(arguments, function(arg) {
|
||
var arr = []
|
||
argType = type(arg)
|
||
if (argType == "array") {
|
||
arg.forEach(function(el) {
|
||
if (el.nodeType !== undefined) return arr.push(el)
|
||
else if ($.zepto.isZ(el)) return arr = arr.concat(el.get())
|
||
arr = arr.concat(zepto.fragment(el))
|
||
})
|
||
return arr
|
||
}
|
||
return argType == "object" || arg == null ?
|
||
arg : zepto.fragment(arg)
|
||
}),
|
||
parent, copyByClone = this.length > 1
|
||
if (nodes.length < 1) return this
|
||
|
||
return this.each(function(_, target){
|
||
parent = inside ? target : target.parentNode
|
||
|
||
// convert all methods to a "before" operation
|
||
target = operatorIndex == 0 ? target.nextSibling :
|
||
operatorIndex == 1 ? target.firstChild :
|
||
operatorIndex == 2 ? target :
|
||
null
|
||
|
||
var parentInDocument = $.contains(document.documentElement, parent)
|
||
|
||
nodes.forEach(function(node){
|
||
if (copyByClone) node = node.cloneNode(true)
|
||
else if (!parent) return $(node).remove()
|
||
|
||
parent.insertBefore(node, target)
|
||
if (parentInDocument) traverseNode(node, function(el){
|
||
if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' &&
|
||
(!el.type || el.type === 'text/javascript') && !el.src){
|
||
var target = el.ownerDocument ? el.ownerDocument.defaultView : window
|
||
target['eval'].call(target, el.innerHTML)
|
||
}
|
||
})
|
||
})
|
||
})
|
||
}
|
||
|
||
// after => insertAfter
|
||
// prepend => prependTo
|
||
// before => insertBefore
|
||
// append => appendTo
|
||
$.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){
|
||
$(html)[operator](this)
|
||
return this
|
||
}
|
||
})
|
||
|
||
zepto.Z.prototype = Z.prototype = $.fn
|
||
|
||
// Export internal API functions in the `$.zepto` namespace
|
||
zepto.uniq = uniq
|
||
zepto.deserializeValue = deserializeValue
|
||
$.zepto = zepto
|
||
|
||
return $
|
||
})()
|
||
|
||
;(function($){
|
||
var _zid = 1, undefined,
|
||
slice = Array.prototype.slice,
|
||
isFunction = $.isFunction,
|
||
isString = function(obj){ return typeof obj == 'string' },
|
||
handlers = {},
|
||
specialEvents={},
|
||
focusinSupported = 'onfocusin' in window,
|
||
focus = { focus: 'focusin', blur: 'focusout' },
|
||
hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }
|
||
|
||
specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'
|
||
|
||
function zid(element) {
|
||
return element._zid || (element._zid = _zid++)
|
||
}
|
||
function findHandlers(element, event, fn, selector) {
|
||
event = parse(event)
|
||
if (event.ns) var matcher = matcherFor(event.ns)
|
||
return (handlers[zid(element)] || []).filter(function(handler) {
|
||
return handler
|
||
&& (!event.e || handler.e == event.e)
|
||
&& (!event.ns || matcher.test(handler.ns))
|
||
&& (!fn || zid(handler.fn) === zid(fn))
|
||
&& (!selector || handler.sel == selector)
|
||
})
|
||
}
|
||
function parse(event) {
|
||
var parts = ('' + event).split('.')
|
||
return {e: parts[0], ns: parts.slice(1).sort().join(' ')}
|
||
}
|
||
function matcherFor(ns) {
|
||
return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)')
|
||
}
|
||
|
||
function eventCapture(handler, captureSetting) {
|
||
return handler.del &&
|
||
(!focusinSupported && (handler.e in focus)) ||
|
||
!!captureSetting
|
||
}
|
||
|
||
function realEvent(type) {
|
||
return hover[type] || (focusinSupported && focus[type]) || type
|
||
}
|
||
|
||
function add(element, events, fn, data, selector, delegator, capture){
|
||
var id = zid(element), set = (handlers[id] || (handlers[id] = []))
|
||
events.split(/\s/).forEach(function(event){
|
||
if (event == 'ready') return $(document).ready(fn)
|
||
var handler = parse(event)
|
||
handler.fn = fn
|
||
handler.sel = selector
|
||
// emulate mouseenter, mouseleave
|
||
if (handler.e in hover) fn = function(e){
|
||
var related = e.relatedTarget
|
||
if (!related || (related !== this && !$.contains(this, related)))
|
||
return handler.fn.apply(this, arguments)
|
||
}
|
||
handler.del = delegator
|
||
var callback = delegator || fn
|
||
handler.proxy = function(e){
|
||
e = compatible(e)
|
||
if (e.isImmediatePropagationStopped()) return
|
||
try {
|
||
var dataPropDescriptor = Object.getOwnPropertyDescriptor(e, 'data')
|
||
if (!dataPropDescriptor || dataPropDescriptor.writable)
|
||
e.data = data
|
||
} catch (e) {} // when using strict mode dataPropDescriptor will be undefined when e is InputEvent (even though data property exists). So we surround with try/catch
|
||
var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args))
|
||
if (result === false) e.preventDefault(), e.stopPropagation()
|
||
return result
|
||
}
|
||
handler.i = set.length
|
||
set.push(handler)
|
||
if ('addEventListener' in element)
|
||
element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
|
||
})
|
||
}
|
||
function remove(element, events, fn, selector, capture){
|
||
var id = zid(element)
|
||
;(events || '').split(/\s/).forEach(function(event){
|
||
findHandlers(element, event, fn, selector).forEach(function(handler){
|
||
delete handlers[id][handler.i]
|
||
if ('removeEventListener' in element)
|
||
element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
|
||
})
|
||
})
|
||
}
|
||
|
||
$.event = { add: add, remove: remove }
|
||
|
||
$.proxy = function(fn, context) {
|
||
var args = (2 in arguments) && slice.call(arguments, 2)
|
||
if (isFunction(fn)) {
|
||
var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) }
|
||
proxyFn._zid = zid(fn)
|
||
return proxyFn
|
||
} else if (isString(context)) {
|
||
if (args) {
|
||
args.unshift(fn[context], fn)
|
||
return $.proxy.apply(null, args)
|
||
} else {
|
||
return $.proxy(fn[context], fn)
|
||
}
|
||
} else {
|
||
throw new TypeError("expected function")
|
||
}
|
||
}
|
||
|
||
$.fn.bind = function(event, data, callback){
|
||
return this.on(event, data, callback)
|
||
}
|
||
$.fn.unbind = function(event, callback){
|
||
return this.off(event, callback)
|
||
}
|
||
$.fn.one = function(event, selector, data, callback){
|
||
return this.on(event, selector, data, callback, 1)
|
||
}
|
||
|
||
var returnTrue = function(){return true},
|
||
returnFalse = function(){return false},
|
||
ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/,
|
||
eventMethods = {
|
||
preventDefault: 'isDefaultPrevented',
|
||
stopImmediatePropagation: 'isImmediatePropagationStopped',
|
||
stopPropagation: 'isPropagationStopped'
|
||
}
|
||
|
||
function compatible(event, source) {
|
||
if (source || !event.isDefaultPrevented) {
|
||
source || (source = event)
|
||
|
||
$.each(eventMethods, function(name, predicate) {
|
||
var sourceMethod = source[name]
|
||
event[name] = function(){
|
||
this[predicate] = returnTrue
|
||
return sourceMethod && sourceMethod.apply(source, arguments)
|
||
}
|
||
event[predicate] = returnFalse
|
||
})
|
||
|
||
event.timeStamp || (event.timeStamp = Date.now())
|
||
|
||
if (source.defaultPrevented !== undefined ? source.defaultPrevented :
|
||
'returnValue' in source ? source.returnValue === false :
|
||
source.getPreventDefault && source.getPreventDefault())
|
||
event.isDefaultPrevented = returnTrue
|
||
}
|
||
return event
|
||
}
|
||
|
||
function createProxy(event) {
|
||
var key, proxy = { originalEvent: event }
|
||
for (key in event)
|
||
if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]
|
||
|
||
return compatible(proxy, event)
|
||
}
|
||
|
||
$.fn.delegate = function(selector, event, callback){
|
||
return this.on(event, selector, callback)
|
||
}
|
||
$.fn.undelegate = function(selector, event, callback){
|
||
return this.off(event, selector, callback)
|
||
}
|
||
|
||
$.fn.live = function(event, callback){
|
||
$(document.body).delegate(this.selector, event, callback)
|
||
return this
|
||
}
|
||
$.fn.die = function(event, callback){
|
||
$(document.body).undelegate(this.selector, event, callback)
|
||
return this
|
||
}
|
||
|
||
$.fn.on = function(event, selector, data, callback, one){
|
||
var autoRemove, delegator, $this = this
|
||
if (event && !isString(event)) {
|
||
$.each(event, function(type, fn){
|
||
$this.on(type, selector, data, fn, one)
|
||
})
|
||
return $this
|
||
}
|
||
|
||
if (!isString(selector) && !isFunction(callback) && callback !== false)
|
||
callback = data, data = selector, selector = undefined
|
||
if (callback === undefined || data === false)
|
||
callback = data, data = undefined
|
||
|
||
if (callback === false) callback = returnFalse
|
||
|
||
return $this.each(function(_, element){
|
||
if (one) autoRemove = function(e){
|
||
remove(element, e.type, callback)
|
||
return callback.apply(this, arguments)
|
||
}
|
||
|
||
if (selector) delegator = function(e){
|
||
var evt, match = $(e.target).closest(selector, element).get(0)
|
||
if (match && match !== element) {
|
||
evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element})
|
||
return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1)))
|
||
}
|
||
}
|
||
|
||
add(element, event, callback, data, selector, delegator || autoRemove)
|
||
})
|
||
}
|
||
$.fn.off = function(event, selector, callback){
|
||
var $this = this
|
||
if (event && !isString(event)) {
|
||
$.each(event, function(type, fn){
|
||
$this.off(type, selector, fn)
|
||
})
|
||
return $this
|
||
}
|
||
|
||
if (!isString(selector) && !isFunction(callback) && callback !== false)
|
||
callback = selector, selector = undefined
|
||
|
||
if (callback === false) callback = returnFalse
|
||
|
||
return $this.each(function(){
|
||
remove(this, event, callback, selector)
|
||
})
|
||
}
|
||
|
||
$.fn.trigger = function(event, args){
|
||
event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)
|
||
event._args = args
|
||
return this.each(function(){
|
||
// handle focus(), blur() by calling them directly
|
||
if (event.type in focus && typeof this[event.type] == "function") this[event.type]()
|
||
// items in the collection might not be DOM elements
|
||
else if ('dispatchEvent' in this) this.dispatchEvent(event)
|
||
else $(this).triggerHandler(event, args)
|
||
})
|
||
}
|
||
|
||
// triggers event handlers on current element just as if an event occurred,
|
||
// doesn't trigger an actual event, doesn't bubble
|
||
$.fn.triggerHandler = function(event, args){
|
||
var e, result
|
||
this.each(function(i, element){
|
||
e = createProxy(isString(event) ? $.Event(event) : event)
|
||
e._args = args
|
||
e.target = element
|
||
$.each(findHandlers(element, event.type || event), function(i, handler){
|
||
result = handler.proxy(e)
|
||
if (e.isImmediatePropagationStopped()) return false
|
||
})
|
||
})
|
||
return result
|
||
}
|
||
|
||
// shortcut methods for `.bind(event, fn)` for each event type
|
||
;('focusin focusout focus blur load resize scroll unload click dblclick '+
|
||
'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+
|
||
'change select keydown keypress keyup error').split(' ').forEach(function(event) {
|
||
$.fn[event] = function(callback) {
|
||
return (0 in arguments) ?
|
||
this.bind(event, callback) :
|
||
this.trigger(event)
|
||
}
|
||
})
|
||
|
||
$.Event = function(type, props) {
|
||
if (!isString(type)) props = type, type = props.type
|
||
var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true
|
||
if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
|
||
event.initEvent(type, bubbles, true)
|
||
return compatible(event)
|
||
}
|
||
|
||
})(Zepto)
|
||
|
||
;(function($){
|
||
var cache = [], timeout
|
||
|
||
$.fn.remove = function(){
|
||
return this.each(function(){
|
||
if(this.parentNode){
|
||
if(this.tagName === 'IMG'){
|
||
cache.push(this)
|
||
this.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
|
||
if (timeout) clearTimeout(timeout)
|
||
timeout = setTimeout(function(){ cache = [] }, 60000)
|
||
}
|
||
this.parentNode.removeChild(this)
|
||
}
|
||
})
|
||
}
|
||
})(Zepto)
|
||
|
||
;(function($){
|
||
var data = {}, dataAttr = $.fn.data, camelize = $.camelCase,
|
||
exp = $.expando = 'Zepto' + (+new Date()), emptyArray = []
|
||
|
||
// Get value from node:
|
||
// 1. first try key as given,
|
||
// 2. then try camelized key,
|
||
// 3. fall back to reading "data-*" attribute.
|
||
function getData(node, name) {
|
||
var id = node[exp], store = id && data[id]
|
||
if (name === undefined) return store || setData(node)
|
||
else {
|
||
if (store) {
|
||
if (name in store) return store[name]
|
||
var camelName = camelize(name)
|
||
if (camelName in store) return store[camelName]
|
||
}
|
||
return dataAttr.call($(node), name)
|
||
}
|
||
}
|
||
|
||
// Store value under camelized key on node
|
||
function setData(node, name, value) {
|
||
var id = node[exp] || (node[exp] = ++$.uuid),
|
||
store = data[id] || (data[id] = attributeData(node))
|
||
if (name !== undefined) store[camelize(name)] = value
|
||
return store
|
||
}
|
||
|
||
// Read all "data-*" attributes from a node
|
||
function attributeData(node) {
|
||
var store = {}
|
||
$.each(node.attributes || emptyArray, function(i, attr){
|
||
if (attr.name.indexOf('data-') == 0)
|
||
store[camelize(attr.name.replace('data-', ''))] =
|
||
$.zepto.deserializeValue(attr.value)
|
||
})
|
||
return store
|
||
}
|
||
|
||
$.fn.data = function(name, value) {
|
||
return value === undefined ?
|
||
// set multiple values via object
|
||
$.isPlainObject(name) ?
|
||
this.each(function(i, node){
|
||
$.each(name, function(key, value){ setData(node, key, value) })
|
||
}) :
|
||
// get value from first element
|
||
(0 in this ? getData(this[0], name) : undefined) :
|
||
// set value on all elements
|
||
this.each(function(){ setData(this, name, value) })
|
||
}
|
||
|
||
$.data = function(elem, name, value) {
|
||
return $(elem).data(name, value)
|
||
}
|
||
|
||
$.hasData = function(elem) {
|
||
var id = elem[exp], store = id && data[id]
|
||
return store ? !$.isEmptyObject(store) : false
|
||
}
|
||
|
||
$.fn.removeData = function(names) {
|
||
if (typeof names == 'string') names = names.split(/\s+/)
|
||
return this.each(function(){
|
||
var id = this[exp], store = id && data[id]
|
||
if (store) $.each(names || store, function(key){
|
||
delete store[names ? camelize(this) : key]
|
||
})
|
||
})
|
||
}
|
||
|
||
// Generate extended `remove` and `empty` functions
|
||
;['remove', 'empty'].forEach(function(methodName){
|
||
var origFn = $.fn[methodName]
|
||
$.fn[methodName] = function() {
|
||
var elements = this.find('*')
|
||
if (methodName === 'remove') elements = elements.add(this)
|
||
elements.removeData()
|
||
return origFn.call(this)
|
||
}
|
||
})
|
||
})(Zepto)
|
||
return Zepto
|
||
}))
|
||
|
||
|
||
/***/ }),
|
||
/* 16 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var namespace = 'autocomplete:';
|
||
|
||
var _ = __webpack_require__(0);
|
||
var DOM = __webpack_require__(1);
|
||
|
||
// constructor
|
||
// -----------
|
||
|
||
function EventBus(o) {
|
||
if (!o || !o.el) {
|
||
_.error('EventBus initialized without el');
|
||
}
|
||
|
||
this.$el = DOM.element(o.el);
|
||
}
|
||
|
||
// instance methods
|
||
// ----------------
|
||
|
||
_.mixin(EventBus.prototype, {
|
||
|
||
// ### public
|
||
|
||
trigger: function(type, suggestion, dataset, context) {
|
||
var event = _.Event(namespace + type);
|
||
this.$el.trigger(event, [suggestion, dataset, context]);
|
||
return event;
|
||
}
|
||
});
|
||
|
||
module.exports = EventBus;
|
||
|
||
|
||
/***/ }),
|
||
/* 17 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
module.exports = {
|
||
wrapper: '<span class="%ROOT%"></span>',
|
||
dropdown: '<span class="%PREFIX%%DROPDOWN_MENU%"></span>',
|
||
dataset: '<div class="%PREFIX%%DATASET%-%CLASS%"></div>',
|
||
suggestions: '<span class="%PREFIX%%SUGGESTIONS%"></span>',
|
||
suggestion: '<div class="%PREFIX%%SUGGESTION%"></div>'
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 18 */
|
||
/***/ (function(module, exports) {
|
||
|
||
module.exports = "0.36.0";
|
||
|
||
|
||
/***/ }),
|
||
/* 19 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
module.exports = function parseAlgoliaClientVersion(agent) {
|
||
var parsed = agent.match(/Algolia for vanilla JavaScript (\d+\.)(\d+\.)(\d+)/);
|
||
if (parsed) return [parsed[1], parsed[2], parsed[3]];
|
||
return undefined;
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 20 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
Object.defineProperty(exports, "__esModule", {
|
||
value: true
|
||
});
|
||
|
||
var _zepto = __webpack_require__(15);
|
||
|
||
var _zepto2 = _interopRequireDefault(_zepto);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
exports.default = _zepto2.default;
|
||
|
||
/***/ }),
|
||
/* 21 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
Object.defineProperty(exports, "__esModule", {
|
||
value: true
|
||
});
|
||
exports.default = '2.6.3';
|
||
|
||
/***/ }),
|
||
/* 22 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var _main = __webpack_require__(23);
|
||
|
||
var _main2 = _interopRequireDefault(_main);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
module.exports = _main2.default; /* eslint-disable import/no-commonjs */
|
||
|
||
/***/ }),
|
||
/* 23 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
Object.defineProperty(exports, "__esModule", {
|
||
value: true
|
||
});
|
||
|
||
var _toFactory = __webpack_require__(24);
|
||
|
||
var _toFactory2 = _interopRequireDefault(_toFactory);
|
||
|
||
var _DocSearch = __webpack_require__(25);
|
||
|
||
var _DocSearch2 = _interopRequireDefault(_DocSearch);
|
||
|
||
var _version = __webpack_require__(21);
|
||
|
||
var _version2 = _interopRequireDefault(_version);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var docsearch = (0, _toFactory2.default)(_DocSearch2.default);
|
||
docsearch.version = _version2.default;
|
||
|
||
exports.default = docsearch;
|
||
|
||
/***/ }),
|
||
/* 24 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var _bind = Function.prototype.bind;
|
||
function toFactory(Class) {
|
||
var Factory = function Factory() {
|
||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
||
args[_key] = arguments[_key];
|
||
}
|
||
|
||
return new (_bind.apply(Class, [null].concat(args)))();
|
||
};
|
||
Factory.__proto__ = Class;
|
||
Factory.prototype = Class.prototype;
|
||
return Factory;
|
||
}
|
||
|
||
module.exports = toFactory;
|
||
|
||
|
||
|
||
/***/ }),
|
||
/* 25 */
|
||
/***/ (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; };
|
||
|
||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||
|
||
var _hogan = __webpack_require__(26);
|
||
|
||
var _hogan2 = _interopRequireDefault(_hogan);
|
||
|
||
var _lite = __webpack_require__(29);
|
||
|
||
var _lite2 = _interopRequireDefault(_lite);
|
||
|
||
var _autocomplete = __webpack_require__(49);
|
||
|
||
var _autocomplete2 = _interopRequireDefault(_autocomplete);
|
||
|
||
var _templates = __webpack_require__(64);
|
||
|
||
var _templates2 = _interopRequireDefault(_templates);
|
||
|
||
var _utils = __webpack_require__(65);
|
||
|
||
var _utils2 = _interopRequireDefault(_utils);
|
||
|
||
var _version = __webpack_require__(21);
|
||
|
||
var _version2 = _interopRequireDefault(_version);
|
||
|
||
var _zepto = __webpack_require__(20);
|
||
|
||
var _zepto2 = _interopRequireDefault(_zepto);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||
|
||
/**
|
||
* Adds an autocomplete dropdown to an input field
|
||
* @function DocSearch
|
||
* @param {string} options.apiKey Read-only API key
|
||
* @param {string} options.indexName Name of the index to target
|
||
* @param {string} options.inputSelector CSS selector that targets the input
|
||
* @param {string} [options.appId] Lets you override the applicationId used.
|
||
* If using the default Algolia Crawler, you should not have to change this
|
||
* value.
|
||
* @param {Object} [options.algoliaOptions] Options to pass the underlying Algolia client
|
||
* @param {Object} [options.autocompleteOptions] Options to pass to the underlying autocomplete instance
|
||
* @return {Object}
|
||
*/
|
||
var usage = 'Usage:\n documentationSearch({\n apiKey,\n indexName,\n inputSelector,\n [ appId ],\n [ algoliaOptions.{hitsPerPage} ]\n [ autocompleteOptions.{hint,debug} ]\n})';
|
||
|
||
var DocSearch = function () {
|
||
function DocSearch(_ref) {
|
||
var apiKey = _ref.apiKey,
|
||
indexName = _ref.indexName,
|
||
inputSelector = _ref.inputSelector,
|
||
_ref$appId = _ref.appId,
|
||
appId = _ref$appId === undefined ? 'BH4D9OD16A' : _ref$appId,
|
||
_ref$debug = _ref.debug,
|
||
debug = _ref$debug === undefined ? false : _ref$debug,
|
||
_ref$algoliaOptions = _ref.algoliaOptions,
|
||
algoliaOptions = _ref$algoliaOptions === undefined ? {} : _ref$algoliaOptions,
|
||
_ref$queryDataCallbac = _ref.queryDataCallback,
|
||
queryDataCallback = _ref$queryDataCallbac === undefined ? null : _ref$queryDataCallbac,
|
||
_ref$autocompleteOpti = _ref.autocompleteOptions,
|
||
autocompleteOptions = _ref$autocompleteOpti === undefined ? {
|
||
debug: false,
|
||
hint: false,
|
||
autoselect: true
|
||
} : _ref$autocompleteOpti,
|
||
_ref$transformData = _ref.transformData,
|
||
transformData = _ref$transformData === undefined ? false : _ref$transformData,
|
||
_ref$queryHook = _ref.queryHook,
|
||
queryHook = _ref$queryHook === undefined ? false : _ref$queryHook,
|
||
_ref$handleSelected = _ref.handleSelected,
|
||
handleSelected = _ref$handleSelected === undefined ? false : _ref$handleSelected,
|
||
_ref$enhancedSearchIn = _ref.enhancedSearchInput,
|
||
enhancedSearchInput = _ref$enhancedSearchIn === undefined ? false : _ref$enhancedSearchIn,
|
||
_ref$layout = _ref.layout,
|
||
layout = _ref$layout === undefined ? 'collumns' : _ref$layout;
|
||
|
||
_classCallCheck(this, DocSearch);
|
||
|
||
DocSearch.checkArguments({
|
||
apiKey: apiKey,
|
||
indexName: indexName,
|
||
inputSelector: inputSelector,
|
||
debug: debug,
|
||
algoliaOptions: algoliaOptions,
|
||
queryDataCallback: queryDataCallback,
|
||
autocompleteOptions: autocompleteOptions,
|
||
transformData: transformData,
|
||
queryHook: queryHook,
|
||
handleSelected: handleSelected,
|
||
enhancedSearchInput: enhancedSearchInput,
|
||
layout: layout
|
||
});
|
||
|
||
this.apiKey = apiKey;
|
||
this.appId = appId;
|
||
this.indexName = indexName;
|
||
this.input = DocSearch.getInputFromSelector(inputSelector);
|
||
this.algoliaOptions = _extends({ hitsPerPage: 5 }, algoliaOptions);
|
||
this.queryDataCallback = queryDataCallback || null;
|
||
var autocompleteOptionsDebug = autocompleteOptions && autocompleteOptions.debug ? autocompleteOptions.debug : false;
|
||
// eslint-disable-next-line no-param-reassign
|
||
autocompleteOptions.debug = debug || autocompleteOptionsDebug;
|
||
this.autocompleteOptions = autocompleteOptions;
|
||
this.autocompleteOptions.cssClasses = this.autocompleteOptions.cssClasses || {};
|
||
this.autocompleteOptions.cssClasses.prefix = this.autocompleteOptions.cssClasses.prefix || 'ds';
|
||
var inputAriaLabel = this.input && typeof this.input.attr === 'function' && this.input.attr('aria-label');
|
||
this.autocompleteOptions.ariaLabel = this.autocompleteOptions.ariaLabel || inputAriaLabel || "search input";
|
||
|
||
this.isSimpleLayout = layout === 'simple';
|
||
|
||
this.client = (0, _lite2.default)(this.appId, this.apiKey);
|
||
this.client.addAlgoliaAgent('docsearch.js ' + _version2.default);
|
||
|
||
if (enhancedSearchInput) {
|
||
this.input = DocSearch.injectSearchBox(this.input);
|
||
}
|
||
|
||
this.autocomplete = (0, _autocomplete2.default)(this.input, autocompleteOptions, [{
|
||
source: this.getAutocompleteSource(transformData, queryHook),
|
||
templates: {
|
||
suggestion: DocSearch.getSuggestionTemplate(this.isSimpleLayout),
|
||
footer: _templates2.default.footer,
|
||
empty: DocSearch.getEmptyTemplate()
|
||
}
|
||
}]);
|
||
|
||
var customHandleSelected = handleSelected;
|
||
this.handleSelected = customHandleSelected || this.handleSelected;
|
||
|
||
// We prevent default link clicking if a custom handleSelected is defined
|
||
if (customHandleSelected) {
|
||
(0, _zepto2.default)('.algolia-autocomplete').on('click', '.ds-suggestions a', function (event) {
|
||
event.preventDefault();
|
||
});
|
||
}
|
||
|
||
this.autocomplete.on('autocomplete:selected', this.handleSelected.bind(null, this.autocomplete.autocomplete));
|
||
|
||
this.autocomplete.on('autocomplete:shown', this.handleShown.bind(null, this.input));
|
||
|
||
if (enhancedSearchInput) {
|
||
DocSearch.bindSearchBoxEvent();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Checks that the passed arguments are valid. Will throw errors otherwise
|
||
* @function checkArguments
|
||
* @param {object} args Arguments as an option object
|
||
* @returns {void}
|
||
*/
|
||
|
||
|
||
_createClass(DocSearch, [{
|
||
key: 'getAutocompleteSource',
|
||
|
||
|
||
/**
|
||
* Returns the `source` method to be passed to autocomplete.js. It will query
|
||
* the Algolia index and call the callbacks with the formatted hits.
|
||
* @function getAutocompleteSource
|
||
* @param {function} transformData An optional function to transform the hits
|
||
* @param {function} queryHook An optional function to transform the query
|
||
* @returns {function} Method to be passed as the `source` option of
|
||
* autocomplete
|
||
*/
|
||
value: function getAutocompleteSource(transformData, queryHook) {
|
||
var _this = this;
|
||
|
||
return function (query, callback) {
|
||
if (queryHook) {
|
||
// eslint-disable-next-line no-param-reassign
|
||
query = queryHook(query) || query;
|
||
}
|
||
|
||
_this.client.search([{
|
||
indexName: _this.indexName,
|
||
query: query,
|
||
params: _this.algoliaOptions
|
||
}]).then(function (data) {
|
||
if (_this.queryDataCallback && typeof _this.queryDataCallback == "function") {
|
||
_this.queryDataCallback(data);
|
||
}
|
||
var hits = data.results[0].hits;
|
||
if (transformData) {
|
||
hits = transformData(hits) || hits;
|
||
}
|
||
callback(DocSearch.formatHits(hits));
|
||
});
|
||
};
|
||
}
|
||
|
||
// Given a list of hits returned by the API, will reformat them to be used in
|
||
// a Hogan template
|
||
|
||
}, {
|
||
key: 'handleSelected',
|
||
value: function handleSelected(input, event, suggestion, datasetNumber) {
|
||
var context = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
|
||
|
||
// Do nothing if click on the suggestion, as it's already a <a href>, the
|
||
// browser will take care of it. This allow Ctrl-Clicking on results and not
|
||
// having the main window being redirected as well
|
||
if (context.selectionMethod === 'click') {
|
||
return;
|
||
}
|
||
|
||
input.setVal('');
|
||
window.location.assign(suggestion.url);
|
||
}
|
||
}, {
|
||
key: 'handleShown',
|
||
value: function handleShown(input) {
|
||
var middleOfInput = input.offset().left + input.width() / 2;
|
||
var middleOfWindow = (0, _zepto2.default)(document).width() / 2;
|
||
|
||
if (isNaN(middleOfWindow)) {
|
||
middleOfWindow = 900;
|
||
}
|
||
|
||
var alignClass = middleOfInput - middleOfWindow >= 0 ? 'algolia-autocomplete-right' : 'algolia-autocomplete-left';
|
||
var otherAlignClass = middleOfInput - middleOfWindow < 0 ? 'algolia-autocomplete-right' : 'algolia-autocomplete-left';
|
||
var autocompleteWrapper = (0, _zepto2.default)('.algolia-autocomplete');
|
||
if (!autocompleteWrapper.hasClass(alignClass)) {
|
||
autocompleteWrapper.addClass(alignClass);
|
||
}
|
||
|
||
if (autocompleteWrapper.hasClass(otherAlignClass)) {
|
||
autocompleteWrapper.removeClass(otherAlignClass);
|
||
}
|
||
}
|
||
}], [{
|
||
key: 'checkArguments',
|
||
value: function checkArguments(args) {
|
||
if (!args.apiKey || !args.indexName) {
|
||
throw new Error(usage);
|
||
}
|
||
|
||
if (typeof args.inputSelector !== 'string') {
|
||
throw new Error('Error: inputSelector:' + args.inputSelector + ' must be a string. Each selector must match only one element and separated by \',\'');
|
||
}
|
||
|
||
if (!DocSearch.getInputFromSelector(args.inputSelector)) {
|
||
throw new Error('Error: No input element in the page matches ' + args.inputSelector);
|
||
}
|
||
}
|
||
}, {
|
||
key: 'injectSearchBox',
|
||
value: function injectSearchBox(input) {
|
||
input.before(_templates2.default.searchBox);
|
||
var newInput = input.prev().prev().find('input');
|
||
input.remove();
|
||
return newInput;
|
||
}
|
||
}, {
|
||
key: 'bindSearchBoxEvent',
|
||
value: function bindSearchBoxEvent() {
|
||
(0, _zepto2.default)('.searchbox [type="reset"]').on('click', function () {
|
||
(0, _zepto2.default)('input#docsearch').focus();
|
||
(0, _zepto2.default)(this).addClass('hide');
|
||
_autocomplete2.default.autocomplete.setVal('');
|
||
});
|
||
|
||
(0, _zepto2.default)('input#docsearch').on('keyup', function () {
|
||
var searchbox = document.querySelector('input#docsearch');
|
||
var reset = document.querySelector('.searchbox [type="reset"]');
|
||
reset.className = 'searchbox__reset';
|
||
if (searchbox.value.length === 0) {
|
||
reset.className += ' hide';
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Returns the matching input from a CSS selector, null if none matches
|
||
* @function getInputFromSelector
|
||
* @param {string} selector CSS selector that matches the search
|
||
* input of the page
|
||
* @returns {void}
|
||
*/
|
||
|
||
}, {
|
||
key: 'getInputFromSelector',
|
||
value: function getInputFromSelector(selector) {
|
||
var input = (0, _zepto2.default)(selector).filter('input');
|
||
return input.length ? (0, _zepto2.default)(input[0]) : null;
|
||
}
|
||
}, {
|
||
key: 'formatHits',
|
||
value: function formatHits(receivedHits) {
|
||
var clonedHits = _utils2.default.deepClone(receivedHits);
|
||
var hits = clonedHits.map(function (hit) {
|
||
if (hit._highlightResult) {
|
||
// eslint-disable-next-line no-param-reassign
|
||
hit._highlightResult = _utils2.default.mergeKeyWithParent(hit._highlightResult, 'hierarchy');
|
||
}
|
||
return _utils2.default.mergeKeyWithParent(hit, 'hierarchy');
|
||
});
|
||
|
||
// Group hits by category / subcategory
|
||
var groupedHits = _utils2.default.groupBy(hits, 'lvl0');
|
||
_zepto2.default.each(groupedHits, function (level, collection) {
|
||
var groupedHitsByLvl1 = _utils2.default.groupBy(collection, 'lvl1');
|
||
var flattenedHits = _utils2.default.flattenAndFlagFirst(groupedHitsByLvl1, 'isSubCategoryHeader');
|
||
groupedHits[level] = flattenedHits;
|
||
});
|
||
groupedHits = _utils2.default.flattenAndFlagFirst(groupedHits, 'isCategoryHeader');
|
||
|
||
// Translate hits into smaller objects to be send to the template
|
||
return groupedHits.map(function (hit) {
|
||
var url = DocSearch.formatURL(hit);
|
||
var category = _utils2.default.getHighlightedValue(hit, 'lvl0');
|
||
var subcategory = _utils2.default.getHighlightedValue(hit, 'lvl1') || category;
|
||
var displayTitle = _utils2.default.compact([_utils2.default.getHighlightedValue(hit, 'lvl2') || subcategory, _utils2.default.getHighlightedValue(hit, 'lvl3'), _utils2.default.getHighlightedValue(hit, 'lvl4'), _utils2.default.getHighlightedValue(hit, 'lvl5'), _utils2.default.getHighlightedValue(hit, 'lvl6')]).join('<span class="aa-suggestion-title-separator" aria-hidden="true"> › </span>');
|
||
var text = _utils2.default.getSnippetedValue(hit, 'content');
|
||
var isTextOrSubcategoryNonEmpty = subcategory && subcategory !== '' || displayTitle && displayTitle !== '';
|
||
var isLvl1EmptyOrDuplicate = !subcategory || subcategory === '' || subcategory === category;
|
||
var isLvl2 = displayTitle && displayTitle !== '' && displayTitle !== subcategory;
|
||
var isLvl1 = !isLvl2 && subcategory && subcategory !== '' && subcategory !== category;
|
||
var isLvl0 = !isLvl1 && !isLvl2;
|
||
|
||
return {
|
||
isLvl0: isLvl0,
|
||
isLvl1: isLvl1,
|
||
isLvl2: isLvl2,
|
||
isLvl1EmptyOrDuplicate: isLvl1EmptyOrDuplicate,
|
||
isCategoryHeader: hit.isCategoryHeader,
|
||
isSubCategoryHeader: hit.isSubCategoryHeader,
|
||
isTextOrSubcategoryNonEmpty: isTextOrSubcategoryNonEmpty,
|
||
category: category,
|
||
subcategory: subcategory,
|
||
title: displayTitle,
|
||
text: text,
|
||
url: url
|
||
};
|
||
});
|
||
}
|
||
}, {
|
||
key: 'formatURL',
|
||
value: function formatURL(hit) {
|
||
var url = hit.url,
|
||
anchor = hit.anchor;
|
||
|
||
if (url) {
|
||
var containsAnchor = url.indexOf('#') !== -1;
|
||
if (containsAnchor) return url;else if (anchor) return hit.url + '#' + hit.anchor;
|
||
return url;
|
||
} else if (anchor) return '#' + hit.anchor;
|
||
/* eslint-disable */
|
||
console.warn('no anchor nor url for : ', JSON.stringify(hit));
|
||
/* eslint-enable */
|
||
return null;
|
||
}
|
||
}, {
|
||
key: 'getEmptyTemplate',
|
||
value: function getEmptyTemplate() {
|
||
return function (args) {
|
||
return _hogan2.default.compile(_templates2.default.empty).render(args);
|
||
};
|
||
}
|
||
}, {
|
||
key: 'getSuggestionTemplate',
|
||
value: function getSuggestionTemplate(isSimpleLayout) {
|
||
var stringTemplate = isSimpleLayout ? _templates2.default.suggestionSimple : _templates2.default.suggestion;
|
||
var template = _hogan2.default.compile(stringTemplate);
|
||
return function (suggestion) {
|
||
return template.render(suggestion);
|
||
};
|
||
}
|
||
}]);
|
||
|
||
return DocSearch;
|
||
}();
|
||
|
||
exports.default = DocSearch;
|
||
|
||
/***/ }),
|
||
/* 26 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
/*
|
||
* Copyright 2011 Twitter, Inc.
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
// This file is for use with Node.js. See dist/ for browser files.
|
||
|
||
var Hogan = __webpack_require__(27);
|
||
Hogan.Template = __webpack_require__(28).Template;
|
||
Hogan.template = Hogan.Template;
|
||
module.exports = Hogan;
|
||
|
||
|
||
/***/ }),
|
||
/* 27 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
/*
|
||
* Copyright 2011 Twitter, Inc.
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
(function (Hogan) {
|
||
// Setup regex assignments
|
||
// remove whitespace according to Mustache spec
|
||
var rIsWhitespace = /\S/,
|
||
rQuot = /\"/g,
|
||
rNewline = /\n/g,
|
||
rCr = /\r/g,
|
||
rSlash = /\\/g,
|
||
rLineSep = /\u2028/,
|
||
rParagraphSep = /\u2029/;
|
||
|
||
Hogan.tags = {
|
||
'#': 1, '^': 2, '<': 3, '$': 4,
|
||
'/': 5, '!': 6, '>': 7, '=': 8, '_v': 9,
|
||
'{': 10, '&': 11, '_t': 12
|
||
};
|
||
|
||
Hogan.scan = function scan(text, delimiters) {
|
||
var len = text.length,
|
||
IN_TEXT = 0,
|
||
IN_TAG_TYPE = 1,
|
||
IN_TAG = 2,
|
||
state = IN_TEXT,
|
||
tagType = null,
|
||
tag = null,
|
||
buf = '',
|
||
tokens = [],
|
||
seenTag = false,
|
||
i = 0,
|
||
lineStart = 0,
|
||
otag = '{{',
|
||
ctag = '}}';
|
||
|
||
function addBuf() {
|
||
if (buf.length > 0) {
|
||
tokens.push({tag: '_t', text: new String(buf)});
|
||
buf = '';
|
||
}
|
||
}
|
||
|
||
function lineIsWhitespace() {
|
||
var isAllWhitespace = true;
|
||
for (var j = lineStart; j < tokens.length; j++) {
|
||
isAllWhitespace =
|
||
(Hogan.tags[tokens[j].tag] < Hogan.tags['_v']) ||
|
||
(tokens[j].tag == '_t' && tokens[j].text.match(rIsWhitespace) === null);
|
||
if (!isAllWhitespace) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return isAllWhitespace;
|
||
}
|
||
|
||
function filterLine(haveSeenTag, noNewLine) {
|
||
addBuf();
|
||
|
||
if (haveSeenTag && lineIsWhitespace()) {
|
||
for (var j = lineStart, next; j < tokens.length; j++) {
|
||
if (tokens[j].text) {
|
||
if ((next = tokens[j+1]) && next.tag == '>') {
|
||
// set indent to token value
|
||
next.indent = tokens[j].text.toString()
|
||
}
|
||
tokens.splice(j, 1);
|
||
}
|
||
}
|
||
} else if (!noNewLine) {
|
||
tokens.push({tag:'\n'});
|
||
}
|
||
|
||
seenTag = false;
|
||
lineStart = tokens.length;
|
||
}
|
||
|
||
function changeDelimiters(text, index) {
|
||
var close = '=' + ctag,
|
||
closeIndex = text.indexOf(close, index),
|
||
delimiters = trim(
|
||
text.substring(text.indexOf('=', index) + 1, closeIndex)
|
||
).split(' ');
|
||
|
||
otag = delimiters[0];
|
||
ctag = delimiters[delimiters.length - 1];
|
||
|
||
return closeIndex + close.length - 1;
|
||
}
|
||
|
||
if (delimiters) {
|
||
delimiters = delimiters.split(' ');
|
||
otag = delimiters[0];
|
||
ctag = delimiters[1];
|
||
}
|
||
|
||
for (i = 0; i < len; i++) {
|
||
if (state == IN_TEXT) {
|
||
if (tagChange(otag, text, i)) {
|
||
--i;
|
||
addBuf();
|
||
state = IN_TAG_TYPE;
|
||
} else {
|
||
if (text.charAt(i) == '\n') {
|
||
filterLine(seenTag);
|
||
} else {
|
||
buf += text.charAt(i);
|
||
}
|
||
}
|
||
} else if (state == IN_TAG_TYPE) {
|
||
i += otag.length - 1;
|
||
tag = Hogan.tags[text.charAt(i + 1)];
|
||
tagType = tag ? text.charAt(i + 1) : '_v';
|
||
if (tagType == '=') {
|
||
i = changeDelimiters(text, i);
|
||
state = IN_TEXT;
|
||
} else {
|
||
if (tag) {
|
||
i++;
|
||
}
|
||
state = IN_TAG;
|
||
}
|
||
seenTag = i;
|
||
} else {
|
||
if (tagChange(ctag, text, i)) {
|
||
tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag,
|
||
i: (tagType == '/') ? seenTag - otag.length : i + ctag.length});
|
||
buf = '';
|
||
i += ctag.length - 1;
|
||
state = IN_TEXT;
|
||
if (tagType == '{') {
|
||
if (ctag == '}}') {
|
||
i++;
|
||
} else {
|
||
cleanTripleStache(tokens[tokens.length - 1]);
|
||
}
|
||
}
|
||
} else {
|
||
buf += text.charAt(i);
|
||
}
|
||
}
|
||
}
|
||
|
||
filterLine(seenTag, true);
|
||
|
||
return tokens;
|
||
}
|
||
|
||
function cleanTripleStache(token) {
|
||
if (token.n.substr(token.n.length - 1) === '}') {
|
||
token.n = token.n.substring(0, token.n.length - 1);
|
||
}
|
||
}
|
||
|
||
function trim(s) {
|
||
if (s.trim) {
|
||
return s.trim();
|
||
}
|
||
|
||
return s.replace(/^\s*|\s*$/g, '');
|
||
}
|
||
|
||
function tagChange(tag, text, index) {
|
||
if (text.charAt(index) != tag.charAt(0)) {
|
||
return false;
|
||
}
|
||
|
||
for (var i = 1, l = tag.length; i < l; i++) {
|
||
if (text.charAt(index + i) != tag.charAt(i)) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
// the tags allowed inside super templates
|
||
var allowedInSuper = {'_t': true, '\n': true, '$': true, '/': true};
|
||
|
||
function buildTree(tokens, kind, stack, customTags) {
|
||
var instructions = [],
|
||
opener = null,
|
||
tail = null,
|
||
token = null;
|
||
|
||
tail = stack[stack.length - 1];
|
||
|
||
while (tokens.length > 0) {
|
||
token = tokens.shift();
|
||
|
||
if (tail && tail.tag == '<' && !(token.tag in allowedInSuper)) {
|
||
throw new Error('Illegal content in < super tag.');
|
||
}
|
||
|
||
if (Hogan.tags[token.tag] <= Hogan.tags['$'] || isOpener(token, customTags)) {
|
||
stack.push(token);
|
||
token.nodes = buildTree(tokens, token.tag, stack, customTags);
|
||
} else if (token.tag == '/') {
|
||
if (stack.length === 0) {
|
||
throw new Error('Closing tag without opener: /' + token.n);
|
||
}
|
||
opener = stack.pop();
|
||
if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) {
|
||
throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n);
|
||
}
|
||
opener.end = token.i;
|
||
return instructions;
|
||
} else if (token.tag == '\n') {
|
||
token.last = (tokens.length == 0) || (tokens[0].tag == '\n');
|
||
}
|
||
|
||
instructions.push(token);
|
||
}
|
||
|
||
if (stack.length > 0) {
|
||
throw new Error('missing closing tag: ' + stack.pop().n);
|
||
}
|
||
|
||
return instructions;
|
||
}
|
||
|
||
function isOpener(token, tags) {
|
||
for (var i = 0, l = tags.length; i < l; i++) {
|
||
if (tags[i].o == token.n) {
|
||
token.tag = '#';
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
function isCloser(close, open, tags) {
|
||
for (var i = 0, l = tags.length; i < l; i++) {
|
||
if (tags[i].c == close && tags[i].o == open) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
function stringifySubstitutions(obj) {
|
||
var items = [];
|
||
for (var key in obj) {
|
||
items.push('"' + esc(key) + '": function(c,p,t,i) {' + obj[key] + '}');
|
||
}
|
||
return "{ " + items.join(",") + " }";
|
||
}
|
||
|
||
function stringifyPartials(codeObj) {
|
||
var partials = [];
|
||
for (var key in codeObj.partials) {
|
||
partials.push('"' + esc(key) + '":{name:"' + esc(codeObj.partials[key].name) + '", ' + stringifyPartials(codeObj.partials[key]) + "}");
|
||
}
|
||
return "partials: {" + partials.join(",") + "}, subs: " + stringifySubstitutions(codeObj.subs);
|
||
}
|
||
|
||
Hogan.stringify = function(codeObj, text, options) {
|
||
return "{code: function (c,p,i) { " + Hogan.wrapMain(codeObj.code) + " }," + stringifyPartials(codeObj) + "}";
|
||
}
|
||
|
||
var serialNo = 0;
|
||
Hogan.generate = function(tree, text, options) {
|
||
serialNo = 0;
|
||
var context = { code: '', subs: {}, partials: {} };
|
||
Hogan.walk(tree, context);
|
||
|
||
if (options.asString) {
|
||
return this.stringify(context, text, options);
|
||
}
|
||
|
||
return this.makeTemplate(context, text, options);
|
||
}
|
||
|
||
Hogan.wrapMain = function(code) {
|
||
return 'var t=this;t.b(i=i||"");' + code + 'return t.fl();';
|
||
}
|
||
|
||
Hogan.template = Hogan.Template;
|
||
|
||
Hogan.makeTemplate = function(codeObj, text, options) {
|
||
var template = this.makePartials(codeObj);
|
||
template.code = new Function('c', 'p', 'i', this.wrapMain(codeObj.code));
|
||
return new this.template(template, text, this, options);
|
||
}
|
||
|
||
Hogan.makePartials = function(codeObj) {
|
||
var key, template = {subs: {}, partials: codeObj.partials, name: codeObj.name};
|
||
for (key in template.partials) {
|
||
template.partials[key] = this.makePartials(template.partials[key]);
|
||
}
|
||
for (key in codeObj.subs) {
|
||
template.subs[key] = new Function('c', 'p', 't', 'i', codeObj.subs[key]);
|
||
}
|
||
return template;
|
||
}
|
||
|
||
function esc(s) {
|
||
return s.replace(rSlash, '\\\\')
|
||
.replace(rQuot, '\\\"')
|
||
.replace(rNewline, '\\n')
|
||
.replace(rCr, '\\r')
|
||
.replace(rLineSep, '\\u2028')
|
||
.replace(rParagraphSep, '\\u2029');
|
||
}
|
||
|
||
function chooseMethod(s) {
|
||
return (~s.indexOf('.')) ? 'd' : 'f';
|
||
}
|
||
|
||
function createPartial(node, context) {
|
||
var prefix = "<" + (context.prefix || "");
|
||
var sym = prefix + node.n + serialNo++;
|
||
context.partials[sym] = {name: node.n, partials: {}};
|
||
context.code += 't.b(t.rp("' + esc(sym) + '",c,p,"' + (node.indent || '') + '"));';
|
||
return sym;
|
||
}
|
||
|
||
Hogan.codegen = {
|
||
'#': function(node, context) {
|
||
context.code += 'if(t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),' +
|
||
'c,p,0,' + node.i + ',' + node.end + ',"' + node.otag + " " + node.ctag + '")){' +
|
||
't.rs(c,p,' + 'function(c,p,t){';
|
||
Hogan.walk(node.nodes, context);
|
||
context.code += '});c.pop();}';
|
||
},
|
||
|
||
'^': function(node, context) {
|
||
context.code += 'if(!t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),c,p,1,0,0,"")){';
|
||
Hogan.walk(node.nodes, context);
|
||
context.code += '};';
|
||
},
|
||
|
||
'>': createPartial,
|
||
'<': function(node, context) {
|
||
var ctx = {partials: {}, code: '', subs: {}, inPartial: true};
|
||
Hogan.walk(node.nodes, ctx);
|
||
var template = context.partials[createPartial(node, context)];
|
||
template.subs = ctx.subs;
|
||
template.partials = ctx.partials;
|
||
},
|
||
|
||
'$': function(node, context) {
|
||
var ctx = {subs: {}, code: '', partials: context.partials, prefix: node.n};
|
||
Hogan.walk(node.nodes, ctx);
|
||
context.subs[node.n] = ctx.code;
|
||
if (!context.inPartial) {
|
||
context.code += 't.sub("' + esc(node.n) + '",c,p,i);';
|
||
}
|
||
},
|
||
|
||
'\n': function(node, context) {
|
||
context.code += write('"\\n"' + (node.last ? '' : ' + i'));
|
||
},
|
||
|
||
'_v': function(node, context) {
|
||
context.code += 't.b(t.v(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));';
|
||
},
|
||
|
||
'_t': function(node, context) {
|
||
context.code += write('"' + esc(node.text) + '"');
|
||
},
|
||
|
||
'{': tripleStache,
|
||
|
||
'&': tripleStache
|
||
}
|
||
|
||
function tripleStache(node, context) {
|
||
context.code += 't.b(t.t(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));';
|
||
}
|
||
|
||
function write(s) {
|
||
return 't.b(' + s + ');';
|
||
}
|
||
|
||
Hogan.walk = function(nodelist, context) {
|
||
var func;
|
||
for (var i = 0, l = nodelist.length; i < l; i++) {
|
||
func = Hogan.codegen[nodelist[i].tag];
|
||
func && func(nodelist[i], context);
|
||
}
|
||
return context;
|
||
}
|
||
|
||
Hogan.parse = function(tokens, text, options) {
|
||
options = options || {};
|
||
return buildTree(tokens, '', [], options.sectionTags || []);
|
||
}
|
||
|
||
Hogan.cache = {};
|
||
|
||
Hogan.cacheKey = function(text, options) {
|
||
return [text, !!options.asString, !!options.disableLambda, options.delimiters, !!options.modelGet].join('||');
|
||
}
|
||
|
||
Hogan.compile = function(text, options) {
|
||
options = options || {};
|
||
var key = Hogan.cacheKey(text, options);
|
||
var template = this.cache[key];
|
||
|
||
if (template) {
|
||
var partials = template.partials;
|
||
for (var name in partials) {
|
||
delete partials[name].instance;
|
||
}
|
||
return template;
|
||
}
|
||
|
||
template = this.generate(this.parse(this.scan(text, options.delimiters), text, options), text, options);
|
||
return this.cache[key] = template;
|
||
}
|
||
})( exports );
|
||
|
||
|
||
/***/ }),
|
||
/* 28 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
/*
|
||
* Copyright 2011 Twitter, Inc.
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
var Hogan = {};
|
||
|
||
(function (Hogan) {
|
||
Hogan.Template = function (codeObj, text, compiler, options) {
|
||
codeObj = codeObj || {};
|
||
this.r = codeObj.code || this.r;
|
||
this.c = compiler;
|
||
this.options = options || {};
|
||
this.text = text || '';
|
||
this.partials = codeObj.partials || {};
|
||
this.subs = codeObj.subs || {};
|
||
this.buf = '';
|
||
}
|
||
|
||
Hogan.Template.prototype = {
|
||
// render: replaced by generated code.
|
||
r: function (context, partials, indent) { return ''; },
|
||
|
||
// variable escaping
|
||
v: hoganEscape,
|
||
|
||
// triple stache
|
||
t: coerceToString,
|
||
|
||
render: function render(context, partials, indent) {
|
||
return this.ri([context], partials || {}, indent);
|
||
},
|
||
|
||
// render internal -- a hook for overrides that catches partials too
|
||
ri: function (context, partials, indent) {
|
||
return this.r(context, partials, indent);
|
||
},
|
||
|
||
// ensurePartial
|
||
ep: function(symbol, partials) {
|
||
var partial = this.partials[symbol];
|
||
|
||
// check to see that if we've instantiated this partial before
|
||
var template = partials[partial.name];
|
||
if (partial.instance && partial.base == template) {
|
||
return partial.instance;
|
||
}
|
||
|
||
if (typeof template == 'string') {
|
||
if (!this.c) {
|
||
throw new Error("No compiler available.");
|
||
}
|
||
template = this.c.compile(template, this.options);
|
||
}
|
||
|
||
if (!template) {
|
||
return null;
|
||
}
|
||
|
||
// We use this to check whether the partials dictionary has changed
|
||
this.partials[symbol].base = template;
|
||
|
||
if (partial.subs) {
|
||
// Make sure we consider parent template now
|
||
if (!partials.stackText) partials.stackText = {};
|
||
for (var key in partial.subs) {
|
||
if (!partials.stackText[key]) {
|
||
partials.stackText[key] = (this.activeSub !== undefined && partials.stackText[this.activeSub]) ? partials.stackText[this.activeSub] : this.text;
|
||
}
|
||
}
|
||
template = createSpecializedPartial(template, partial.subs, partial.partials,
|
||
this.stackSubs, this.stackPartials, partials.stackText);
|
||
}
|
||
this.partials[symbol].instance = template;
|
||
|
||
return template;
|
||
},
|
||
|
||
// tries to find a partial in the current scope and render it
|
||
rp: function(symbol, context, partials, indent) {
|
||
var partial = this.ep(symbol, partials);
|
||
if (!partial) {
|
||
return '';
|
||
}
|
||
|
||
return partial.ri(context, partials, indent);
|
||
},
|
||
|
||
// render a section
|
||
rs: function(context, partials, section) {
|
||
var tail = context[context.length - 1];
|
||
|
||
if (!isArray(tail)) {
|
||
section(context, partials, this);
|
||
return;
|
||
}
|
||
|
||
for (var i = 0; i < tail.length; i++) {
|
||
context.push(tail[i]);
|
||
section(context, partials, this);
|
||
context.pop();
|
||
}
|
||
},
|
||
|
||
// maybe start a section
|
||
s: function(val, ctx, partials, inverted, start, end, tags) {
|
||
var pass;
|
||
|
||
if (isArray(val) && val.length === 0) {
|
||
return false;
|
||
}
|
||
|
||
if (typeof val == 'function') {
|
||
val = this.ms(val, ctx, partials, inverted, start, end, tags);
|
||
}
|
||
|
||
pass = !!val;
|
||
|
||
if (!inverted && pass && ctx) {
|
||
ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]);
|
||
}
|
||
|
||
return pass;
|
||
},
|
||
|
||
// find values with dotted names
|
||
d: function(key, ctx, partials, returnFound) {
|
||
var found,
|
||
names = key.split('.'),
|
||
val = this.f(names[0], ctx, partials, returnFound),
|
||
doModelGet = this.options.modelGet,
|
||
cx = null;
|
||
|
||
if (key === '.' && isArray(ctx[ctx.length - 2])) {
|
||
val = ctx[ctx.length - 1];
|
||
} else {
|
||
for (var i = 1; i < names.length; i++) {
|
||
found = findInScope(names[i], val, doModelGet);
|
||
if (found !== undefined) {
|
||
cx = val;
|
||
val = found;
|
||
} else {
|
||
val = '';
|
||
}
|
||
}
|
||
}
|
||
|
||
if (returnFound && !val) {
|
||
return false;
|
||
}
|
||
|
||
if (!returnFound && typeof val == 'function') {
|
||
ctx.push(cx);
|
||
val = this.mv(val, ctx, partials);
|
||
ctx.pop();
|
||
}
|
||
|
||
return val;
|
||
},
|
||
|
||
// find values with normal names
|
||
f: function(key, ctx, partials, returnFound) {
|
||
var val = false,
|
||
v = null,
|
||
found = false,
|
||
doModelGet = this.options.modelGet;
|
||
|
||
for (var i = ctx.length - 1; i >= 0; i--) {
|
||
v = ctx[i];
|
||
val = findInScope(key, v, doModelGet);
|
||
if (val !== undefined) {
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!found) {
|
||
return (returnFound) ? false : "";
|
||
}
|
||
|
||
if (!returnFound && typeof val == 'function') {
|
||
val = this.mv(val, ctx, partials);
|
||
}
|
||
|
||
return val;
|
||
},
|
||
|
||
// higher order templates
|
||
ls: function(func, cx, partials, text, tags) {
|
||
var oldTags = this.options.delimiters;
|
||
|
||
this.options.delimiters = tags;
|
||
this.b(this.ct(coerceToString(func.call(cx, text)), cx, partials));
|
||
this.options.delimiters = oldTags;
|
||
|
||
return false;
|
||
},
|
||
|
||
// compile text
|
||
ct: function(text, cx, partials) {
|
||
if (this.options.disableLambda) {
|
||
throw new Error('Lambda features disabled.');
|
||
}
|
||
return this.c.compile(text, this.options).render(cx, partials);
|
||
},
|
||
|
||
// template result buffering
|
||
b: function(s) { this.buf += s; },
|
||
|
||
fl: function() { var r = this.buf; this.buf = ''; return r; },
|
||
|
||
// method replace section
|
||
ms: function(func, ctx, partials, inverted, start, end, tags) {
|
||
var textSource,
|
||
cx = ctx[ctx.length - 1],
|
||
result = func.call(cx);
|
||
|
||
if (typeof result == 'function') {
|
||
if (inverted) {
|
||
return true;
|
||
} else {
|
||
textSource = (this.activeSub && this.subsText && this.subsText[this.activeSub]) ? this.subsText[this.activeSub] : this.text;
|
||
return this.ls(result, cx, partials, textSource.substring(start, end), tags);
|
||
}
|
||
}
|
||
|
||
return result;
|
||
},
|
||
|
||
// method replace variable
|
||
mv: function(func, ctx, partials) {
|
||
var cx = ctx[ctx.length - 1];
|
||
var result = func.call(cx);
|
||
|
||
if (typeof result == 'function') {
|
||
return this.ct(coerceToString(result.call(cx)), cx, partials);
|
||
}
|
||
|
||
return result;
|
||
},
|
||
|
||
sub: function(name, context, partials, indent) {
|
||
var f = this.subs[name];
|
||
if (f) {
|
||
this.activeSub = name;
|
||
f(context, partials, this, indent);
|
||
this.activeSub = false;
|
||
}
|
||
}
|
||
|
||
};
|
||
|
||
//Find a key in an object
|
||
function findInScope(key, scope, doModelGet) {
|
||
var val;
|
||
|
||
if (scope && typeof scope == 'object') {
|
||
|
||
if (scope[key] !== undefined) {
|
||
val = scope[key];
|
||
|
||
// try lookup with get for backbone or similar model data
|
||
} else if (doModelGet && scope.get && typeof scope.get == 'function') {
|
||
val = scope.get(key);
|
||
}
|
||
}
|
||
|
||
return val;
|
||
}
|
||
|
||
function createSpecializedPartial(instance, subs, partials, stackSubs, stackPartials, stackText) {
|
||
function PartialTemplate() {};
|
||
PartialTemplate.prototype = instance;
|
||
function Substitutions() {};
|
||
Substitutions.prototype = instance.subs;
|
||
var key;
|
||
var partial = new PartialTemplate();
|
||
partial.subs = new Substitutions();
|
||
partial.subsText = {}; //hehe. substext.
|
||
partial.buf = '';
|
||
|
||
stackSubs = stackSubs || {};
|
||
partial.stackSubs = stackSubs;
|
||
partial.subsText = stackText;
|
||
for (key in subs) {
|
||
if (!stackSubs[key]) stackSubs[key] = subs[key];
|
||
}
|
||
for (key in stackSubs) {
|
||
partial.subs[key] = stackSubs[key];
|
||
}
|
||
|
||
stackPartials = stackPartials || {};
|
||
partial.stackPartials = stackPartials;
|
||
for (key in partials) {
|
||
if (!stackPartials[key]) stackPartials[key] = partials[key];
|
||
}
|
||
for (key in stackPartials) {
|
||
partial.partials[key] = stackPartials[key];
|
||
}
|
||
|
||
return partial;
|
||
}
|
||
|
||
var rAmp = /&/g,
|
||
rLt = /</g,
|
||
rGt = />/g,
|
||
rApos = /\'/g,
|
||
rQuot = /\"/g,
|
||
hChars = /[&<>\"\']/;
|
||
|
||
function coerceToString(val) {
|
||
return String((val === null || val === undefined) ? '' : val);
|
||
}
|
||
|
||
function hoganEscape(str) {
|
||
str = coerceToString(str);
|
||
return hChars.test(str) ?
|
||
str
|
||
.replace(rAmp, '&')
|
||
.replace(rLt, '<')
|
||
.replace(rGt, '>')
|
||
.replace(rApos, ''')
|
||
.replace(rQuot, '"') :
|
||
str;
|
||
}
|
||
|
||
var isArray = Array.isArray || function(a) {
|
||
return Object.prototype.toString.call(a) === '[object Array]';
|
||
};
|
||
|
||
})( true ? exports : Hogan);
|
||
|
||
|
||
/***/ }),
|
||
/* 29 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var AlgoliaSearchCore = __webpack_require__(30);
|
||
var createAlgoliasearch = __webpack_require__(41);
|
||
|
||
module.exports = createAlgoliasearch(AlgoliaSearchCore, '(lite) ');
|
||
|
||
|
||
/***/ }),
|
||
/* 30 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = AlgoliaSearchCore;
|
||
|
||
var errors = __webpack_require__(5);
|
||
var exitPromise = __webpack_require__(31);
|
||
var IndexCore = __webpack_require__(32);
|
||
var store = __webpack_require__(38);
|
||
|
||
// 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 =
|
||
Object({"NODE_ENV":"production"}).RESET_APP_DATA_TIMER && parseInt(Object({"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='https:'] - The protocol used to query Algolia Search API.
|
||
* Set to 'http:' to force using http.
|
||
* @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__(8)('algoliasearch');
|
||
|
||
var clone = __webpack_require__(3);
|
||
var isArray = __webpack_require__(6);
|
||
var map = __webpack_require__(7);
|
||
|
||
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 || {};
|
||
|
||
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;
|
||
}
|
||
|
||
var protocol = opts.protocol || 'https:';
|
||
// 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 (protocol !== 'http:' && 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
|
||
var mainSuffix = (opts.dsn === false ? '' : '-dsn') + '.algolia.net';
|
||
this.hosts.read = [this.applicationID + mainSuffix].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._useRequestCache = this._useCache && opts._useRequestCache;
|
||
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[name.toLowerCase()] = value;
|
||
};
|
||
|
||
/**
|
||
* Get the value of an extra HTTP header
|
||
*
|
||
* @param name the header field name
|
||
*/
|
||
AlgoliaSearchCore.prototype.getExtraHeader = function(name) {
|
||
return this.extraHeaders[name.toLowerCase()];
|
||
};
|
||
|
||
/**
|
||
* Remove an extra field from the HTTP request
|
||
*
|
||
* @param name the header field name
|
||
*/
|
||
AlgoliaSearchCore.prototype.unsetExtraHeader = function(name) {
|
||
delete this.extraHeaders[name.toLowerCase()];
|
||
};
|
||
|
||
/**
|
||
* 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__(8)('algoliasearch:' + initialOpts.url);
|
||
|
||
|
||
var body;
|
||
var cacheID;
|
||
var additionalUA = initialOpts.additionalUA || '';
|
||
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({
|
||
additionalUA: additionalUA,
|
||
withApiKey: false,
|
||
headers: initialOpts.headers
|
||
});
|
||
} else {
|
||
headers = this._computeRequestHeaders({
|
||
additionalUA: additionalUA,
|
||
headers: initialOpts.headers
|
||
});
|
||
}
|
||
|
||
if (initialOpts.body !== undefined) {
|
||
body = safeJSONStringify(initialOpts.body);
|
||
}
|
||
|
||
requestDebug('request start');
|
||
var debugData = [];
|
||
|
||
|
||
function doRequest(requester, reqOpts) {
|
||
client._checkAppIdData();
|
||
|
||
var startTime = new Date();
|
||
|
||
if (client._useCache && !client._useRequestCache) {
|
||
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 && !client._useRequestCache && body) {
|
||
cacheID += '_body_' + reqOpts.body;
|
||
}
|
||
|
||
// handle cache existence
|
||
if (isCacheValidWithCurrentID(!client._useRequestCache, cache, cacheID)) {
|
||
requestDebug('serving response from cache');
|
||
|
||
var responseText = cache[cacheID];
|
||
|
||
// Cache response must match the type of the original one
|
||
return client._promise.resolve({
|
||
body: JSON.parse(responseText),
|
||
responseText: responseText
|
||
});
|
||
}
|
||
|
||
// 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({
|
||
additionalUA: additionalUA,
|
||
headers: initialOpts.headers
|
||
});
|
||
|
||
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,
|
||
forceAuthHeaders: reqOpts.forceAuthHeaders
|
||
};
|
||
|
||
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 && !client._useRequestCache && cache) {
|
||
cache[cacheID] = httpResponse.responseText;
|
||
}
|
||
|
||
return {
|
||
responseText: httpResponse.responseText,
|
||
body: 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);
|
||
}
|
||
}
|
||
|
||
function isCacheValidWithCurrentID(
|
||
useRequestCache,
|
||
currentCache,
|
||
currentCacheID
|
||
) {
|
||
return (
|
||
client._useCache &&
|
||
useRequestCache &&
|
||
currentCache &&
|
||
currentCache[currentCacheID] !== undefined
|
||
);
|
||
}
|
||
|
||
|
||
function interopCallbackReturn(request, callback) {
|
||
if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) {
|
||
request.catch(function() {
|
||
// Release the cache on error
|
||
delete cache[cacheID];
|
||
});
|
||
}
|
||
|
||
if (typeof initialOpts.callback === 'function') {
|
||
// either we have a callback
|
||
request.then(function okCb(content) {
|
||
exitPromise(function() {
|
||
initialOpts.callback(null, callback(content));
|
||
}, client._setTimeout || setTimeout);
|
||
}, function nookCb(err) {
|
||
exitPromise(function() {
|
||
initialOpts.callback(err);
|
||
}, client._setTimeout || setTimeout);
|
||
});
|
||
} else {
|
||
// either we are using promises
|
||
return request.then(callback);
|
||
}
|
||
}
|
||
|
||
if (client._useCache && client._useRequestCache) {
|
||
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 && client._useRequestCache && body) {
|
||
cacheID += '_body_' + body;
|
||
}
|
||
|
||
if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) {
|
||
requestDebug('serving request from cache');
|
||
|
||
var maybePromiseForCache = cache[cacheID];
|
||
|
||
// In case the cache is warmup with value that is not a promise
|
||
var promiseForCache = typeof maybePromiseForCache.then !== 'function'
|
||
? client._promise.resolve({responseText: maybePromiseForCache})
|
||
: maybePromiseForCache;
|
||
|
||
return interopCallbackReturn(promiseForCache, function(content) {
|
||
// In case of the cache request, return the original value
|
||
return JSON.parse(content.responseText);
|
||
});
|
||
}
|
||
|
||
var request = doRequest(
|
||
client._request, {
|
||
url: initialOpts.url,
|
||
method: initialOpts.method,
|
||
body: body,
|
||
jsonBody: initialOpts.body,
|
||
timeouts: client._getTimeoutsForRequest(initialOpts.hostType),
|
||
forceAuthHeaders: initialOpts.forceAuthHeaders
|
||
}
|
||
);
|
||
|
||
if (client._useCache && client._useRequestCache && cache) {
|
||
cache[cacheID] = request;
|
||
}
|
||
|
||
return interopCallbackReturn(request, function(content) {
|
||
// In case of the first request, return the JSON value
|
||
return content.body;
|
||
});
|
||
};
|
||
|
||
/*
|
||
* Transform search param object in query string
|
||
* @param {object} args arguments to add to the current query string
|
||
* @param {string} params current query string
|
||
* @return {string} the final 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;
|
||
};
|
||
|
||
/**
|
||
* Compute the headers for a request
|
||
*
|
||
* @param [string] options.additionalUA semi-colon separated string with other user agents to add
|
||
* @param [boolean=true] options.withApiKey Send the api key as a header
|
||
* @param [Object] options.headers Extra headers to send
|
||
*/
|
||
AlgoliaSearchCore.prototype._computeRequestHeaders = function(options) {
|
||
var forEach = __webpack_require__(2);
|
||
|
||
var ua = options.additionalUA ?
|
||
this._ua + ';' + options.additionalUA :
|
||
this._ua;
|
||
|
||
var requestHeaders = {
|
||
'x-algolia-agent': 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 (options.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;
|
||
}
|
||
|
||
forEach(this.extraHeaders, function addToRequestHeaders(value, key) {
|
||
requestHeaders[key] = value;
|
||
});
|
||
|
||
if (options.headers) {
|
||
forEach(options.headers, function addToRequestHeaders(value, key) {
|
||
requestHeaders[key] = 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__(6);
|
||
var map = __webpack_require__(7);
|
||
|
||
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) {
|
||
postObj.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
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Search for facet values
|
||
* https://www.algolia.com/doc/rest-api/search#search-for-facet-values
|
||
* This is the top-level API for SFFV.
|
||
*
|
||
* @param {object[]} queries An array of queries to run.
|
||
* @param {string} queries[].indexName Index name, name of the index to search.
|
||
* @param {object} queries[].params Query parameters.
|
||
* @param {string} queries[].params.facetName Facet name, name of the attribute to search for values in.
|
||
* Must be declared as a facet
|
||
* @param {string} queries[].params.facetQuery Query for the facet search
|
||
* @param {string} [queries[].params.*] Any search parameter of Algolia,
|
||
* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters
|
||
* Pagination is not supported. The page and hitsPerPage parameters will be ignored.
|
||
*/
|
||
AlgoliaSearchCore.prototype.searchForFacetValues = function(queries) {
|
||
var isArray = __webpack_require__(6);
|
||
var map = __webpack_require__(7);
|
||
|
||
var usage = 'Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])'; // eslint-disable-line max-len
|
||
|
||
if (!isArray(queries)) {
|
||
throw new Error(usage);
|
||
}
|
||
|
||
var client = this;
|
||
|
||
return client._promise.all(map(queries, function performQuery(query) {
|
||
if (
|
||
!query ||
|
||
query.indexName === undefined ||
|
||
query.params.facetName === undefined ||
|
||
query.params.facetQuery === undefined
|
||
) {
|
||
throw new Error(usage);
|
||
}
|
||
|
||
var clone = __webpack_require__(3);
|
||
var omit = __webpack_require__(14);
|
||
|
||
var indexName = query.indexName;
|
||
var params = query.params;
|
||
|
||
var facetName = params.facetName;
|
||
var filteredParams = omit(clone(params), function(keyName) {
|
||
return keyName === 'facetName';
|
||
});
|
||
var searchParameters = client._getSearchParams(filteredParams, '');
|
||
|
||
return client._jsonRequest({
|
||
cache: client.cache,
|
||
method: 'POST',
|
||
url:
|
||
'/1/indexes/' +
|
||
encodeURIComponent(indexName) +
|
||
'/facets/' +
|
||
encodeURIComponent(facetName) +
|
||
'/query',
|
||
hostType: 'read',
|
||
body: {params: searchParameters}
|
||
});
|
||
}));
|
||
};
|
||
|
||
/**
|
||
* 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__(2);
|
||
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__(3);
|
||
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;
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 31 */
|
||
/***/ (function(module, exports) {
|
||
|
||
// Parse cloud does not supports setTimeout
|
||
// We do not store a setTimeout reference in the client everytime
|
||
// We only fallback to a fake setTimeout when not available
|
||
// setTimeout cannot be override globally sadly
|
||
module.exports = function exitPromise(fn, _setTimeout) {
|
||
_setTimeout(fn, 0);
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 32 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
var buildSearchMethod = __webpack_require__(13);
|
||
var deprecate = __webpack_require__(33);
|
||
var deprecatedMessage = __webpack_require__(34);
|
||
|
||
module.exports = IndexCore;
|
||
|
||
/*
|
||
* Index class constructor.
|
||
* You should not use this method directly but use initIndex() function
|
||
*/
|
||
function IndexCore(algoliasearch, indexName) {
|
||
this.indexName = indexName;
|
||
this.as = algoliasearch;
|
||
this.typeAheadArgs = null;
|
||
this.typeAheadValueOption = null;
|
||
|
||
// make sure every index instance has it's own cache
|
||
this.cache = {};
|
||
}
|
||
|
||
/*
|
||
* Clear all queries in cache
|
||
*/
|
||
IndexCore.prototype.clearCache = function() {
|
||
this.cache = {};
|
||
};
|
||
|
||
/*
|
||
* Search inside the index using XMLHttpRequest request (Using a POST query to
|
||
* minimize number of OPTIONS queries: Cross-Origin Resource Sharing).
|
||
*
|
||
* @param {string} [query] the full text query
|
||
* @param {object} [args] (optional) if set, contains an object with query parameters:
|
||
* - page: (integer) Pagination parameter used to select the page to retrieve.
|
||
* Page is zero-based and defaults to 0. Thus,
|
||
* to retrieve the 10th page you need to set page=9
|
||
* - hitsPerPage: (integer) Pagination parameter used to select the number of hits per page. Defaults to 20.
|
||
* - attributesToRetrieve: a string that contains the list of object attributes
|
||
* you want to retrieve (let you minimize the answer size).
|
||
* Attributes are separated with a comma (for example "name,address").
|
||
* You can also use an array (for example ["name","address"]).
|
||
* By default, all attributes are retrieved. You can also use '*' to retrieve all
|
||
* values when an attributesToRetrieve setting is specified for your index.
|
||
* - attributesToHighlight: a string that contains the list of attributes you
|
||
* want to highlight according to the query.
|
||
* Attributes are separated by a comma. You can also use an array (for example ["name","address"]).
|
||
* If an attribute has no match for the query, the raw value is returned.
|
||
* By default all indexed text attributes are highlighted.
|
||
* You can use `*` if you want to highlight all textual attributes.
|
||
* Numerical attributes are not highlighted.
|
||
* A matchLevel is returned for each highlighted attribute and can contain:
|
||
* - full: if all the query terms were found in the attribute,
|
||
* - partial: if only some of the query terms were found,
|
||
* - none: if none of the query terms were found.
|
||
* - attributesToSnippet: a string that contains the list of attributes to snippet alongside
|
||
* the number of words to return (syntax is `attributeName:nbWords`).
|
||
* Attributes are separated by a comma (Example: attributesToSnippet=name:10,content:10).
|
||
* You can also use an array (Example: attributesToSnippet: ['name:10','content:10']).
|
||
* By default no snippet is computed.
|
||
* - minWordSizefor1Typo: the minimum number of characters in a query word to accept one typo in this word.
|
||
* Defaults to 3.
|
||
* - minWordSizefor2Typos: the minimum number of characters in a query word
|
||
* to accept two typos in this word. Defaults to 7.
|
||
* - getRankingInfo: if set to 1, the result hits will contain ranking
|
||
* information in _rankingInfo attribute.
|
||
* - aroundLatLng: search for entries around a given
|
||
* latitude/longitude (specified as two floats separated by a comma).
|
||
* For example aroundLatLng=47.316669,5.016670).
|
||
* You can specify the maximum distance in meters with the aroundRadius parameter (in meters)
|
||
* and the precision for ranking with aroundPrecision
|
||
* (for example if you set aroundPrecision=100, two objects that are distant of
|
||
* less than 100m will be considered as identical for "geo" ranking parameter).
|
||
* At indexing, you should specify geoloc of an object with the _geoloc attribute
|
||
* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}})
|
||
* - insideBoundingBox: search entries inside a given area defined by the two extreme points
|
||
* of a rectangle (defined by 4 floats: p1Lat,p1Lng,p2Lat,p2Lng).
|
||
* For example insideBoundingBox=47.3165,4.9665,47.3424,5.0201).
|
||
* At indexing, you should specify geoloc of an object with the _geoloc attribute
|
||
* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}})
|
||
* - numericFilters: a string that contains the list of numeric filters you want to
|
||
* apply separated by a comma.
|
||
* The syntax of one filter is `attributeName` followed by `operand` followed by `value`.
|
||
* Supported operands are `<`, `<=`, `=`, `>` and `>=`.
|
||
* You can have multiple conditions on one attribute like for example numericFilters=price>100,price<1000.
|
||
* You can also use an array (for example numericFilters: ["price>100","price<1000"]).
|
||
* - tagFilters: filter the query by a set of tags. You can AND tags by separating them by commas.
|
||
* To OR tags, you must add parentheses. For example, tags=tag1,(tag2,tag3) means tag1 AND (tag2 OR tag3).
|
||
* You can also use an array, for example tagFilters: ["tag1",["tag2","tag3"]]
|
||
* means tag1 AND (tag2 OR tag3).
|
||
* At indexing, tags should be added in the _tags** attribute
|
||
* of objects (for example {"_tags":["tag1","tag2"]}).
|
||
* - facetFilters: filter the query by a list of facets.
|
||
* Facets are separated by commas and each facet is encoded as `attributeName:value`.
|
||
* For example: `facetFilters=category:Book,author:John%20Doe`.
|
||
* You can also use an array (for example `["category:Book","author:John%20Doe"]`).
|
||
* - facets: List of object attributes that you want to use for faceting.
|
||
* Comma separated list: `"category,author"` or array `['category','author']`
|
||
* Only attributes that have been added in **attributesForFaceting** index setting
|
||
* can be used in this parameter.
|
||
* You can also use `*` to perform faceting on all attributes specified in **attributesForFaceting**.
|
||
* - queryType: select how the query words are interpreted, it can be one of the following value:
|
||
* - prefixAll: all query words are interpreted as prefixes,
|
||
* - prefixLast: only the last word is interpreted as a prefix (default behavior),
|
||
* - prefixNone: no query word is interpreted as a prefix. This option is not recommended.
|
||
* - optionalWords: a string that contains the list of words that should
|
||
* be considered as optional when found in the query.
|
||
* Comma separated and array are accepted.
|
||
* - distinct: If set to 1, enable the distinct feature (disabled by default)
|
||
* if the attributeForDistinct index setting is set.
|
||
* This feature is similar to the SQL "distinct" keyword: when enabled
|
||
* in a query with the distinct=1 parameter,
|
||
* all hits containing a duplicate value for the attributeForDistinct attribute are removed from results.
|
||
* For example, if the chosen attribute is show_name and several hits have
|
||
* the same value for show_name, then only the best
|
||
* one is kept and others are removed.
|
||
* - restrictSearchableAttributes: List of attributes you want to use for
|
||
* textual search (must be a subset of the attributesToIndex index setting)
|
||
* either comma separated or as an array
|
||
* @param {function} [callback] the result callback called with two arguments:
|
||
* error: null or Error('message'). If false, the content contains the error.
|
||
* content: the server answer that contains the list of results.
|
||
*/
|
||
IndexCore.prototype.search = buildSearchMethod('query');
|
||
|
||
/*
|
||
* -- BETA --
|
||
* Search a record similar to the query inside the index using XMLHttpRequest request (Using a POST query to
|
||
* minimize number of OPTIONS queries: Cross-Origin Resource Sharing).
|
||
*
|
||
* @param {string} [query] the similar query
|
||
* @param {object} [args] (optional) if set, contains an object with query parameters.
|
||
* All search parameters are supported (see search function), restrictSearchableAttributes and facetFilters
|
||
* are the two most useful to restrict the similar results and get more relevant content
|
||
*/
|
||
IndexCore.prototype.similarSearch = buildSearchMethod('similarQuery');
|
||
|
||
/*
|
||
* Browse index content. The response content will have a `cursor` property that you can use
|
||
* to browse subsequent pages for this query. Use `index.browseFrom(cursor)` when you want.
|
||
*
|
||
* @param {string} query - The full text query
|
||
* @param {Object} [queryParameters] - Any search query parameter
|
||
* @param {Function} [callback] - The result callback called with two arguments
|
||
* error: null or Error('message')
|
||
* content: the server answer with the browse result
|
||
* @return {Promise|undefined} Returns a promise if no callback given
|
||
* @example
|
||
* index.browse('cool songs', {
|
||
* tagFilters: 'public,comments',
|
||
* hitsPerPage: 500
|
||
* }, callback);
|
||
* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation}
|
||
*/
|
||
IndexCore.prototype.browse = function(query, queryParameters, callback) {
|
||
var merge = __webpack_require__(35);
|
||
|
||
var indexObj = this;
|
||
|
||
var page;
|
||
var hitsPerPage;
|
||
|
||
// we check variadic calls that are not the one defined
|
||
// .browse()/.browse(fn)
|
||
// => page = 0
|
||
if (arguments.length === 0 || arguments.length === 1 && typeof arguments[0] === 'function') {
|
||
page = 0;
|
||
callback = arguments[0];
|
||
query = undefined;
|
||
} else if (typeof arguments[0] === 'number') {
|
||
// .browse(2)/.browse(2, 10)/.browse(2, fn)/.browse(2, 10, fn)
|
||
page = arguments[0];
|
||
if (typeof arguments[1] === 'number') {
|
||
hitsPerPage = arguments[1];
|
||
} else if (typeof arguments[1] === 'function') {
|
||
callback = arguments[1];
|
||
hitsPerPage = undefined;
|
||
}
|
||
query = undefined;
|
||
queryParameters = undefined;
|
||
} else if (typeof arguments[0] === 'object') {
|
||
// .browse(queryParameters)/.browse(queryParameters, cb)
|
||
if (typeof arguments[1] === 'function') {
|
||
callback = arguments[1];
|
||
}
|
||
queryParameters = arguments[0];
|
||
query = undefined;
|
||
} else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'function') {
|
||
// .browse(query, cb)
|
||
callback = arguments[1];
|
||
queryParameters = undefined;
|
||
}
|
||
|
||
// otherwise it's a .browse(query)/.browse(query, queryParameters)/.browse(query, queryParameters, cb)
|
||
|
||
// get search query parameters combining various possible calls
|
||
// to .browse();
|
||
queryParameters = merge({}, queryParameters || {}, {
|
||
page: page,
|
||
hitsPerPage: hitsPerPage,
|
||
query: query
|
||
});
|
||
|
||
var params = this.as._getSearchParams(queryParameters, '');
|
||
|
||
return this.as._jsonRequest({
|
||
method: 'POST',
|
||
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/browse',
|
||
body: {params: params},
|
||
hostType: 'read',
|
||
callback: callback
|
||
});
|
||
};
|
||
|
||
/*
|
||
* Continue browsing from a previous position (cursor), obtained via a call to `.browse()`.
|
||
*
|
||
* @param {string} query - The full text query
|
||
* @param {Object} [queryParameters] - Any search query parameter
|
||
* @param {Function} [callback] - The result callback called with two arguments
|
||
* error: null or Error('message')
|
||
* content: the server answer with the browse result
|
||
* @return {Promise|undefined} Returns a promise if no callback given
|
||
* @example
|
||
* index.browseFrom('14lkfsakl32', callback);
|
||
* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation}
|
||
*/
|
||
IndexCore.prototype.browseFrom = function(cursor, callback) {
|
||
return this.as._jsonRequest({
|
||
method: 'POST',
|
||
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/browse',
|
||
body: {cursor: cursor},
|
||
hostType: 'read',
|
||
callback: callback
|
||
});
|
||
};
|
||
|
||
/*
|
||
* Search for facet values
|
||
* https://www.algolia.com/doc/rest-api/search#search-for-facet-values
|
||
*
|
||
* @param {string} params.facetName Facet name, name of the attribute to search for values in.
|
||
* Must be declared as a facet
|
||
* @param {string} params.facetQuery Query for the facet search
|
||
* @param {string} [params.*] Any search parameter of Algolia,
|
||
* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters
|
||
* Pagination is not supported. The page and hitsPerPage parameters will be ignored.
|
||
* @param callback (optional)
|
||
*/
|
||
IndexCore.prototype.searchForFacetValues = function(params, callback) {
|
||
var clone = __webpack_require__(3);
|
||
var omit = __webpack_require__(14);
|
||
var usage = 'Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])';
|
||
|
||
if (params.facetName === undefined || params.facetQuery === undefined) {
|
||
throw new Error(usage);
|
||
}
|
||
|
||
var facetName = params.facetName;
|
||
var filteredParams = omit(clone(params), function(keyName) {
|
||
return keyName === 'facetName';
|
||
});
|
||
var searchParameters = this.as._getSearchParams(filteredParams, '');
|
||
|
||
return this.as._jsonRequest({
|
||
method: 'POST',
|
||
url: '/1/indexes/' +
|
||
encodeURIComponent(this.indexName) + '/facets/' + encodeURIComponent(facetName) + '/query',
|
||
hostType: 'read',
|
||
body: {params: searchParameters},
|
||
callback: callback
|
||
});
|
||
};
|
||
|
||
IndexCore.prototype.searchFacet = deprecate(function(params, callback) {
|
||
return this.searchForFacetValues(params, callback);
|
||
}, deprecatedMessage(
|
||
'index.searchFacet(params[, callback])',
|
||
'index.searchForFacetValues(params[, callback])'
|
||
));
|
||
|
||
IndexCore.prototype._search = function(params, url, callback, additionalUA) {
|
||
return this.as._jsonRequest({
|
||
cache: this.cache,
|
||
method: 'POST',
|
||
url: url || '/1/indexes/' + encodeURIComponent(this.indexName) + '/query',
|
||
body: {params: params},
|
||
hostType: 'read',
|
||
fallback: {
|
||
method: 'GET',
|
||
url: '/1/indexes/' + encodeURIComponent(this.indexName),
|
||
body: {params: params}
|
||
},
|
||
callback: callback,
|
||
additionalUA: additionalUA
|
||
});
|
||
};
|
||
|
||
/*
|
||
* Get an object from this index
|
||
*
|
||
* @param objectID the unique identifier of the object to retrieve
|
||
* @param attrs (optional) if set, contains the array of attribute names to retrieve
|
||
* @param callback (optional) the result callback called with two arguments
|
||
* error: null or Error('message')
|
||
* content: the object to retrieve or the error message if a failure occured
|
||
*/
|
||
IndexCore.prototype.getObject = function(objectID, attrs, callback) {
|
||
var indexObj = this;
|
||
|
||
if (arguments.length === 1 || typeof attrs === 'function') {
|
||
callback = attrs;
|
||
attrs = undefined;
|
||
}
|
||
|
||
var params = '';
|
||
if (attrs !== undefined) {
|
||
params = '?attributes=';
|
||
for (var i = 0; i < attrs.length; ++i) {
|
||
if (i !== 0) {
|
||
params += ',';
|
||
}
|
||
params += attrs[i];
|
||
}
|
||
}
|
||
|
||
return this.as._jsonRequest({
|
||
method: 'GET',
|
||
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID) + params,
|
||
hostType: 'read',
|
||
callback: callback
|
||
});
|
||
};
|
||
|
||
/*
|
||
* Get several objects from this index
|
||
*
|
||
* @param objectIDs the array of unique identifier of objects to retrieve
|
||
*/
|
||
IndexCore.prototype.getObjects = function(objectIDs, attributesToRetrieve, callback) {
|
||
var isArray = __webpack_require__(6);
|
||
var map = __webpack_require__(7);
|
||
|
||
var usage = 'Usage: index.getObjects(arrayOfObjectIDs[, callback])';
|
||
|
||
if (!isArray(objectIDs)) {
|
||
throw new Error(usage);
|
||
}
|
||
|
||
var indexObj = this;
|
||
|
||
if (arguments.length === 1 || typeof attributesToRetrieve === 'function') {
|
||
callback = attributesToRetrieve;
|
||
attributesToRetrieve = undefined;
|
||
}
|
||
|
||
var body = {
|
||
requests: map(objectIDs, function prepareRequest(objectID) {
|
||
var request = {
|
||
indexName: indexObj.indexName,
|
||
objectID: objectID
|
||
};
|
||
|
||
if (attributesToRetrieve) {
|
||
request.attributesToRetrieve = attributesToRetrieve.join(',');
|
||
}
|
||
|
||
return request;
|
||
})
|
||
};
|
||
|
||
return this.as._jsonRequest({
|
||
method: 'POST',
|
||
url: '/1/indexes/*/objects',
|
||
hostType: 'read',
|
||
body: body,
|
||
callback: callback
|
||
});
|
||
};
|
||
|
||
IndexCore.prototype.as = null;
|
||
IndexCore.prototype.indexName = null;
|
||
IndexCore.prototype.typeAheadArgs = null;
|
||
IndexCore.prototype.typeAheadValueOption = null;
|
||
|
||
|
||
/***/ }),
|
||
/* 33 */
|
||
/***/ (function(module, exports) {
|
||
|
||
module.exports = function deprecate(fn, message) {
|
||
var warned = false;
|
||
|
||
function deprecated() {
|
||
if (!warned) {
|
||
/* eslint no-console:0 */
|
||
console.warn(message);
|
||
warned = true;
|
||
}
|
||
|
||
return fn.apply(this, arguments);
|
||
}
|
||
|
||
return deprecated;
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 34 */
|
||
/***/ (function(module, exports) {
|
||
|
||
module.exports = function deprecatedMessage(previousUsage, newUsage) {
|
||
var githubAnchorLink = previousUsage.toLowerCase()
|
||
.replace(/[\.\(\)]/g, '');
|
||
|
||
return 'algoliasearch: `' + previousUsage + '` was replaced by `' + newUsage +
|
||
'`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#' + githubAnchorLink;
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 35 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
var foreach = __webpack_require__(2);
|
||
|
||
module.exports = function merge(destination/* , sources */) {
|
||
var sources = Array.prototype.slice.call(arguments);
|
||
|
||
foreach(sources, function(source) {
|
||
for (var keyName in source) {
|
||
if (source.hasOwnProperty(keyName)) {
|
||
if (typeof destination[keyName] === 'object' && typeof source[keyName] === 'object') {
|
||
destination[keyName] = merge({}, destination[keyName], source[keyName]);
|
||
} else if (source[keyName] !== undefined) {
|
||
destination[keyName] = source[keyName];
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
return destination;
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 36 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
// modified from https://github.com/es-shims/es5-shim
|
||
var has = Object.prototype.hasOwnProperty;
|
||
var toStr = Object.prototype.toString;
|
||
var slice = Array.prototype.slice;
|
||
var isArgs = __webpack_require__(37);
|
||
var isEnumerable = Object.prototype.propertyIsEnumerable;
|
||
var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString');
|
||
var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype');
|
||
var dontEnums = [
|
||
'toString',
|
||
'toLocaleString',
|
||
'valueOf',
|
||
'hasOwnProperty',
|
||
'isPrototypeOf',
|
||
'propertyIsEnumerable',
|
||
'constructor'
|
||
];
|
||
var equalsConstructorPrototype = function (o) {
|
||
var ctor = o.constructor;
|
||
return ctor && ctor.prototype === o;
|
||
};
|
||
var excludedKeys = {
|
||
$applicationCache: true,
|
||
$console: true,
|
||
$external: true,
|
||
$frame: true,
|
||
$frameElement: true,
|
||
$frames: true,
|
||
$innerHeight: true,
|
||
$innerWidth: true,
|
||
$outerHeight: true,
|
||
$outerWidth: true,
|
||
$pageXOffset: true,
|
||
$pageYOffset: true,
|
||
$parent: true,
|
||
$scrollLeft: true,
|
||
$scrollTop: true,
|
||
$scrollX: true,
|
||
$scrollY: true,
|
||
$self: true,
|
||
$webkitIndexedDB: true,
|
||
$webkitStorageInfo: true,
|
||
$window: true
|
||
};
|
||
var hasAutomationEqualityBug = (function () {
|
||
/* global window */
|
||
if (typeof window === 'undefined') { return false; }
|
||
for (var k in window) {
|
||
try {
|
||
if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') {
|
||
try {
|
||
equalsConstructorPrototype(window[k]);
|
||
} catch (e) {
|
||
return true;
|
||
}
|
||
}
|
||
} catch (e) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}());
|
||
var equalsConstructorPrototypeIfNotBuggy = function (o) {
|
||
/* global window */
|
||
if (typeof window === 'undefined' || !hasAutomationEqualityBug) {
|
||
return equalsConstructorPrototype(o);
|
||
}
|
||
try {
|
||
return equalsConstructorPrototype(o);
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
var keysShim = function keys(object) {
|
||
var isObject = object !== null && typeof object === 'object';
|
||
var isFunction = toStr.call(object) === '[object Function]';
|
||
var isArguments = isArgs(object);
|
||
var isString = isObject && toStr.call(object) === '[object String]';
|
||
var theKeys = [];
|
||
|
||
if (!isObject && !isFunction && !isArguments) {
|
||
throw new TypeError('Object.keys called on a non-object');
|
||
}
|
||
|
||
var skipProto = hasProtoEnumBug && isFunction;
|
||
if (isString && object.length > 0 && !has.call(object, 0)) {
|
||
for (var i = 0; i < object.length; ++i) {
|
||
theKeys.push(String(i));
|
||
}
|
||
}
|
||
|
||
if (isArguments && object.length > 0) {
|
||
for (var j = 0; j < object.length; ++j) {
|
||
theKeys.push(String(j));
|
||
}
|
||
} else {
|
||
for (var name in object) {
|
||
if (!(skipProto && name === 'prototype') && has.call(object, name)) {
|
||
theKeys.push(String(name));
|
||
}
|
||
}
|
||
}
|
||
|
||
if (hasDontEnumBug) {
|
||
var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
|
||
|
||
for (var k = 0; k < dontEnums.length; ++k) {
|
||
if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) {
|
||
theKeys.push(dontEnums[k]);
|
||
}
|
||
}
|
||
}
|
||
return theKeys;
|
||
};
|
||
|
||
keysShim.shim = function shimObjectKeys() {
|
||
if (Object.keys) {
|
||
var keysWorksWithArguments = (function () {
|
||
// Safari 5.0 bug
|
||
return (Object.keys(arguments) || '').length === 2;
|
||
}(1, 2));
|
||
if (!keysWorksWithArguments) {
|
||
var originalKeys = Object.keys;
|
||
Object.keys = function keys(object) { // eslint-disable-line func-name-matching
|
||
if (isArgs(object)) {
|
||
return originalKeys(slice.call(object));
|
||
} else {
|
||
return originalKeys(object);
|
||
}
|
||
};
|
||
}
|
||
} else {
|
||
Object.keys = keysShim;
|
||
}
|
||
return Object.keys || keysShim;
|
||
};
|
||
|
||
module.exports = keysShim;
|
||
|
||
|
||
/***/ }),
|
||
/* 37 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var toStr = Object.prototype.toString;
|
||
|
||
module.exports = function isArguments(value) {
|
||
var str = toStr.call(value);
|
||
var isArgs = str === '[object Arguments]';
|
||
if (!isArgs) {
|
||
isArgs = str !== '[object Array]' &&
|
||
value !== null &&
|
||
typeof value === 'object' &&
|
||
typeof value.length === 'number' &&
|
||
value.length >= 0 &&
|
||
toStr.call(value.callee) === '[object Function]';
|
||
}
|
||
return isArgs;
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 38 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {var debug = __webpack_require__(8)('algoliasearch:src/hostIndexState.js');
|
||
var localStorageNamespace = 'algoliasearch-client-js';
|
||
|
||
var store;
|
||
var moduleStore = {
|
||
state: {},
|
||
set: function(key, data) {
|
||
this.state[key] = data;
|
||
return this.state[key];
|
||
},
|
||
get: function(key) {
|
||
return this.state[key] || null;
|
||
}
|
||
};
|
||
|
||
var localStorageStore = {
|
||
set: function(key, data) {
|
||
moduleStore.set(key, data); // always replicate localStorageStore to moduleStore in case of failure
|
||
|
||
try {
|
||
var namespace = JSON.parse(global.localStorage[localStorageNamespace]);
|
||
namespace[key] = data;
|
||
global.localStorage[localStorageNamespace] = JSON.stringify(namespace);
|
||
return namespace[key];
|
||
} catch (e) {
|
||
return localStorageFailure(key, e);
|
||
}
|
||
},
|
||
get: function(key) {
|
||
try {
|
||
return JSON.parse(global.localStorage[localStorageNamespace])[key] || null;
|
||
} catch (e) {
|
||
return localStorageFailure(key, e);
|
||
}
|
||
}
|
||
};
|
||
|
||
function localStorageFailure(key, e) {
|
||
debug('localStorage failed with', e);
|
||
cleanup();
|
||
store = moduleStore;
|
||
return store.get(key);
|
||
}
|
||
|
||
store = supportsLocalStorage() ? localStorageStore : moduleStore;
|
||
|
||
module.exports = {
|
||
get: getOrSet,
|
||
set: getOrSet,
|
||
supportsLocalStorage: supportsLocalStorage
|
||
};
|
||
|
||
function getOrSet(key, data) {
|
||
if (arguments.length === 1) {
|
||
return store.get(key);
|
||
}
|
||
|
||
return store.set(key, data);
|
||
}
|
||
|
||
function supportsLocalStorage() {
|
||
try {
|
||
if ('localStorage' in global &&
|
||
global.localStorage !== null) {
|
||
if (!global.localStorage[localStorageNamespace]) {
|
||
// actual creation of the namespace
|
||
global.localStorage.setItem(localStorageNamespace, JSON.stringify({}));
|
||
}
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
} catch (_) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// In case of any error on localStorage, we clean our own namespace, this should handle
|
||
// quota errors when a lot of keys + data are used
|
||
function cleanup() {
|
||
try {
|
||
global.localStorage.removeItem(localStorageNamespace);
|
||
} catch (_) {
|
||
// nothing to do
|
||
}
|
||
}
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
|
||
|
||
/***/ }),
|
||
/* 39 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
|
||
/**
|
||
* This is the common logic for both the Node.js and web browser
|
||
* implementations of `debug()`.
|
||
*
|
||
* Expose `debug()` as the module.
|
||
*/
|
||
|
||
exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;
|
||
exports.coerce = coerce;
|
||
exports.disable = disable;
|
||
exports.enable = enable;
|
||
exports.enabled = enabled;
|
||
exports.humanize = __webpack_require__(40);
|
||
|
||
/**
|
||
* The currently active debug mode names, and names to skip.
|
||
*/
|
||
|
||
exports.names = [];
|
||
exports.skips = [];
|
||
|
||
/**
|
||
* Map of special "%n" handling functions, for the debug "format" argument.
|
||
*
|
||
* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
|
||
*/
|
||
|
||
exports.formatters = {};
|
||
|
||
/**
|
||
* Previous log timestamp.
|
||
*/
|
||
|
||
var prevTime;
|
||
|
||
/**
|
||
* Select a color.
|
||
* @param {String} namespace
|
||
* @return {Number}
|
||
* @api private
|
||
*/
|
||
|
||
function selectColor(namespace) {
|
||
var hash = 0, i;
|
||
|
||
for (i in namespace) {
|
||
hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
|
||
hash |= 0; // Convert to 32bit integer
|
||
}
|
||
|
||
return exports.colors[Math.abs(hash) % exports.colors.length];
|
||
}
|
||
|
||
/**
|
||
* Create a debugger with the given `namespace`.
|
||
*
|
||
* @param {String} namespace
|
||
* @return {Function}
|
||
* @api public
|
||
*/
|
||
|
||
function createDebug(namespace) {
|
||
|
||
function debug() {
|
||
// disabled?
|
||
if (!debug.enabled) return;
|
||
|
||
var self = debug;
|
||
|
||
// set `diff` timestamp
|
||
var curr = +new Date();
|
||
var ms = curr - (prevTime || curr);
|
||
self.diff = ms;
|
||
self.prev = prevTime;
|
||
self.curr = curr;
|
||
prevTime = curr;
|
||
|
||
// turn the `arguments` into a proper Array
|
||
var args = new Array(arguments.length);
|
||
for (var i = 0; i < args.length; i++) {
|
||
args[i] = arguments[i];
|
||
}
|
||
|
||
args[0] = exports.coerce(args[0]);
|
||
|
||
if ('string' !== typeof args[0]) {
|
||
// anything else let's inspect with %O
|
||
args.unshift('%O');
|
||
}
|
||
|
||
// apply any `formatters` transformations
|
||
var index = 0;
|
||
args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
|
||
// if we encounter an escaped % then don't increase the array index
|
||
if (match === '%%') return match;
|
||
index++;
|
||
var formatter = exports.formatters[format];
|
||
if ('function' === typeof formatter) {
|
||
var val = args[index];
|
||
match = formatter.call(self, val);
|
||
|
||
// now we need to remove `args[index]` since it's inlined in the `format`
|
||
args.splice(index, 1);
|
||
index--;
|
||
}
|
||
return match;
|
||
});
|
||
|
||
// apply env-specific formatting (colors, etc.)
|
||
exports.formatArgs.call(self, args);
|
||
|
||
var logFn = debug.log || exports.log || console.log.bind(console);
|
||
logFn.apply(self, args);
|
||
}
|
||
|
||
debug.namespace = namespace;
|
||
debug.enabled = exports.enabled(namespace);
|
||
debug.useColors = exports.useColors();
|
||
debug.color = selectColor(namespace);
|
||
|
||
// env-specific initialization logic for debug instances
|
||
if ('function' === typeof exports.init) {
|
||
exports.init(debug);
|
||
}
|
||
|
||
return debug;
|
||
}
|
||
|
||
/**
|
||
* Enables a debug mode by namespaces. This can include modes
|
||
* separated by a colon and wildcards.
|
||
*
|
||
* @param {String} namespaces
|
||
* @api public
|
||
*/
|
||
|
||
function enable(namespaces) {
|
||
exports.save(namespaces);
|
||
|
||
exports.names = [];
|
||
exports.skips = [];
|
||
|
||
var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
|
||
var len = split.length;
|
||
|
||
for (var i = 0; i < len; i++) {
|
||
if (!split[i]) continue; // ignore empty strings
|
||
namespaces = split[i].replace(/\*/g, '.*?');
|
||
if (namespaces[0] === '-') {
|
||
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
|
||
} else {
|
||
exports.names.push(new RegExp('^' + namespaces + '$'));
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Disable debug output.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function disable() {
|
||
exports.enable('');
|
||
}
|
||
|
||
/**
|
||
* Returns true if the given mode name is enabled, false otherwise.
|
||
*
|
||
* @param {String} name
|
||
* @return {Boolean}
|
||
* @api public
|
||
*/
|
||
|
||
function enabled(name) {
|
||
var i, len;
|
||
for (i = 0, len = exports.skips.length; i < len; i++) {
|
||
if (exports.skips[i].test(name)) {
|
||
return false;
|
||
}
|
||
}
|
||
for (i = 0, len = exports.names.length; i < len; i++) {
|
||
if (exports.names[i].test(name)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Coerce `val`.
|
||
*
|
||
* @param {Mixed} val
|
||
* @return {Mixed}
|
||
* @api private
|
||
*/
|
||
|
||
function coerce(val) {
|
||
if (val instanceof Error) return val.stack || val.message;
|
||
return val;
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 40 */
|
||
/***/ (function(module, exports) {
|
||
|
||
/**
|
||
* Helpers.
|
||
*/
|
||
|
||
var s = 1000;
|
||
var m = s * 60;
|
||
var h = m * 60;
|
||
var d = h * 24;
|
||
var y = d * 365.25;
|
||
|
||
/**
|
||
* Parse or format the given `val`.
|
||
*
|
||
* Options:
|
||
*
|
||
* - `long` verbose formatting [false]
|
||
*
|
||
* @param {String|Number} val
|
||
* @param {Object} [options]
|
||
* @throws {Error} throw an error if val is not a non-empty string or a number
|
||
* @return {String|Number}
|
||
* @api public
|
||
*/
|
||
|
||
module.exports = function(val, options) {
|
||
options = options || {};
|
||
var type = typeof val;
|
||
if (type === 'string' && val.length > 0) {
|
||
return parse(val);
|
||
} else if (type === 'number' && isNaN(val) === false) {
|
||
return options.long ? fmtLong(val) : fmtShort(val);
|
||
}
|
||
throw new Error(
|
||
'val is not a non-empty string or a valid number. val=' +
|
||
JSON.stringify(val)
|
||
);
|
||
};
|
||
|
||
/**
|
||
* Parse the given `str` and return milliseconds.
|
||
*
|
||
* @param {String} str
|
||
* @return {Number}
|
||
* @api private
|
||
*/
|
||
|
||
function parse(str) {
|
||
str = String(str);
|
||
if (str.length > 100) {
|
||
return;
|
||
}
|
||
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(
|
||
str
|
||
);
|
||
if (!match) {
|
||
return;
|
||
}
|
||
var n = parseFloat(match[1]);
|
||
var type = (match[2] || 'ms').toLowerCase();
|
||
switch (type) {
|
||
case 'years':
|
||
case 'year':
|
||
case 'yrs':
|
||
case 'yr':
|
||
case 'y':
|
||
return n * y;
|
||
case 'days':
|
||
case 'day':
|
||
case 'd':
|
||
return n * d;
|
||
case 'hours':
|
||
case 'hour':
|
||
case 'hrs':
|
||
case 'hr':
|
||
case 'h':
|
||
return n * h;
|
||
case 'minutes':
|
||
case 'minute':
|
||
case 'mins':
|
||
case 'min':
|
||
case 'm':
|
||
return n * m;
|
||
case 'seconds':
|
||
case 'second':
|
||
case 'secs':
|
||
case 'sec':
|
||
case 's':
|
||
return n * s;
|
||
case 'milliseconds':
|
||
case 'millisecond':
|
||
case 'msecs':
|
||
case 'msec':
|
||
case 'ms':
|
||
return n;
|
||
default:
|
||
return undefined;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Short format for `ms`.
|
||
*
|
||
* @param {Number} ms
|
||
* @return {String}
|
||
* @api private
|
||
*/
|
||
|
||
function fmtShort(ms) {
|
||
if (ms >= d) {
|
||
return Math.round(ms / d) + 'd';
|
||
}
|
||
if (ms >= h) {
|
||
return Math.round(ms / h) + 'h';
|
||
}
|
||
if (ms >= m) {
|
||
return Math.round(ms / m) + 'm';
|
||
}
|
||
if (ms >= s) {
|
||
return Math.round(ms / s) + 's';
|
||
}
|
||
return ms + 'ms';
|
||
}
|
||
|
||
/**
|
||
* Long format for `ms`.
|
||
*
|
||
* @param {Number} ms
|
||
* @return {String}
|
||
* @api private
|
||
*/
|
||
|
||
function fmtLong(ms) {
|
||
return plural(ms, d, 'day') ||
|
||
plural(ms, h, 'hour') ||
|
||
plural(ms, m, 'minute') ||
|
||
plural(ms, s, 'second') ||
|
||
ms + ' ms';
|
||
}
|
||
|
||
/**
|
||
* Pluralization helper.
|
||
*/
|
||
|
||
function plural(ms, n, name) {
|
||
if (ms < n) {
|
||
return;
|
||
}
|
||
if (ms < n * 1.5) {
|
||
return Math.floor(ms / n) + ' ' + name;
|
||
}
|
||
return Math.ceil(ms / n) + ' ' + name + 's';
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 41 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var global = __webpack_require__(42);
|
||
var Promise = global.Promise || __webpack_require__(43).Promise;
|
||
|
||
// This is the standalone browser build entry point
|
||
// Browser implementation of the Algolia Search JavaScript client,
|
||
// using XMLHttpRequest, XDomainRequest and JSONP as fallback
|
||
module.exports = function createAlgoliasearch(AlgoliaSearch, uaSuffix) {
|
||
var inherits = __webpack_require__(12);
|
||
var errors = __webpack_require__(5);
|
||
var inlineHeaders = __webpack_require__(44);
|
||
var jsonpRequest = __webpack_require__(46);
|
||
var places = __webpack_require__(47);
|
||
uaSuffix = uaSuffix || '';
|
||
|
||
if (false) {
|
||
require('debug').enable('algoliasearch*');
|
||
}
|
||
|
||
function algoliasearch(applicationID, apiKey, opts) {
|
||
var cloneDeep = __webpack_require__(3);
|
||
|
||
opts = cloneDeep(opts || {});
|
||
|
||
opts._ua = opts._ua || algoliasearch.ua;
|
||
|
||
return new AlgoliaSearchBrowser(applicationID, apiKey, opts);
|
||
}
|
||
|
||
algoliasearch.version = __webpack_require__(48);
|
||
algoliasearch.ua = 'Algolia for vanilla JavaScript ' + uaSuffix + algoliasearch.version;
|
||
algoliasearch.initPlaces = places(algoliasearch);
|
||
|
||
// we expose into window no matter how we are used, this will allow
|
||
// us to easily debug any website running algolia
|
||
global.__algolia = {
|
||
debug: __webpack_require__(8),
|
||
algoliasearch: algoliasearch
|
||
};
|
||
|
||
var support = {
|
||
hasXMLHttpRequest: 'XMLHttpRequest' in global,
|
||
hasXDomainRequest: 'XDomainRequest' in global
|
||
};
|
||
|
||
if (support.hasXMLHttpRequest) {
|
||
support.cors = 'withCredentials' in new XMLHttpRequest();
|
||
}
|
||
|
||
function AlgoliaSearchBrowser() {
|
||
// call AlgoliaSearch constructor
|
||
AlgoliaSearch.apply(this, arguments);
|
||
}
|
||
|
||
inherits(AlgoliaSearchBrowser, AlgoliaSearch);
|
||
|
||
AlgoliaSearchBrowser.prototype._request = function request(url, opts) {
|
||
return new Promise(function wrapRequest(resolve, reject) {
|
||
// no cors or XDomainRequest, no request
|
||
if (!support.cors && !support.hasXDomainRequest) {
|
||
// very old browser, not supported
|
||
reject(new errors.Network('CORS not supported'));
|
||
return;
|
||
}
|
||
|
||
url = inlineHeaders(url, opts.headers);
|
||
|
||
var body = opts.body;
|
||
var req = support.cors ? new XMLHttpRequest() : new XDomainRequest();
|
||
var reqTimeout;
|
||
var timedOut;
|
||
var connected = false;
|
||
|
||
reqTimeout = setTimeout(onTimeout, opts.timeouts.connect);
|
||
// we set an empty onprogress listener
|
||
// so that XDomainRequest on IE9 is not aborted
|
||
// refs:
|
||
// - https://github.com/algolia/algoliasearch-client-js/issues/76
|
||
// - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment
|
||
req.onprogress = onProgress;
|
||
if ('onreadystatechange' in req) req.onreadystatechange = onReadyStateChange;
|
||
req.onload = onLoad;
|
||
req.onerror = onError;
|
||
|
||
// do not rely on default XHR async flag, as some analytics code like hotjar
|
||
// breaks it and set it to false by default
|
||
if (req instanceof XMLHttpRequest) {
|
||
req.open(opts.method, url, true);
|
||
|
||
// The Analytics API never accepts Auth headers as query string
|
||
// this option exists specifically for them.
|
||
if (opts.forceAuthHeaders) {
|
||
req.setRequestHeader(
|
||
'x-algolia-application-id',
|
||
opts.headers['x-algolia-application-id']
|
||
);
|
||
req.setRequestHeader(
|
||
'x-algolia-api-key',
|
||
opts.headers['x-algolia-api-key']
|
||
);
|
||
}
|
||
} else {
|
||
req.open(opts.method, url);
|
||
}
|
||
|
||
// headers are meant to be sent after open
|
||
if (support.cors) {
|
||
if (body) {
|
||
if (opts.method === 'POST') {
|
||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests
|
||
req.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
|
||
} else {
|
||
req.setRequestHeader('content-type', 'application/json');
|
||
}
|
||
}
|
||
req.setRequestHeader('accept', 'application/json');
|
||
}
|
||
|
||
if (body) {
|
||
req.send(body);
|
||
} else {
|
||
req.send();
|
||
}
|
||
|
||
// event object not received in IE8, at least
|
||
// but we do not use it, still important to note
|
||
function onLoad(/* event */) {
|
||
// When browser does not supports req.timeout, we can
|
||
// have both a load and timeout event, since handled by a dumb setTimeout
|
||
if (timedOut) {
|
||
return;
|
||
}
|
||
|
||
clearTimeout(reqTimeout);
|
||
|
||
var out;
|
||
|
||
try {
|
||
out = {
|
||
body: JSON.parse(req.responseText),
|
||
responseText: req.responseText,
|
||
statusCode: req.status,
|
||
// XDomainRequest does not have any response headers
|
||
headers: req.getAllResponseHeaders && req.getAllResponseHeaders() || {}
|
||
};
|
||
} catch (e) {
|
||
out = new errors.UnparsableJSON({
|
||
more: req.responseText
|
||
});
|
||
}
|
||
|
||
if (out instanceof errors.UnparsableJSON) {
|
||
reject(out);
|
||
} else {
|
||
resolve(out);
|
||
}
|
||
}
|
||
|
||
function onError(event) {
|
||
if (timedOut) {
|
||
return;
|
||
}
|
||
|
||
clearTimeout(reqTimeout);
|
||
|
||
// error event is trigerred both with XDR/XHR on:
|
||
// - DNS error
|
||
// - unallowed cross domain request
|
||
reject(
|
||
new errors.Network({
|
||
more: event
|
||
})
|
||
);
|
||
}
|
||
|
||
function onTimeout() {
|
||
timedOut = true;
|
||
req.abort();
|
||
|
||
reject(new errors.RequestTimeout());
|
||
}
|
||
|
||
function onConnect() {
|
||
connected = true;
|
||
clearTimeout(reqTimeout);
|
||
reqTimeout = setTimeout(onTimeout, opts.timeouts.complete);
|
||
}
|
||
|
||
function onProgress() {
|
||
if (!connected) onConnect();
|
||
}
|
||
|
||
function onReadyStateChange() {
|
||
if (!connected && req.readyState > 1) onConnect();
|
||
}
|
||
});
|
||
};
|
||
|
||
AlgoliaSearchBrowser.prototype._request.fallback = function requestFallback(url, opts) {
|
||
url = inlineHeaders(url, opts.headers);
|
||
|
||
return new Promise(function wrapJsonpRequest(resolve, reject) {
|
||
jsonpRequest(url, opts, function jsonpRequestDone(err, content) {
|
||
if (err) {
|
||
reject(err);
|
||
return;
|
||
}
|
||
|
||
resolve(content);
|
||
});
|
||
});
|
||
};
|
||
|
||
AlgoliaSearchBrowser.prototype._promise = {
|
||
reject: function rejectPromise(val) {
|
||
return Promise.reject(val);
|
||
},
|
||
resolve: function resolvePromise(val) {
|
||
return Promise.resolve(val);
|
||
},
|
||
delay: function delayPromise(ms) {
|
||
return new Promise(function resolveOnTimeout(resolve/* , reject*/) {
|
||
setTimeout(resolve, ms);
|
||
});
|
||
},
|
||
all: function all(promises) {
|
||
return Promise.all(promises);
|
||
}
|
||
};
|
||
|
||
return algoliasearch;
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 42 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {var win;
|
||
|
||
if (typeof window !== "undefined") {
|
||
win = window;
|
||
} else if (typeof global !== "undefined") {
|
||
win = global;
|
||
} else if (typeof self !== "undefined"){
|
||
win = self;
|
||
} else {
|
||
win = {};
|
||
}
|
||
|
||
module.exports = win;
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
|
||
|
||
/***/ }),
|
||
/* 43 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(process, global) {/*!
|
||
* @overview es6-promise - a tiny implementation of Promises/A+.
|
||
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
|
||
* @license Licensed under MIT license
|
||
* See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
|
||
* @version v4.2.4+314e4831
|
||
*/
|
||
|
||
(function (global, factory) {
|
||
true ? module.exports = factory() :
|
||
typeof define === 'function' && define.amd ? define(factory) :
|
||
(global.ES6Promise = factory());
|
||
}(this, (function () { 'use strict';
|
||
|
||
function objectOrFunction(x) {
|
||
var type = typeof x;
|
||
return x !== null && (type === 'object' || type === 'function');
|
||
}
|
||
|
||
function isFunction(x) {
|
||
return typeof x === 'function';
|
||
}
|
||
|
||
|
||
|
||
var _isArray = void 0;
|
||
if (Array.isArray) {
|
||
_isArray = Array.isArray;
|
||
} else {
|
||
_isArray = function (x) {
|
||
return Object.prototype.toString.call(x) === '[object Array]';
|
||
};
|
||
}
|
||
|
||
var isArray = _isArray;
|
||
|
||
var len = 0;
|
||
var vertxNext = void 0;
|
||
var customSchedulerFn = void 0;
|
||
|
||
var asap = function asap(callback, arg) {
|
||
queue[len] = callback;
|
||
queue[len + 1] = arg;
|
||
len += 2;
|
||
if (len === 2) {
|
||
// If len is 2, that means that we need to schedule an async flush.
|
||
// If additional callbacks are queued before the queue is flushed, they
|
||
// will be processed by this flush that we are scheduling.
|
||
if (customSchedulerFn) {
|
||
customSchedulerFn(flush);
|
||
} else {
|
||
scheduleFlush();
|
||
}
|
||
}
|
||
};
|
||
|
||
function setScheduler(scheduleFn) {
|
||
customSchedulerFn = scheduleFn;
|
||
}
|
||
|
||
function setAsap(asapFn) {
|
||
asap = asapFn;
|
||
}
|
||
|
||
var browserWindow = typeof window !== 'undefined' ? window : undefined;
|
||
var browserGlobal = browserWindow || {};
|
||
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
|
||
var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
|
||
|
||
// test for web worker but not in IE10
|
||
var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
|
||
|
||
// node
|
||
function useNextTick() {
|
||
// node version 0.10.x displays a deprecation warning when nextTick is used recursively
|
||
// see https://github.com/cujojs/when/issues/410 for details
|
||
return function () {
|
||
return process.nextTick(flush);
|
||
};
|
||
}
|
||
|
||
// vertx
|
||
function useVertxTimer() {
|
||
if (typeof vertxNext !== 'undefined') {
|
||
return function () {
|
||
vertxNext(flush);
|
||
};
|
||
}
|
||
|
||
return useSetTimeout();
|
||
}
|
||
|
||
function useMutationObserver() {
|
||
var iterations = 0;
|
||
var observer = new BrowserMutationObserver(flush);
|
||
var node = document.createTextNode('');
|
||
observer.observe(node, { characterData: true });
|
||
|
||
return function () {
|
||
node.data = iterations = ++iterations % 2;
|
||
};
|
||
}
|
||
|
||
// web worker
|
||
function useMessageChannel() {
|
||
var channel = new MessageChannel();
|
||
channel.port1.onmessage = flush;
|
||
return function () {
|
||
return channel.port2.postMessage(0);
|
||
};
|
||
}
|
||
|
||
function useSetTimeout() {
|
||
// Store setTimeout reference so es6-promise will be unaffected by
|
||
// other code modifying setTimeout (like sinon.useFakeTimers())
|
||
var globalSetTimeout = setTimeout;
|
||
return function () {
|
||
return globalSetTimeout(flush, 1);
|
||
};
|
||
}
|
||
|
||
var queue = new Array(1000);
|
||
function flush() {
|
||
for (var i = 0; i < len; i += 2) {
|
||
var callback = queue[i];
|
||
var arg = queue[i + 1];
|
||
|
||
callback(arg);
|
||
|
||
queue[i] = undefined;
|
||
queue[i + 1] = undefined;
|
||
}
|
||
|
||
len = 0;
|
||
}
|
||
|
||
function attemptVertx() {
|
||
try {
|
||
var vertx = Function('return this')().require('vertx');
|
||
vertxNext = vertx.runOnLoop || vertx.runOnContext;
|
||
return useVertxTimer();
|
||
} catch (e) {
|
||
return useSetTimeout();
|
||
}
|
||
}
|
||
|
||
var scheduleFlush = void 0;
|
||
// Decide what async method to use to triggering processing of queued callbacks:
|
||
if (isNode) {
|
||
scheduleFlush = useNextTick();
|
||
} else if (BrowserMutationObserver) {
|
||
scheduleFlush = useMutationObserver();
|
||
} else if (isWorker) {
|
||
scheduleFlush = useMessageChannel();
|
||
} else if (browserWindow === undefined && "function" === 'function') {
|
||
scheduleFlush = attemptVertx();
|
||
} else {
|
||
scheduleFlush = useSetTimeout();
|
||
}
|
||
|
||
function then(onFulfillment, onRejection) {
|
||
var parent = this;
|
||
|
||
var child = new this.constructor(noop);
|
||
|
||
if (child[PROMISE_ID] === undefined) {
|
||
makePromise(child);
|
||
}
|
||
|
||
var _state = parent._state;
|
||
|
||
|
||
if (_state) {
|
||
var callback = arguments[_state - 1];
|
||
asap(function () {
|
||
return invokeCallback(_state, child, callback, parent._result);
|
||
});
|
||
} else {
|
||
subscribe(parent, child, onFulfillment, onRejection);
|
||
}
|
||
|
||
return child;
|
||
}
|
||
|
||
/**
|
||
`Promise.resolve` returns a promise that will become resolved with the
|
||
passed `value`. It is shorthand for the following:
|
||
|
||
```javascript
|
||
let promise = new Promise(function(resolve, reject){
|
||
resolve(1);
|
||
});
|
||
|
||
promise.then(function(value){
|
||
// value === 1
|
||
});
|
||
```
|
||
|
||
Instead of writing the above, your code now simply becomes the following:
|
||
|
||
```javascript
|
||
let promise = Promise.resolve(1);
|
||
|
||
promise.then(function(value){
|
||
// value === 1
|
||
});
|
||
```
|
||
|
||
@method resolve
|
||
@static
|
||
@param {Any} value value that the returned promise will be resolved with
|
||
Useful for tooling.
|
||
@return {Promise} a promise that will become fulfilled with the given
|
||
`value`
|
||
*/
|
||
function resolve$1(object) {
|
||
/*jshint validthis:true */
|
||
var Constructor = this;
|
||
|
||
if (object && typeof object === 'object' && object.constructor === Constructor) {
|
||
return object;
|
||
}
|
||
|
||
var promise = new Constructor(noop);
|
||
resolve(promise, object);
|
||
return promise;
|
||
}
|
||
|
||
var PROMISE_ID = Math.random().toString(36).substring(2);
|
||
|
||
function noop() {}
|
||
|
||
var PENDING = void 0;
|
||
var FULFILLED = 1;
|
||
var REJECTED = 2;
|
||
|
||
var TRY_CATCH_ERROR = { error: null };
|
||
|
||
function selfFulfillment() {
|
||
return new TypeError("You cannot resolve a promise with itself");
|
||
}
|
||
|
||
function cannotReturnOwn() {
|
||
return new TypeError('A promises callback cannot return that same promise.');
|
||
}
|
||
|
||
function getThen(promise) {
|
||
try {
|
||
return promise.then;
|
||
} catch (error) {
|
||
TRY_CATCH_ERROR.error = error;
|
||
return TRY_CATCH_ERROR;
|
||
}
|
||
}
|
||
|
||
function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
|
||
try {
|
||
then$$1.call(value, fulfillmentHandler, rejectionHandler);
|
||
} catch (e) {
|
||
return e;
|
||
}
|
||
}
|
||
|
||
function handleForeignThenable(promise, thenable, then$$1) {
|
||
asap(function (promise) {
|
||
var sealed = false;
|
||
var error = tryThen(then$$1, thenable, function (value) {
|
||
if (sealed) {
|
||
return;
|
||
}
|
||
sealed = true;
|
||
if (thenable !== value) {
|
||
resolve(promise, value);
|
||
} else {
|
||
fulfill(promise, value);
|
||
}
|
||
}, function (reason) {
|
||
if (sealed) {
|
||
return;
|
||
}
|
||
sealed = true;
|
||
|
||
reject(promise, reason);
|
||
}, 'Settle: ' + (promise._label || ' unknown promise'));
|
||
|
||
if (!sealed && error) {
|
||
sealed = true;
|
||
reject(promise, error);
|
||
}
|
||
}, promise);
|
||
}
|
||
|
||
function handleOwnThenable(promise, thenable) {
|
||
if (thenable._state === FULFILLED) {
|
||
fulfill(promise, thenable._result);
|
||
} else if (thenable._state === REJECTED) {
|
||
reject(promise, thenable._result);
|
||
} else {
|
||
subscribe(thenable, undefined, function (value) {
|
||
return resolve(promise, value);
|
||
}, function (reason) {
|
||
return reject(promise, reason);
|
||
});
|
||
}
|
||
}
|
||
|
||
function handleMaybeThenable(promise, maybeThenable, then$$1) {
|
||
if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) {
|
||
handleOwnThenable(promise, maybeThenable);
|
||
} else {
|
||
if (then$$1 === TRY_CATCH_ERROR) {
|
||
reject(promise, TRY_CATCH_ERROR.error);
|
||
TRY_CATCH_ERROR.error = null;
|
||
} else if (then$$1 === undefined) {
|
||
fulfill(promise, maybeThenable);
|
||
} else if (isFunction(then$$1)) {
|
||
handleForeignThenable(promise, maybeThenable, then$$1);
|
||
} else {
|
||
fulfill(promise, maybeThenable);
|
||
}
|
||
}
|
||
}
|
||
|
||
function resolve(promise, value) {
|
||
if (promise === value) {
|
||
reject(promise, selfFulfillment());
|
||
} else if (objectOrFunction(value)) {
|
||
handleMaybeThenable(promise, value, getThen(value));
|
||
} else {
|
||
fulfill(promise, value);
|
||
}
|
||
}
|
||
|
||
function publishRejection(promise) {
|
||
if (promise._onerror) {
|
||
promise._onerror(promise._result);
|
||
}
|
||
|
||
publish(promise);
|
||
}
|
||
|
||
function fulfill(promise, value) {
|
||
if (promise._state !== PENDING) {
|
||
return;
|
||
}
|
||
|
||
promise._result = value;
|
||
promise._state = FULFILLED;
|
||
|
||
if (promise._subscribers.length !== 0) {
|
||
asap(publish, promise);
|
||
}
|
||
}
|
||
|
||
function reject(promise, reason) {
|
||
if (promise._state !== PENDING) {
|
||
return;
|
||
}
|
||
promise._state = REJECTED;
|
||
promise._result = reason;
|
||
|
||
asap(publishRejection, promise);
|
||
}
|
||
|
||
function subscribe(parent, child, onFulfillment, onRejection) {
|
||
var _subscribers = parent._subscribers;
|
||
var length = _subscribers.length;
|
||
|
||
|
||
parent._onerror = null;
|
||
|
||
_subscribers[length] = child;
|
||
_subscribers[length + FULFILLED] = onFulfillment;
|
||
_subscribers[length + REJECTED] = onRejection;
|
||
|
||
if (length === 0 && parent._state) {
|
||
asap(publish, parent);
|
||
}
|
||
}
|
||
|
||
function publish(promise) {
|
||
var subscribers = promise._subscribers;
|
||
var settled = promise._state;
|
||
|
||
if (subscribers.length === 0) {
|
||
return;
|
||
}
|
||
|
||
var child = void 0,
|
||
callback = void 0,
|
||
detail = promise._result;
|
||
|
||
for (var i = 0; i < subscribers.length; i += 3) {
|
||
child = subscribers[i];
|
||
callback = subscribers[i + settled];
|
||
|
||
if (child) {
|
||
invokeCallback(settled, child, callback, detail);
|
||
} else {
|
||
callback(detail);
|
||
}
|
||
}
|
||
|
||
promise._subscribers.length = 0;
|
||
}
|
||
|
||
function tryCatch(callback, detail) {
|
||
try {
|
||
return callback(detail);
|
||
} catch (e) {
|
||
TRY_CATCH_ERROR.error = e;
|
||
return TRY_CATCH_ERROR;
|
||
}
|
||
}
|
||
|
||
function invokeCallback(settled, promise, callback, detail) {
|
||
var hasCallback = isFunction(callback),
|
||
value = void 0,
|
||
error = void 0,
|
||
succeeded = void 0,
|
||
failed = void 0;
|
||
|
||
if (hasCallback) {
|
||
value = tryCatch(callback, detail);
|
||
|
||
if (value === TRY_CATCH_ERROR) {
|
||
failed = true;
|
||
error = value.error;
|
||
value.error = null;
|
||
} else {
|
||
succeeded = true;
|
||
}
|
||
|
||
if (promise === value) {
|
||
reject(promise, cannotReturnOwn());
|
||
return;
|
||
}
|
||
} else {
|
||
value = detail;
|
||
succeeded = true;
|
||
}
|
||
|
||
if (promise._state !== PENDING) {
|
||
// noop
|
||
} else if (hasCallback && succeeded) {
|
||
resolve(promise, value);
|
||
} else if (failed) {
|
||
reject(promise, error);
|
||
} else if (settled === FULFILLED) {
|
||
fulfill(promise, value);
|
||
} else if (settled === REJECTED) {
|
||
reject(promise, value);
|
||
}
|
||
}
|
||
|
||
function initializePromise(promise, resolver) {
|
||
try {
|
||
resolver(function resolvePromise(value) {
|
||
resolve(promise, value);
|
||
}, function rejectPromise(reason) {
|
||
reject(promise, reason);
|
||
});
|
||
} catch (e) {
|
||
reject(promise, e);
|
||
}
|
||
}
|
||
|
||
var id = 0;
|
||
function nextId() {
|
||
return id++;
|
||
}
|
||
|
||
function makePromise(promise) {
|
||
promise[PROMISE_ID] = id++;
|
||
promise._state = undefined;
|
||
promise._result = undefined;
|
||
promise._subscribers = [];
|
||
}
|
||
|
||
function validationError() {
|
||
return new Error('Array Methods must be provided an Array');
|
||
}
|
||
|
||
var Enumerator = function () {
|
||
function Enumerator(Constructor, input) {
|
||
this._instanceConstructor = Constructor;
|
||
this.promise = new Constructor(noop);
|
||
|
||
if (!this.promise[PROMISE_ID]) {
|
||
makePromise(this.promise);
|
||
}
|
||
|
||
if (isArray(input)) {
|
||
this.length = input.length;
|
||
this._remaining = input.length;
|
||
|
||
this._result = new Array(this.length);
|
||
|
||
if (this.length === 0) {
|
||
fulfill(this.promise, this._result);
|
||
} else {
|
||
this.length = this.length || 0;
|
||
this._enumerate(input);
|
||
if (this._remaining === 0) {
|
||
fulfill(this.promise, this._result);
|
||
}
|
||
}
|
||
} else {
|
||
reject(this.promise, validationError());
|
||
}
|
||
}
|
||
|
||
Enumerator.prototype._enumerate = function _enumerate(input) {
|
||
for (var i = 0; this._state === PENDING && i < input.length; i++) {
|
||
this._eachEntry(input[i], i);
|
||
}
|
||
};
|
||
|
||
Enumerator.prototype._eachEntry = function _eachEntry(entry, i) {
|
||
var c = this._instanceConstructor;
|
||
var resolve$$1 = c.resolve;
|
||
|
||
|
||
if (resolve$$1 === resolve$1) {
|
||
var _then = getThen(entry);
|
||
|
||
if (_then === then && entry._state !== PENDING) {
|
||
this._settledAt(entry._state, i, entry._result);
|
||
} else if (typeof _then !== 'function') {
|
||
this._remaining--;
|
||
this._result[i] = entry;
|
||
} else if (c === Promise$1) {
|
||
var promise = new c(noop);
|
||
handleMaybeThenable(promise, entry, _then);
|
||
this._willSettleAt(promise, i);
|
||
} else {
|
||
this._willSettleAt(new c(function (resolve$$1) {
|
||
return resolve$$1(entry);
|
||
}), i);
|
||
}
|
||
} else {
|
||
this._willSettleAt(resolve$$1(entry), i);
|
||
}
|
||
};
|
||
|
||
Enumerator.prototype._settledAt = function _settledAt(state, i, value) {
|
||
var promise = this.promise;
|
||
|
||
|
||
if (promise._state === PENDING) {
|
||
this._remaining--;
|
||
|
||
if (state === REJECTED) {
|
||
reject(promise, value);
|
||
} else {
|
||
this._result[i] = value;
|
||
}
|
||
}
|
||
|
||
if (this._remaining === 0) {
|
||
fulfill(promise, this._result);
|
||
}
|
||
};
|
||
|
||
Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i) {
|
||
var enumerator = this;
|
||
|
||
subscribe(promise, undefined, function (value) {
|
||
return enumerator._settledAt(FULFILLED, i, value);
|
||
}, function (reason) {
|
||
return enumerator._settledAt(REJECTED, i, reason);
|
||
});
|
||
};
|
||
|
||
return Enumerator;
|
||
}();
|
||
|
||
/**
|
||
`Promise.all` accepts an array of promises, and returns a new promise which
|
||
is fulfilled with an array of fulfillment values for the passed promises, or
|
||
rejected with the reason of the first passed promise to be rejected. It casts all
|
||
elements of the passed iterable to promises as it runs this algorithm.
|
||
|
||
Example:
|
||
|
||
```javascript
|
||
let promise1 = resolve(1);
|
||
let promise2 = resolve(2);
|
||
let promise3 = resolve(3);
|
||
let promises = [ promise1, promise2, promise3 ];
|
||
|
||
Promise.all(promises).then(function(array){
|
||
// The array here would be [ 1, 2, 3 ];
|
||
});
|
||
```
|
||
|
||
If any of the `promises` given to `all` are rejected, the first promise
|
||
that is rejected will be given as an argument to the returned promises's
|
||
rejection handler. For example:
|
||
|
||
Example:
|
||
|
||
```javascript
|
||
let promise1 = resolve(1);
|
||
let promise2 = reject(new Error("2"));
|
||
let promise3 = reject(new Error("3"));
|
||
let promises = [ promise1, promise2, promise3 ];
|
||
|
||
Promise.all(promises).then(function(array){
|
||
// Code here never runs because there are rejected promises!
|
||
}, function(error) {
|
||
// error.message === "2"
|
||
});
|
||
```
|
||
|
||
@method all
|
||
@static
|
||
@param {Array} entries array of promises
|
||
@param {String} label optional string for labeling the promise.
|
||
Useful for tooling.
|
||
@return {Promise} promise that is fulfilled when all `promises` have been
|
||
fulfilled, or rejected if any of them become rejected.
|
||
@static
|
||
*/
|
||
function all(entries) {
|
||
return new Enumerator(this, entries).promise;
|
||
}
|
||
|
||
/**
|
||
`Promise.race` returns a new promise which is settled in the same way as the
|
||
first passed promise to settle.
|
||
|
||
Example:
|
||
|
||
```javascript
|
||
let promise1 = new Promise(function(resolve, reject){
|
||
setTimeout(function(){
|
||
resolve('promise 1');
|
||
}, 200);
|
||
});
|
||
|
||
let promise2 = new Promise(function(resolve, reject){
|
||
setTimeout(function(){
|
||
resolve('promise 2');
|
||
}, 100);
|
||
});
|
||
|
||
Promise.race([promise1, promise2]).then(function(result){
|
||
// result === 'promise 2' because it was resolved before promise1
|
||
// was resolved.
|
||
});
|
||
```
|
||
|
||
`Promise.race` is deterministic in that only the state of the first
|
||
settled promise matters. For example, even if other promises given to the
|
||
`promises` array argument are resolved, but the first settled promise has
|
||
become rejected before the other promises became fulfilled, the returned
|
||
promise will become rejected:
|
||
|
||
```javascript
|
||
let promise1 = new Promise(function(resolve, reject){
|
||
setTimeout(function(){
|
||
resolve('promise 1');
|
||
}, 200);
|
||
});
|
||
|
||
let promise2 = new Promise(function(resolve, reject){
|
||
setTimeout(function(){
|
||
reject(new Error('promise 2'));
|
||
}, 100);
|
||
});
|
||
|
||
Promise.race([promise1, promise2]).then(function(result){
|
||
// Code here never runs
|
||
}, function(reason){
|
||
// reason.message === 'promise 2' because promise 2 became rejected before
|
||
// promise 1 became fulfilled
|
||
});
|
||
```
|
||
|
||
An example real-world use case is implementing timeouts:
|
||
|
||
```javascript
|
||
Promise.race([ajax('foo.json'), timeout(5000)])
|
||
```
|
||
|
||
@method race
|
||
@static
|
||
@param {Array} promises array of promises to observe
|
||
Useful for tooling.
|
||
@return {Promise} a promise which settles in the same way as the first passed
|
||
promise to settle.
|
||
*/
|
||
function race(entries) {
|
||
/*jshint validthis:true */
|
||
var Constructor = this;
|
||
|
||
if (!isArray(entries)) {
|
||
return new Constructor(function (_, reject) {
|
||
return reject(new TypeError('You must pass an array to race.'));
|
||
});
|
||
} else {
|
||
return new Constructor(function (resolve, reject) {
|
||
var length = entries.length;
|
||
for (var i = 0; i < length; i++) {
|
||
Constructor.resolve(entries[i]).then(resolve, reject);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
`Promise.reject` returns a promise rejected with the passed `reason`.
|
||
It is shorthand for the following:
|
||
|
||
```javascript
|
||
let promise = new Promise(function(resolve, reject){
|
||
reject(new Error('WHOOPS'));
|
||
});
|
||
|
||
promise.then(function(value){
|
||
// Code here doesn't run because the promise is rejected!
|
||
}, function(reason){
|
||
// reason.message === 'WHOOPS'
|
||
});
|
||
```
|
||
|
||
Instead of writing the above, your code now simply becomes the following:
|
||
|
||
```javascript
|
||
let promise = Promise.reject(new Error('WHOOPS'));
|
||
|
||
promise.then(function(value){
|
||
// Code here doesn't run because the promise is rejected!
|
||
}, function(reason){
|
||
// reason.message === 'WHOOPS'
|
||
});
|
||
```
|
||
|
||
@method reject
|
||
@static
|
||
@param {Any} reason value that the returned promise will be rejected with.
|
||
Useful for tooling.
|
||
@return {Promise} a promise rejected with the given `reason`.
|
||
*/
|
||
function reject$1(reason) {
|
||
/*jshint validthis:true */
|
||
var Constructor = this;
|
||
var promise = new Constructor(noop);
|
||
reject(promise, reason);
|
||
return promise;
|
||
}
|
||
|
||
function needsResolver() {
|
||
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
|
||
}
|
||
|
||
function needsNew() {
|
||
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
|
||
}
|
||
|
||
/**
|
||
Promise objects represent the eventual result of an asynchronous operation. The
|
||
primary way of interacting with a promise is through its `then` method, which
|
||
registers callbacks to receive either a promise's eventual value or the reason
|
||
why the promise cannot be fulfilled.
|
||
|
||
Terminology
|
||
-----------
|
||
|
||
- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
|
||
- `thenable` is an object or function that defines a `then` method.
|
||
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
|
||
- `exception` is a value that is thrown using the throw statement.
|
||
- `reason` is a value that indicates why a promise was rejected.
|
||
- `settled` the final resting state of a promise, fulfilled or rejected.
|
||
|
||
A promise can be in one of three states: pending, fulfilled, or rejected.
|
||
|
||
Promises that are fulfilled have a fulfillment value and are in the fulfilled
|
||
state. Promises that are rejected have a rejection reason and are in the
|
||
rejected state. A fulfillment value is never a thenable.
|
||
|
||
Promises can also be said to *resolve* a value. If this value is also a
|
||
promise, then the original promise's settled state will match the value's
|
||
settled state. So a promise that *resolves* a promise that rejects will
|
||
itself reject, and a promise that *resolves* a promise that fulfills will
|
||
itself fulfill.
|
||
|
||
|
||
Basic Usage:
|
||
------------
|
||
|
||
```js
|
||
let promise = new Promise(function(resolve, reject) {
|
||
// on success
|
||
resolve(value);
|
||
|
||
// on failure
|
||
reject(reason);
|
||
});
|
||
|
||
promise.then(function(value) {
|
||
// on fulfillment
|
||
}, function(reason) {
|
||
// on rejection
|
||
});
|
||
```
|
||
|
||
Advanced Usage:
|
||
---------------
|
||
|
||
Promises shine when abstracting away asynchronous interactions such as
|
||
`XMLHttpRequest`s.
|
||
|
||
```js
|
||
function getJSON(url) {
|
||
return new Promise(function(resolve, reject){
|
||
let xhr = new XMLHttpRequest();
|
||
|
||
xhr.open('GET', url);
|
||
xhr.onreadystatechange = handler;
|
||
xhr.responseType = 'json';
|
||
xhr.setRequestHeader('Accept', 'application/json');
|
||
xhr.send();
|
||
|
||
function handler() {
|
||
if (this.readyState === this.DONE) {
|
||
if (this.status === 200) {
|
||
resolve(this.response);
|
||
} else {
|
||
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
|
||
}
|
||
}
|
||
};
|
||
});
|
||
}
|
||
|
||
getJSON('/posts.json').then(function(json) {
|
||
// on fulfillment
|
||
}, function(reason) {
|
||
// on rejection
|
||
});
|
||
```
|
||
|
||
Unlike callbacks, promises are great composable primitives.
|
||
|
||
```js
|
||
Promise.all([
|
||
getJSON('/posts'),
|
||
getJSON('/comments')
|
||
]).then(function(values){
|
||
values[0] // => postsJSON
|
||
values[1] // => commentsJSON
|
||
|
||
return values;
|
||
});
|
||
```
|
||
|
||
@class Promise
|
||
@param {Function} resolver
|
||
Useful for tooling.
|
||
@constructor
|
||
*/
|
||
|
||
var Promise$1 = function () {
|
||
function Promise(resolver) {
|
||
this[PROMISE_ID] = nextId();
|
||
this._result = this._state = undefined;
|
||
this._subscribers = [];
|
||
|
||
if (noop !== resolver) {
|
||
typeof resolver !== 'function' && needsResolver();
|
||
this instanceof Promise ? initializePromise(this, resolver) : needsNew();
|
||
}
|
||
}
|
||
|
||
/**
|
||
The primary way of interacting with a promise is through its `then` method,
|
||
which registers callbacks to receive either a promise's eventual value or the
|
||
reason why the promise cannot be fulfilled.
|
||
```js
|
||
findUser().then(function(user){
|
||
// user is available
|
||
}, function(reason){
|
||
// user is unavailable, and you are given the reason why
|
||
});
|
||
```
|
||
Chaining
|
||
--------
|
||
The return value of `then` is itself a promise. This second, 'downstream'
|
||
promise is resolved with the return value of the first promise's fulfillment
|
||
or rejection handler, or rejected if the handler throws an exception.
|
||
```js
|
||
findUser().then(function (user) {
|
||
return user.name;
|
||
}, function (reason) {
|
||
return 'default name';
|
||
}).then(function (userName) {
|
||
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
|
||
// will be `'default name'`
|
||
});
|
||
findUser().then(function (user) {
|
||
throw new Error('Found user, but still unhappy');
|
||
}, function (reason) {
|
||
throw new Error('`findUser` rejected and we're unhappy');
|
||
}).then(function (value) {
|
||
// never reached
|
||
}, function (reason) {
|
||
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
|
||
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
|
||
});
|
||
```
|
||
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
|
||
```js
|
||
findUser().then(function (user) {
|
||
throw new PedagogicalException('Upstream error');
|
||
}).then(function (value) {
|
||
// never reached
|
||
}).then(function (value) {
|
||
// never reached
|
||
}, function (reason) {
|
||
// The `PedgagocialException` is propagated all the way down to here
|
||
});
|
||
```
|
||
Assimilation
|
||
------------
|
||
Sometimes the value you want to propagate to a downstream promise can only be
|
||
retrieved asynchronously. This can be achieved by returning a promise in the
|
||
fulfillment or rejection handler. The downstream promise will then be pending
|
||
until the returned promise is settled. This is called *assimilation*.
|
||
```js
|
||
findUser().then(function (user) {
|
||
return findCommentsByAuthor(user);
|
||
}).then(function (comments) {
|
||
// The user's comments are now available
|
||
});
|
||
```
|
||
If the assimliated promise rejects, then the downstream promise will also reject.
|
||
```js
|
||
findUser().then(function (user) {
|
||
return findCommentsByAuthor(user);
|
||
}).then(function (comments) {
|
||
// If `findCommentsByAuthor` fulfills, we'll have the value here
|
||
}, function (reason) {
|
||
// If `findCommentsByAuthor` rejects, we'll have the reason here
|
||
});
|
||
```
|
||
Simple Example
|
||
--------------
|
||
Synchronous Example
|
||
```javascript
|
||
let result;
|
||
try {
|
||
result = findResult();
|
||
// success
|
||
} catch(reason) {
|
||
// failure
|
||
}
|
||
```
|
||
Errback Example
|
||
```js
|
||
findResult(function(result, err){
|
||
if (err) {
|
||
// failure
|
||
} else {
|
||
// success
|
||
}
|
||
});
|
||
```
|
||
Promise Example;
|
||
```javascript
|
||
findResult().then(function(result){
|
||
// success
|
||
}, function(reason){
|
||
// failure
|
||
});
|
||
```
|
||
Advanced Example
|
||
--------------
|
||
Synchronous Example
|
||
```javascript
|
||
let author, books;
|
||
try {
|
||
author = findAuthor();
|
||
books = findBooksByAuthor(author);
|
||
// success
|
||
} catch(reason) {
|
||
// failure
|
||
}
|
||
```
|
||
Errback Example
|
||
```js
|
||
function foundBooks(books) {
|
||
}
|
||
function failure(reason) {
|
||
}
|
||
findAuthor(function(author, err){
|
||
if (err) {
|
||
failure(err);
|
||
// failure
|
||
} else {
|
||
try {
|
||
findBoooksByAuthor(author, function(books, err) {
|
||
if (err) {
|
||
failure(err);
|
||
} else {
|
||
try {
|
||
foundBooks(books);
|
||
} catch(reason) {
|
||
failure(reason);
|
||
}
|
||
}
|
||
});
|
||
} catch(error) {
|
||
failure(err);
|
||
}
|
||
// success
|
||
}
|
||
});
|
||
```
|
||
Promise Example;
|
||
```javascript
|
||
findAuthor().
|
||
then(findBooksByAuthor).
|
||
then(function(books){
|
||
// found books
|
||
}).catch(function(reason){
|
||
// something went wrong
|
||
});
|
||
```
|
||
@method then
|
||
@param {Function} onFulfilled
|
||
@param {Function} onRejected
|
||
Useful for tooling.
|
||
@return {Promise}
|
||
*/
|
||
|
||
/**
|
||
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
|
||
as the catch block of a try/catch statement.
|
||
```js
|
||
function findAuthor(){
|
||
throw new Error('couldn't find that author');
|
||
}
|
||
// synchronous
|
||
try {
|
||
findAuthor();
|
||
} catch(reason) {
|
||
// something went wrong
|
||
}
|
||
// async with promises
|
||
findAuthor().catch(function(reason){
|
||
// something went wrong
|
||
});
|
||
```
|
||
@method catch
|
||
@param {Function} onRejection
|
||
Useful for tooling.
|
||
@return {Promise}
|
||
*/
|
||
|
||
|
||
Promise.prototype.catch = function _catch(onRejection) {
|
||
return this.then(null, onRejection);
|
||
};
|
||
|
||
/**
|
||
`finally` will be invoked regardless of the promise's fate just as native
|
||
try/catch/finally behaves
|
||
|
||
Synchronous example:
|
||
|
||
```js
|
||
findAuthor() {
|
||
if (Math.random() > 0.5) {
|
||
throw new Error();
|
||
}
|
||
return new Author();
|
||
}
|
||
|
||
try {
|
||
return findAuthor(); // succeed or fail
|
||
} catch(error) {
|
||
return findOtherAuther();
|
||
} finally {
|
||
// always runs
|
||
// doesn't affect the return value
|
||
}
|
||
```
|
||
|
||
Asynchronous example:
|
||
|
||
```js
|
||
findAuthor().catch(function(reason){
|
||
return findOtherAuther();
|
||
}).finally(function(){
|
||
// author was either found, or not
|
||
});
|
||
```
|
||
|
||
@method finally
|
||
@param {Function} callback
|
||
@return {Promise}
|
||
*/
|
||
|
||
|
||
Promise.prototype.finally = function _finally(callback) {
|
||
var promise = this;
|
||
var constructor = promise.constructor;
|
||
|
||
return promise.then(function (value) {
|
||
return constructor.resolve(callback()).then(function () {
|
||
return value;
|
||
});
|
||
}, function (reason) {
|
||
return constructor.resolve(callback()).then(function () {
|
||
throw reason;
|
||
});
|
||
});
|
||
};
|
||
|
||
return Promise;
|
||
}();
|
||
|
||
Promise$1.prototype.then = then;
|
||
Promise$1.all = all;
|
||
Promise$1.race = race;
|
||
Promise$1.resolve = resolve$1;
|
||
Promise$1.reject = reject$1;
|
||
Promise$1._setScheduler = setScheduler;
|
||
Promise$1._setAsap = setAsap;
|
||
Promise$1._asap = asap;
|
||
|
||
/*global self*/
|
||
function polyfill() {
|
||
var local = void 0;
|
||
|
||
if (typeof global !== 'undefined') {
|
||
local = global;
|
||
} else if (typeof self !== 'undefined') {
|
||
local = self;
|
||
} else {
|
||
try {
|
||
local = Function('return this')();
|
||
} catch (e) {
|
||
throw new Error('polyfill failed because global object is unavailable in this environment');
|
||
}
|
||
}
|
||
|
||
var P = local.Promise;
|
||
|
||
if (P) {
|
||
var promiseToString = null;
|
||
try {
|
||
promiseToString = Object.prototype.toString.call(P.resolve());
|
||
} catch (e) {
|
||
// silently ignored
|
||
}
|
||
|
||
if (promiseToString === '[object Promise]' && !P.cast) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
local.Promise = Promise$1;
|
||
}
|
||
|
||
// Strange compat..
|
||
Promise$1.polyfill = polyfill;
|
||
Promise$1.Promise = Promise$1;
|
||
|
||
return Promise$1;
|
||
|
||
})));
|
||
|
||
|
||
|
||
//# sourceMappingURL=es6-promise.map
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9), __webpack_require__(4)))
|
||
|
||
/***/ }),
|
||
/* 44 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
module.exports = inlineHeaders;
|
||
|
||
var encode = __webpack_require__(45);
|
||
|
||
function inlineHeaders(url, headers) {
|
||
if (/\?/.test(url)) {
|
||
url += '&';
|
||
} else {
|
||
url += '?';
|
||
}
|
||
|
||
return url + encode(headers);
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 45 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
// 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.
|
||
|
||
|
||
|
||
var stringifyPrimitive = function(v) {
|
||
switch (typeof v) {
|
||
case 'string':
|
||
return v;
|
||
|
||
case 'boolean':
|
||
return v ? 'true' : 'false';
|
||
|
||
case 'number':
|
||
return isFinite(v) ? v : '';
|
||
|
||
default:
|
||
return '';
|
||
}
|
||
};
|
||
|
||
module.exports = function(obj, sep, eq, name) {
|
||
sep = sep || '&';
|
||
eq = eq || '=';
|
||
if (obj === null) {
|
||
obj = undefined;
|
||
}
|
||
|
||
if (typeof obj === 'object') {
|
||
return map(objectKeys(obj), function(k) {
|
||
var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
|
||
if (isArray(obj[k])) {
|
||
return map(obj[k], function(v) {
|
||
return ks + encodeURIComponent(stringifyPrimitive(v));
|
||
}).join(sep);
|
||
} else {
|
||
return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
|
||
}
|
||
}).join(sep);
|
||
|
||
}
|
||
|
||
if (!name) return '';
|
||
return encodeURIComponent(stringifyPrimitive(name)) + eq +
|
||
encodeURIComponent(stringifyPrimitive(obj));
|
||
};
|
||
|
||
var isArray = Array.isArray || function (xs) {
|
||
return Object.prototype.toString.call(xs) === '[object Array]';
|
||
};
|
||
|
||
function map (xs, f) {
|
||
if (xs.map) return xs.map(f);
|
||
var res = [];
|
||
for (var i = 0; i < xs.length; i++) {
|
||
res.push(f(xs[i], i));
|
||
}
|
||
return res;
|
||
}
|
||
|
||
var objectKeys = Object.keys || function (obj) {
|
||
var res = [];
|
||
for (var key in obj) {
|
||
if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key);
|
||
}
|
||
return res;
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 46 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
module.exports = jsonpRequest;
|
||
|
||
var errors = __webpack_require__(5);
|
||
|
||
var JSONPCounter = 0;
|
||
|
||
function jsonpRequest(url, opts, cb) {
|
||
if (opts.method !== 'GET') {
|
||
cb(new Error('Method ' + opts.method + ' ' + url + ' is not supported by JSONP.'));
|
||
return;
|
||
}
|
||
|
||
opts.debug('JSONP: start');
|
||
|
||
var cbCalled = false;
|
||
var timedOut = false;
|
||
|
||
JSONPCounter += 1;
|
||
var head = document.getElementsByTagName('head')[0];
|
||
var script = document.createElement('script');
|
||
var cbName = 'algoliaJSONP_' + JSONPCounter;
|
||
var done = false;
|
||
|
||
window[cbName] = function(data) {
|
||
removeGlobals();
|
||
|
||
if (timedOut) {
|
||
opts.debug('JSONP: Late answer, ignoring');
|
||
return;
|
||
}
|
||
|
||
cbCalled = true;
|
||
|
||
clean();
|
||
|
||
cb(null, {
|
||
body: data,
|
||
responseText: JSON.stringify(data)/* ,
|
||
// We do not send the statusCode, there's no statusCode in JSONP, it will be
|
||
// computed using data.status && data.message like with XDR
|
||
statusCode*/
|
||
});
|
||
};
|
||
|
||
// add callback by hand
|
||
url += '&callback=' + cbName;
|
||
|
||
// add body params manually
|
||
if (opts.jsonBody && opts.jsonBody.params) {
|
||
url += '&' + opts.jsonBody.params;
|
||
}
|
||
|
||
var ontimeout = setTimeout(timeout, opts.timeouts.complete);
|
||
|
||
// script onreadystatechange needed only for
|
||
// <= IE8
|
||
// https://github.com/angular/angular.js/issues/4523
|
||
script.onreadystatechange = readystatechange;
|
||
script.onload = success;
|
||
script.onerror = error;
|
||
|
||
script.async = true;
|
||
script.defer = true;
|
||
script.src = url;
|
||
head.appendChild(script);
|
||
|
||
function success() {
|
||
opts.debug('JSONP: success');
|
||
|
||
if (done || timedOut) {
|
||
return;
|
||
}
|
||
|
||
done = true;
|
||
|
||
// script loaded but did not call the fn => script loading error
|
||
if (!cbCalled) {
|
||
opts.debug('JSONP: Fail. Script loaded but did not call the callback');
|
||
clean();
|
||
cb(new errors.JSONPScriptFail());
|
||
}
|
||
}
|
||
|
||
function readystatechange() {
|
||
if (this.readyState === 'loaded' || this.readyState === 'complete') {
|
||
success();
|
||
}
|
||
}
|
||
|
||
function clean() {
|
||
clearTimeout(ontimeout);
|
||
script.onload = null;
|
||
script.onreadystatechange = null;
|
||
script.onerror = null;
|
||
head.removeChild(script);
|
||
}
|
||
|
||
function removeGlobals() {
|
||
try {
|
||
delete window[cbName];
|
||
delete window[cbName + '_loaded'];
|
||
} catch (e) {
|
||
window[cbName] = window[cbName + '_loaded'] = undefined;
|
||
}
|
||
}
|
||
|
||
function timeout() {
|
||
opts.debug('JSONP: Script timeout');
|
||
timedOut = true;
|
||
clean();
|
||
cb(new errors.RequestTimeout());
|
||
}
|
||
|
||
function error() {
|
||
opts.debug('JSONP: Script error');
|
||
|
||
if (done || timedOut) {
|
||
return;
|
||
}
|
||
|
||
clean();
|
||
cb(new errors.JSONPScriptError());
|
||
}
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 47 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = createPlacesClient;
|
||
|
||
var buildSearchMethod = __webpack_require__(13);
|
||
|
||
function createPlacesClient(algoliasearch) {
|
||
return function places(appID, apiKey, opts) {
|
||
var cloneDeep = __webpack_require__(3);
|
||
|
||
opts = opts && cloneDeep(opts) || {};
|
||
opts.hosts = opts.hosts || [
|
||
'places-dsn.algolia.net',
|
||
'places-1.algolianet.com',
|
||
'places-2.algolianet.com',
|
||
'places-3.algolianet.com'
|
||
];
|
||
|
||
// allow initPlaces() no arguments => community rate limited
|
||
if (arguments.length === 0 || typeof appID === 'object' || appID === undefined) {
|
||
appID = '';
|
||
apiKey = '';
|
||
opts._allowEmptyCredentials = true;
|
||
}
|
||
|
||
var client = algoliasearch(appID, apiKey, opts);
|
||
var index = client.initIndex('places');
|
||
index.search = buildSearchMethod('query', '/1/places/query');
|
||
index.getObject = function(objectID, callback) {
|
||
return this.as._jsonRequest({
|
||
method: 'GET',
|
||
url: '/1/places/' + encodeURIComponent(objectID),
|
||
hostType: 'read',
|
||
callback: callback
|
||
});
|
||
};
|
||
return index;
|
||
};
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 48 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
module.exports = '3.30.0';
|
||
|
||
|
||
/***/ }),
|
||
/* 49 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
module.exports = __webpack_require__(50);
|
||
|
||
|
||
/***/ }),
|
||
/* 50 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
// this will inject Zepto in window, unfortunately no easy commonJS zepto build
|
||
var zepto = __webpack_require__(15);
|
||
|
||
// setup DOM element
|
||
var DOM = __webpack_require__(1);
|
||
DOM.element = zepto;
|
||
|
||
// setup utils functions
|
||
var _ = __webpack_require__(0);
|
||
_.isArray = zepto.isArray;
|
||
_.isFunction = zepto.isFunction;
|
||
_.isObject = zepto.isPlainObject;
|
||
_.bind = zepto.proxy;
|
||
_.each = function(collection, cb) {
|
||
// stupid argument order for jQuery.each
|
||
zepto.each(collection, reverseArgs);
|
||
function reverseArgs(index, value) {
|
||
return cb(value, index);
|
||
}
|
||
};
|
||
_.map = zepto.map;
|
||
_.mixin = zepto.extend;
|
||
_.Event = zepto.Event;
|
||
|
||
var typeaheadKey = 'aaAutocomplete';
|
||
var Typeahead = __webpack_require__(51);
|
||
var EventBus = __webpack_require__(16);
|
||
|
||
function autocomplete(selector, options, datasets, typeaheadObject) {
|
||
datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 2);
|
||
|
||
var inputs = zepto(selector).each(function(i, input) {
|
||
var $input = zepto(input);
|
||
var eventBus = new EventBus({el: $input});
|
||
var typeahead = typeaheadObject || new Typeahead({
|
||
input: $input,
|
||
eventBus: eventBus,
|
||
dropdownMenuContainer: options.dropdownMenuContainer,
|
||
hint: options.hint === undefined ? true : !!options.hint,
|
||
minLength: options.minLength,
|
||
autoselect: options.autoselect,
|
||
autoselectOnBlur: options.autoselectOnBlur,
|
||
tabAutocomplete: options.tabAutocomplete,
|
||
openOnFocus: options.openOnFocus,
|
||
templates: options.templates,
|
||
debug: options.debug,
|
||
clearOnSelected: options.clearOnSelected,
|
||
cssClasses: options.cssClasses,
|
||
datasets: datasets,
|
||
keyboardShortcuts: options.keyboardShortcuts,
|
||
appendTo: options.appendTo,
|
||
autoWidth: options.autoWidth,
|
||
ariaLabel: options.ariaLabel || input.getAttribute('aria-label')
|
||
});
|
||
$input.data(typeaheadKey, typeahead);
|
||
});
|
||
|
||
// expose all methods in the `autocomplete` attribute
|
||
inputs.autocomplete = {};
|
||
_.each(['open', 'close', 'getVal', 'setVal', 'destroy', 'getWrapper'], function(method) {
|
||
inputs.autocomplete[method] = function() {
|
||
var methodArguments = arguments;
|
||
var result;
|
||
inputs.each(function(j, input) {
|
||
var typeahead = zepto(input).data(typeaheadKey);
|
||
result = typeahead[method].apply(typeahead, methodArguments);
|
||
});
|
||
return result;
|
||
};
|
||
});
|
||
|
||
return inputs;
|
||
}
|
||
|
||
autocomplete.sources = Typeahead.sources;
|
||
autocomplete.escapeHighlightedString = _.escapeHighlightedString;
|
||
|
||
var wasAutocompleteSet = 'autocomplete' in window;
|
||
var oldAutocomplete = window.autocomplete;
|
||
autocomplete.noConflict = function noConflict() {
|
||
if (wasAutocompleteSet) {
|
||
window.autocomplete = oldAutocomplete;
|
||
} else {
|
||
delete window.autocomplete;
|
||
}
|
||
return autocomplete;
|
||
};
|
||
|
||
module.exports = autocomplete;
|
||
|
||
|
||
/***/ }),
|
||
/* 51 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var attrsKey = 'aaAttrs';
|
||
|
||
var _ = __webpack_require__(0);
|
||
var DOM = __webpack_require__(1);
|
||
var EventBus = __webpack_require__(16);
|
||
var Input = __webpack_require__(52);
|
||
var Dropdown = __webpack_require__(59);
|
||
var html = __webpack_require__(17);
|
||
var css = __webpack_require__(11);
|
||
|
||
// constructor
|
||
// -----------
|
||
|
||
// THOUGHT: what if datasets could dynamically be added/removed?
|
||
function Typeahead(o) {
|
||
var $menu;
|
||
var $hint;
|
||
|
||
o = o || {};
|
||
|
||
if (!o.input) {
|
||
_.error('missing input');
|
||
}
|
||
|
||
this.isActivated = false;
|
||
this.debug = !!o.debug;
|
||
this.autoselect = !!o.autoselect;
|
||
this.autoselectOnBlur = !!o.autoselectOnBlur;
|
||
this.openOnFocus = !!o.openOnFocus;
|
||
this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
|
||
this.autoWidth = (o.autoWidth === undefined) ? true : !!o.autoWidth;
|
||
this.clearOnSelected = !!o.clearOnSelected;
|
||
this.tabAutocomplete = (o.tabAutocomplete === undefined) ? true : !!o.tabAutocomplete;
|
||
|
||
o.hint = !!o.hint;
|
||
|
||
if (o.hint && o.appendTo) {
|
||
throw new Error('[autocomplete.js] hint and appendTo options can\'t be used at the same time');
|
||
}
|
||
|
||
this.css = o.css = _.mixin({}, css, o.appendTo ? css.appendTo : {});
|
||
this.cssClasses = o.cssClasses = _.mixin({}, css.defaultClasses, o.cssClasses || {});
|
||
this.cssClasses.prefix =
|
||
o.cssClasses.formattedPrefix = _.formatPrefix(this.cssClasses.prefix, this.cssClasses.noPrefix);
|
||
this.listboxId = o.listboxId = [this.cssClasses.root, 'listbox', _.getUniqueId()].join('-');
|
||
|
||
var domElts = buildDom(o);
|
||
|
||
this.$node = domElts.wrapper;
|
||
var $input = this.$input = domElts.input;
|
||
$menu = domElts.menu;
|
||
$hint = domElts.hint;
|
||
|
||
if (o.dropdownMenuContainer) {
|
||
DOM.element(o.dropdownMenuContainer)
|
||
.css('position', 'relative') // ensure the container has a relative position
|
||
.append($menu.css('top', '0')); // override the top: 100%
|
||
}
|
||
|
||
// #705: if there's scrollable overflow, ie doesn't support
|
||
// blur cancellations when the scrollbar is clicked
|
||
//
|
||
// #351: preventDefault won't cancel blurs in ie <= 8
|
||
$input.on('blur.aa', function($e) {
|
||
var active = document.activeElement;
|
||
if (_.isMsie() && ($menu[0] === active || $menu[0].contains(active))) {
|
||
$e.preventDefault();
|
||
// stop immediate in order to prevent Input#_onBlur from
|
||
// getting exectued
|
||
$e.stopImmediatePropagation();
|
||
_.defer(function() { $input.focus(); });
|
||
}
|
||
});
|
||
|
||
// #351: prevents input blur due to clicks within dropdown menu
|
||
$menu.on('mousedown.aa', function($e) { $e.preventDefault(); });
|
||
|
||
this.eventBus = o.eventBus || new EventBus({el: $input});
|
||
|
||
this.dropdown = new Typeahead.Dropdown({
|
||
appendTo: o.appendTo,
|
||
wrapper: this.$node,
|
||
menu: $menu,
|
||
datasets: o.datasets,
|
||
templates: o.templates,
|
||
cssClasses: o.cssClasses,
|
||
minLength: this.minLength
|
||
})
|
||
.onSync('suggestionClicked', this._onSuggestionClicked, this)
|
||
.onSync('cursorMoved', this._onCursorMoved, this)
|
||
.onSync('cursorRemoved', this._onCursorRemoved, this)
|
||
.onSync('opened', this._onOpened, this)
|
||
.onSync('closed', this._onClosed, this)
|
||
.onSync('shown', this._onShown, this)
|
||
.onSync('empty', this._onEmpty, this)
|
||
.onSync('redrawn', this._onRedrawn, this)
|
||
.onAsync('datasetRendered', this._onDatasetRendered, this);
|
||
|
||
this.input = new Typeahead.Input({input: $input, hint: $hint})
|
||
.onSync('focused', this._onFocused, this)
|
||
.onSync('blurred', this._onBlurred, this)
|
||
.onSync('enterKeyed', this._onEnterKeyed, this)
|
||
.onSync('tabKeyed', this._onTabKeyed, this)
|
||
.onSync('escKeyed', this._onEscKeyed, this)
|
||
.onSync('upKeyed', this._onUpKeyed, this)
|
||
.onSync('downKeyed', this._onDownKeyed, this)
|
||
.onSync('leftKeyed', this._onLeftKeyed, this)
|
||
.onSync('rightKeyed', this._onRightKeyed, this)
|
||
.onSync('queryChanged', this._onQueryChanged, this)
|
||
.onSync('whitespaceChanged', this._onWhitespaceChanged, this);
|
||
|
||
this._bindKeyboardShortcuts(o);
|
||
|
||
this._setLanguageDirection();
|
||
}
|
||
|
||
// instance methods
|
||
// ----------------
|
||
|
||
_.mixin(Typeahead.prototype, {
|
||
// ### private
|
||
|
||
_bindKeyboardShortcuts: function(options) {
|
||
if (!options.keyboardShortcuts) {
|
||
return;
|
||
}
|
||
var $input = this.$input;
|
||
var keyboardShortcuts = [];
|
||
_.each(options.keyboardShortcuts, function(key) {
|
||
if (typeof key === 'string') {
|
||
key = key.toUpperCase().charCodeAt(0);
|
||
}
|
||
keyboardShortcuts.push(key);
|
||
});
|
||
DOM.element(document).keydown(function(event) {
|
||
var elt = (event.target || event.srcElement);
|
||
var tagName = elt.tagName;
|
||
if (elt.isContentEditable || tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
|
||
// already in an input
|
||
return;
|
||
}
|
||
|
||
var which = event.which || event.keyCode;
|
||
if (keyboardShortcuts.indexOf(which) === -1) {
|
||
// not the right shortcut
|
||
return;
|
||
}
|
||
|
||
$input.focus();
|
||
event.stopPropagation();
|
||
event.preventDefault();
|
||
});
|
||
},
|
||
|
||
_onSuggestionClicked: function onSuggestionClicked(type, $el) {
|
||
var datum;
|
||
var context = {selectionMethod: 'click'};
|
||
|
||
if (datum = this.dropdown.getDatumForSuggestion($el)) {
|
||
this._select(datum, context);
|
||
}
|
||
},
|
||
|
||
_onCursorMoved: function onCursorMoved(event, updateInput) {
|
||
var datum = this.dropdown.getDatumForCursor();
|
||
var currentCursorId = this.dropdown.getCurrentCursor().attr('id');
|
||
this.input.setActiveDescendant(currentCursorId);
|
||
|
||
if (datum) {
|
||
if (updateInput) {
|
||
this.input.setInputValue(datum.value, true);
|
||
}
|
||
|
||
this.eventBus.trigger('cursorchanged', datum.raw, datum.datasetName);
|
||
}
|
||
},
|
||
|
||
_onCursorRemoved: function onCursorRemoved() {
|
||
this.input.resetInputValue();
|
||
this._updateHint();
|
||
this.eventBus.trigger('cursorremoved');
|
||
},
|
||
|
||
_onDatasetRendered: function onDatasetRendered() {
|
||
this._updateHint();
|
||
|
||
this.eventBus.trigger('updated');
|
||
},
|
||
|
||
_onOpened: function onOpened() {
|
||
this._updateHint();
|
||
this.input.expand();
|
||
|
||
this.eventBus.trigger('opened');
|
||
},
|
||
|
||
_onEmpty: function onEmpty() {
|
||
this.eventBus.trigger('empty');
|
||
},
|
||
|
||
_onRedrawn: function onRedrawn() {
|
||
this.$node.css('top', 0 + 'px');
|
||
this.$node.css('left', 0 + 'px');
|
||
|
||
var inputRect = this.$input[0].getBoundingClientRect();
|
||
|
||
if (this.autoWidth) {
|
||
this.$node.css('width', inputRect.width + 'px');
|
||
}
|
||
|
||
var wrapperRect = this.$node[0].getBoundingClientRect();
|
||
|
||
var top = inputRect.bottom - wrapperRect.top;
|
||
this.$node.css('top', top + 'px');
|
||
var left = inputRect.left - wrapperRect.left;
|
||
this.$node.css('left', left + 'px');
|
||
|
||
this.eventBus.trigger('redrawn');
|
||
},
|
||
|
||
_onShown: function onShown() {
|
||
this.eventBus.trigger('shown');
|
||
if (this.autoselect) {
|
||
this.dropdown.cursorTopSuggestion();
|
||
}
|
||
},
|
||
|
||
_onClosed: function onClosed() {
|
||
this.input.clearHint();
|
||
this.input.removeActiveDescendant();
|
||
this.input.collapse();
|
||
|
||
this.eventBus.trigger('closed');
|
||
},
|
||
|
||
_onFocused: function onFocused() {
|
||
this.isActivated = true;
|
||
|
||
if (this.openOnFocus) {
|
||
var query = this.input.getQuery();
|
||
if (query.length >= this.minLength) {
|
||
this.dropdown.update(query);
|
||
} else {
|
||
this.dropdown.empty();
|
||
}
|
||
|
||
this.dropdown.open();
|
||
}
|
||
},
|
||
|
||
_onBlurred: function onBlurred() {
|
||
var cursorDatum;
|
||
var topSuggestionDatum;
|
||
|
||
cursorDatum = this.dropdown.getDatumForCursor();
|
||
topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();
|
||
var context = {selectionMethod: 'blur'};
|
||
|
||
if (!this.debug) {
|
||
if (this.autoselectOnBlur && cursorDatum) {
|
||
this._select(cursorDatum, context);
|
||
} else if (this.autoselectOnBlur && topSuggestionDatum) {
|
||
this._select(topSuggestionDatum, context);
|
||
} else {
|
||
this.isActivated = false;
|
||
this.dropdown.empty();
|
||
this.dropdown.close();
|
||
}
|
||
}
|
||
},
|
||
|
||
_onEnterKeyed: function onEnterKeyed(type, $e) {
|
||
var cursorDatum;
|
||
var topSuggestionDatum;
|
||
|
||
cursorDatum = this.dropdown.getDatumForCursor();
|
||
topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();
|
||
var context = {selectionMethod: 'enterKey'};
|
||
|
||
if (cursorDatum) {
|
||
this._select(cursorDatum, context);
|
||
$e.preventDefault();
|
||
} else if (this.autoselect && topSuggestionDatum) {
|
||
this._select(topSuggestionDatum, context);
|
||
$e.preventDefault();
|
||
}
|
||
},
|
||
|
||
_onTabKeyed: function onTabKeyed(type, $e) {
|
||
if (!this.tabAutocomplete) {
|
||
// Closing the dropdown enables further tabbing
|
||
this.dropdown.close();
|
||
return;
|
||
}
|
||
|
||
var datum;
|
||
var context = {selectionMethod: 'tabKey'};
|
||
|
||
if (datum = this.dropdown.getDatumForCursor()) {
|
||
this._select(datum, context);
|
||
$e.preventDefault();
|
||
} else {
|
||
this._autocomplete(true);
|
||
}
|
||
},
|
||
|
||
_onEscKeyed: function onEscKeyed() {
|
||
this.dropdown.close();
|
||
this.input.resetInputValue();
|
||
},
|
||
|
||
_onUpKeyed: function onUpKeyed() {
|
||
var query = this.input.getQuery();
|
||
|
||
if (this.dropdown.isEmpty && query.length >= this.minLength) {
|
||
this.dropdown.update(query);
|
||
} else {
|
||
this.dropdown.moveCursorUp();
|
||
}
|
||
|
||
this.dropdown.open();
|
||
},
|
||
|
||
_onDownKeyed: function onDownKeyed() {
|
||
var query = this.input.getQuery();
|
||
|
||
if (this.dropdown.isEmpty && query.length >= this.minLength) {
|
||
this.dropdown.update(query);
|
||
} else {
|
||
this.dropdown.moveCursorDown();
|
||
}
|
||
|
||
this.dropdown.open();
|
||
},
|
||
|
||
_onLeftKeyed: function onLeftKeyed() {
|
||
if (this.dir === 'rtl') {
|
||
this._autocomplete();
|
||
}
|
||
},
|
||
|
||
_onRightKeyed: function onRightKeyed() {
|
||
if (this.dir === 'ltr') {
|
||
this._autocomplete();
|
||
}
|
||
},
|
||
|
||
_onQueryChanged: function onQueryChanged(e, query) {
|
||
this.input.clearHintIfInvalid();
|
||
|
||
if (query.length >= this.minLength) {
|
||
this.dropdown.update(query);
|
||
} else {
|
||
this.dropdown.empty();
|
||
}
|
||
|
||
this.dropdown.open();
|
||
this._setLanguageDirection();
|
||
},
|
||
|
||
_onWhitespaceChanged: function onWhitespaceChanged() {
|
||
this._updateHint();
|
||
this.dropdown.open();
|
||
},
|
||
|
||
_setLanguageDirection: function setLanguageDirection() {
|
||
var dir = this.input.getLanguageDirection();
|
||
|
||
if (this.dir !== dir) {
|
||
this.dir = dir;
|
||
this.$node.css('direction', dir);
|
||
this.dropdown.setLanguageDirection(dir);
|
||
}
|
||
},
|
||
|
||
_updateHint: function updateHint() {
|
||
var datum;
|
||
var val;
|
||
var query;
|
||
var escapedQuery;
|
||
var frontMatchRegEx;
|
||
var match;
|
||
|
||
datum = this.dropdown.getDatumForTopSuggestion();
|
||
|
||
if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {
|
||
val = this.input.getInputValue();
|
||
query = Input.normalizeQuery(val);
|
||
escapedQuery = _.escapeRegExChars(query);
|
||
|
||
// match input value, then capture trailing text
|
||
frontMatchRegEx = new RegExp('^(?:' + escapedQuery + ')(.+$)', 'i');
|
||
match = frontMatchRegEx.exec(datum.value);
|
||
|
||
// clear hint if there's no trailing text
|
||
if (match) {
|
||
this.input.setHint(val + match[1]);
|
||
} else {
|
||
this.input.clearHint();
|
||
}
|
||
} else {
|
||
this.input.clearHint();
|
||
}
|
||
},
|
||
|
||
_autocomplete: function autocomplete(laxCursor) {
|
||
var hint;
|
||
var query;
|
||
var isCursorAtEnd;
|
||
var datum;
|
||
|
||
hint = this.input.getHint();
|
||
query = this.input.getQuery();
|
||
isCursorAtEnd = laxCursor || this.input.isCursorAtEnd();
|
||
|
||
if (hint && query !== hint && isCursorAtEnd) {
|
||
datum = this.dropdown.getDatumForTopSuggestion();
|
||
if (datum) {
|
||
this.input.setInputValue(datum.value);
|
||
}
|
||
|
||
this.eventBus.trigger('autocompleted', datum.raw, datum.datasetName);
|
||
}
|
||
},
|
||
|
||
_select: function select(datum, context) {
|
||
if (typeof datum.value !== 'undefined') {
|
||
this.input.setQuery(datum.value);
|
||
}
|
||
if (this.clearOnSelected) {
|
||
this.setVal('');
|
||
} else {
|
||
this.input.setInputValue(datum.value, true);
|
||
}
|
||
|
||
this._setLanguageDirection();
|
||
|
||
var event = this.eventBus.trigger('selected', datum.raw, datum.datasetName, context);
|
||
if (event.isDefaultPrevented() === false) {
|
||
this.dropdown.close();
|
||
|
||
// #118: allow click event to bubble up to the body before removing
|
||
// the suggestions otherwise we break event delegation
|
||
_.defer(_.bind(this.dropdown.empty, this.dropdown));
|
||
}
|
||
},
|
||
|
||
// ### public
|
||
|
||
open: function open() {
|
||
// if the menu is not activated yet, we need to update
|
||
// the underlying dropdown menu to trigger the search
|
||
// otherwise we're not gonna see anything
|
||
if (!this.isActivated) {
|
||
var query = this.input.getInputValue();
|
||
if (query.length >= this.minLength) {
|
||
this.dropdown.update(query);
|
||
} else {
|
||
this.dropdown.empty();
|
||
}
|
||
}
|
||
this.dropdown.open();
|
||
},
|
||
|
||
close: function close() {
|
||
this.dropdown.close();
|
||
},
|
||
|
||
setVal: function setVal(val) {
|
||
// expect val to be a string, so be safe, and coerce
|
||
val = _.toStr(val);
|
||
|
||
if (this.isActivated) {
|
||
this.input.setInputValue(val);
|
||
} else {
|
||
this.input.setQuery(val);
|
||
this.input.setInputValue(val, true);
|
||
}
|
||
|
||
this._setLanguageDirection();
|
||
},
|
||
|
||
getVal: function getVal() {
|
||
return this.input.getQuery();
|
||
},
|
||
|
||
destroy: function destroy() {
|
||
this.input.destroy();
|
||
this.dropdown.destroy();
|
||
|
||
destroyDomStructure(this.$node, this.cssClasses);
|
||
|
||
this.$node = null;
|
||
},
|
||
|
||
getWrapper: function getWrapper() {
|
||
return this.dropdown.$container[0];
|
||
}
|
||
});
|
||
|
||
function buildDom(options) {
|
||
var $input;
|
||
var $wrapper;
|
||
var $dropdown;
|
||
var $hint;
|
||
|
||
$input = DOM.element(options.input);
|
||
$wrapper = DOM
|
||
.element(html.wrapper.replace('%ROOT%', options.cssClasses.root))
|
||
.css(options.css.wrapper);
|
||
|
||
// override the display property with the table-cell value
|
||
// if the parent element is a table and the original input was a block
|
||
// -> https://github.com/algolia/autocomplete.js/issues/16
|
||
if (!options.appendTo && $input.css('display') === 'block' && $input.parent().css('display') === 'table') {
|
||
$wrapper.css('display', 'table-cell');
|
||
}
|
||
var dropdownHtml = html.dropdown.
|
||
replace('%PREFIX%', options.cssClasses.prefix).
|
||
replace('%DROPDOWN_MENU%', options.cssClasses.dropdownMenu);
|
||
$dropdown = DOM.element(dropdownHtml)
|
||
.css(options.css.dropdown)
|
||
.attr({
|
||
role: 'listbox',
|
||
id: options.listboxId
|
||
});
|
||
if (options.templates && options.templates.dropdownMenu) {
|
||
$dropdown.html(_.templatify(options.templates.dropdownMenu)());
|
||
}
|
||
$hint = $input.clone().css(options.css.hint).css(getBackgroundStyles($input));
|
||
|
||
$hint
|
||
.val('')
|
||
.addClass(_.className(options.cssClasses.prefix, options.cssClasses.hint, true))
|
||
.removeAttr('id name placeholder required')
|
||
.prop('readonly', true)
|
||
.attr({
|
||
'aria-hidden': 'true',
|
||
autocomplete: 'off',
|
||
spellcheck: 'false',
|
||
tabindex: -1
|
||
});
|
||
if ($hint.removeData) {
|
||
$hint.removeData();
|
||
}
|
||
|
||
// store the original values of the attrs that get modified
|
||
// so modifications can be reverted on destroy
|
||
$input.data(attrsKey, {
|
||
'aria-autocomplete': $input.attr('aria-autocomplete'),
|
||
'aria-expanded': $input.attr('aria-expanded'),
|
||
'aria-owns': $input.attr('aria-owns'),
|
||
autocomplete: $input.attr('autocomplete'),
|
||
dir: $input.attr('dir'),
|
||
role: $input.attr('role'),
|
||
spellcheck: $input.attr('spellcheck'),
|
||
style: $input.attr('style'),
|
||
type: $input.attr('type')
|
||
});
|
||
|
||
$input
|
||
.addClass(_.className(options.cssClasses.prefix, options.cssClasses.input, true))
|
||
.attr({
|
||
autocomplete: 'off',
|
||
spellcheck: false,
|
||
|
||
// Accessibility features
|
||
// Give the field a presentation of a "select".
|
||
// Combobox is the combined presentation of a single line textfield
|
||
// with a listbox popup.
|
||
// https://www.w3.org/WAI/PF/aria/roles#combobox
|
||
role: 'combobox',
|
||
// Let the screen reader know the field has an autocomplete
|
||
// feature to it.
|
||
'aria-autocomplete': (options.datasets &&
|
||
options.datasets[0] && options.datasets[0].displayKey ? 'both' : 'list'),
|
||
// Indicates whether the dropdown it controls is currently expanded or collapsed
|
||
'aria-expanded': 'false',
|
||
'aria-label': options.ariaLabel,
|
||
// Explicitly point to the listbox,
|
||
// which is a list of suggestions (aka options)
|
||
'aria-owns': options.listboxId
|
||
})
|
||
.css(options.hint ? options.css.input : options.css.inputWithNoHint);
|
||
|
||
// ie7 does not like it when dir is set to auto
|
||
try {
|
||
if (!$input.attr('dir')) {
|
||
$input.attr('dir', 'auto');
|
||
}
|
||
} catch (e) {
|
||
// ignore
|
||
}
|
||
|
||
$wrapper = options.appendTo
|
||
? $wrapper.appendTo(DOM.element(options.appendTo).eq(0)).eq(0)
|
||
: $input.wrap($wrapper).parent();
|
||
|
||
$wrapper
|
||
.prepend(options.hint ? $hint : null)
|
||
.append($dropdown);
|
||
|
||
return {
|
||
wrapper: $wrapper,
|
||
input: $input,
|
||
hint: $hint,
|
||
menu: $dropdown
|
||
};
|
||
}
|
||
|
||
function getBackgroundStyles($el) {
|
||
return {
|
||
backgroundAttachment: $el.css('background-attachment'),
|
||
backgroundClip: $el.css('background-clip'),
|
||
backgroundColor: $el.css('background-color'),
|
||
backgroundImage: $el.css('background-image'),
|
||
backgroundOrigin: $el.css('background-origin'),
|
||
backgroundPosition: $el.css('background-position'),
|
||
backgroundRepeat: $el.css('background-repeat'),
|
||
backgroundSize: $el.css('background-size')
|
||
};
|
||
}
|
||
|
||
function destroyDomStructure($node, cssClasses) {
|
||
var $input = $node.find(_.className(cssClasses.prefix, cssClasses.input));
|
||
|
||
// need to remove attrs that weren't previously defined and
|
||
// revert attrs that originally had a value
|
||
_.each($input.data(attrsKey), function(val, key) {
|
||
if (val === undefined) {
|
||
$input.removeAttr(key);
|
||
} else {
|
||
$input.attr(key, val);
|
||
}
|
||
});
|
||
|
||
$input
|
||
.detach()
|
||
.removeClass(_.className(cssClasses.prefix, cssClasses.input, true))
|
||
.insertAfter($node);
|
||
if ($input.removeData) {
|
||
$input.removeData(attrsKey);
|
||
}
|
||
|
||
$node.remove();
|
||
}
|
||
|
||
Typeahead.Dropdown = Dropdown;
|
||
Typeahead.Input = Input;
|
||
Typeahead.sources = __webpack_require__(61);
|
||
|
||
module.exports = Typeahead;
|
||
|
||
|
||
/***/ }),
|
||
/* 52 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var specialKeyCodeMap;
|
||
|
||
specialKeyCodeMap = {
|
||
9: 'tab',
|
||
27: 'esc',
|
||
37: 'left',
|
||
39: 'right',
|
||
13: 'enter',
|
||
38: 'up',
|
||
40: 'down'
|
||
};
|
||
|
||
var _ = __webpack_require__(0);
|
||
var DOM = __webpack_require__(1);
|
||
var EventEmitter = __webpack_require__(10);
|
||
|
||
// constructor
|
||
// -----------
|
||
|
||
function Input(o) {
|
||
var that = this;
|
||
var onBlur;
|
||
var onFocus;
|
||
var onKeydown;
|
||
var onInput;
|
||
|
||
o = o || {};
|
||
|
||
if (!o.input) {
|
||
_.error('input is missing');
|
||
}
|
||
|
||
// bound functions
|
||
onBlur = _.bind(this._onBlur, this);
|
||
onFocus = _.bind(this._onFocus, this);
|
||
onKeydown = _.bind(this._onKeydown, this);
|
||
onInput = _.bind(this._onInput, this);
|
||
|
||
this.$hint = DOM.element(o.hint);
|
||
this.$input = DOM.element(o.input)
|
||
.on('blur.aa', onBlur)
|
||
.on('focus.aa', onFocus)
|
||
.on('keydown.aa', onKeydown);
|
||
|
||
// if no hint, noop all the hint related functions
|
||
if (this.$hint.length === 0) {
|
||
this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
|
||
}
|
||
|
||
// ie7 and ie8 don't support the input event
|
||
// ie9 doesn't fire the input event when characters are removed
|
||
// not sure if ie10 is compatible
|
||
if (!_.isMsie()) {
|
||
this.$input.on('input.aa', onInput);
|
||
} else {
|
||
this.$input.on('keydown.aa keypress.aa cut.aa paste.aa', function($e) {
|
||
// if a special key triggered this, ignore it
|
||
if (specialKeyCodeMap[$e.which || $e.keyCode]) {
|
||
return;
|
||
}
|
||
|
||
// give the browser a chance to update the value of the input
|
||
// before checking to see if the query changed
|
||
_.defer(_.bind(that._onInput, that, $e));
|
||
});
|
||
}
|
||
|
||
// the query defaults to whatever the value of the input is
|
||
// on initialization, it'll most likely be an empty string
|
||
this.query = this.$input.val();
|
||
|
||
// helps with calculating the width of the input's value
|
||
this.$overflowHelper = buildOverflowHelper(this.$input);
|
||
}
|
||
|
||
// static methods
|
||
// --------------
|
||
|
||
Input.normalizeQuery = function(str) {
|
||
// strips leading whitespace and condenses all whitespace
|
||
return (str || '').replace(/^\s*/g, '').replace(/\s{2,}/g, ' ');
|
||
};
|
||
|
||
// instance methods
|
||
// ----------------
|
||
|
||
_.mixin(Input.prototype, EventEmitter, {
|
||
|
||
// ### private
|
||
|
||
_onBlur: function onBlur() {
|
||
this.resetInputValue();
|
||
this.$input.removeAttr('aria-activedescendant');
|
||
this.trigger('blurred');
|
||
},
|
||
|
||
_onFocus: function onFocus() {
|
||
this.trigger('focused');
|
||
},
|
||
|
||
_onKeydown: function onKeydown($e) {
|
||
// which is normalized and consistent (but not for ie)
|
||
var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
|
||
|
||
this._managePreventDefault(keyName, $e);
|
||
if (keyName && this._shouldTrigger(keyName, $e)) {
|
||
this.trigger(keyName + 'Keyed', $e);
|
||
}
|
||
},
|
||
|
||
_onInput: function onInput() {
|
||
this._checkInputValue();
|
||
},
|
||
|
||
_managePreventDefault: function managePreventDefault(keyName, $e) {
|
||
var preventDefault;
|
||
var hintValue;
|
||
var inputValue;
|
||
|
||
switch (keyName) {
|
||
case 'tab':
|
||
hintValue = this.getHint();
|
||
inputValue = this.getInputValue();
|
||
|
||
preventDefault = hintValue &&
|
||
hintValue !== inputValue &&
|
||
!withModifier($e);
|
||
break;
|
||
|
||
case 'up':
|
||
case 'down':
|
||
preventDefault = !withModifier($e);
|
||
break;
|
||
|
||
default:
|
||
preventDefault = false;
|
||
}
|
||
|
||
if (preventDefault) {
|
||
$e.preventDefault();
|
||
}
|
||
},
|
||
|
||
_shouldTrigger: function shouldTrigger(keyName, $e) {
|
||
var trigger;
|
||
|
||
switch (keyName) {
|
||
case 'tab':
|
||
trigger = !withModifier($e);
|
||
break;
|
||
|
||
default:
|
||
trigger = true;
|
||
}
|
||
|
||
return trigger;
|
||
},
|
||
|
||
_checkInputValue: function checkInputValue() {
|
||
var inputValue;
|
||
var areEquivalent;
|
||
var hasDifferentWhitespace;
|
||
|
||
inputValue = this.getInputValue();
|
||
areEquivalent = areQueriesEquivalent(inputValue, this.query);
|
||
hasDifferentWhitespace = areEquivalent && this.query ?
|
||
this.query.length !== inputValue.length : false;
|
||
|
||
this.query = inputValue;
|
||
|
||
if (!areEquivalent) {
|
||
this.trigger('queryChanged', this.query);
|
||
} else if (hasDifferentWhitespace) {
|
||
this.trigger('whitespaceChanged', this.query);
|
||
}
|
||
},
|
||
|
||
// ### public
|
||
|
||
focus: function focus() {
|
||
this.$input.focus();
|
||
},
|
||
|
||
blur: function blur() {
|
||
this.$input.blur();
|
||
},
|
||
|
||
getQuery: function getQuery() {
|
||
return this.query;
|
||
},
|
||
|
||
setQuery: function setQuery(query) {
|
||
this.query = query;
|
||
},
|
||
|
||
getInputValue: function getInputValue() {
|
||
return this.$input.val();
|
||
},
|
||
|
||
setInputValue: function setInputValue(value, silent) {
|
||
if (typeof value === 'undefined') {
|
||
value = this.query;
|
||
}
|
||
this.$input.val(value);
|
||
|
||
// silent prevents any additional events from being triggered
|
||
if (silent) {
|
||
this.clearHint();
|
||
} else {
|
||
this._checkInputValue();
|
||
}
|
||
},
|
||
|
||
expand: function expand() {
|
||
this.$input.attr('aria-expanded', 'true');
|
||
},
|
||
|
||
collapse: function collapse() {
|
||
this.$input.attr('aria-expanded', 'false');
|
||
},
|
||
|
||
setActiveDescendant: function setActiveDescendant(activedescendantId) {
|
||
this.$input.attr('aria-activedescendant', activedescendantId);
|
||
},
|
||
|
||
removeActiveDescendant: function removeActiveDescendant() {
|
||
this.$input.removeAttr('aria-activedescendant');
|
||
},
|
||
|
||
resetInputValue: function resetInputValue() {
|
||
this.setInputValue(this.query, true);
|
||
},
|
||
|
||
getHint: function getHint() {
|
||
return this.$hint.val();
|
||
},
|
||
|
||
setHint: function setHint(value) {
|
||
this.$hint.val(value);
|
||
},
|
||
|
||
clearHint: function clearHint() {
|
||
this.setHint('');
|
||
},
|
||
|
||
clearHintIfInvalid: function clearHintIfInvalid() {
|
||
var val;
|
||
var hint;
|
||
var valIsPrefixOfHint;
|
||
var isValid;
|
||
|
||
val = this.getInputValue();
|
||
hint = this.getHint();
|
||
valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
|
||
isValid = val !== '' && valIsPrefixOfHint && !this.hasOverflow();
|
||
|
||
if (!isValid) {
|
||
this.clearHint();
|
||
}
|
||
},
|
||
|
||
getLanguageDirection: function getLanguageDirection() {
|
||
return (this.$input.css('direction') || 'ltr').toLowerCase();
|
||
},
|
||
|
||
hasOverflow: function hasOverflow() {
|
||
// 2 is arbitrary, just picking a small number to handle edge cases
|
||
var constraint = this.$input.width() - 2;
|
||
|
||
this.$overflowHelper.text(this.getInputValue());
|
||
|
||
return this.$overflowHelper.width() >= constraint;
|
||
},
|
||
|
||
isCursorAtEnd: function() {
|
||
var valueLength;
|
||
var selectionStart;
|
||
var range;
|
||
|
||
valueLength = this.$input.val().length;
|
||
selectionStart = this.$input[0].selectionStart;
|
||
|
||
if (_.isNumber(selectionStart)) {
|
||
return selectionStart === valueLength;
|
||
} else if (document.selection) {
|
||
// NOTE: this won't work unless the input has focus, the good news
|
||
// is this code should only get called when the input has focus
|
||
range = document.selection.createRange();
|
||
range.moveStart('character', -valueLength);
|
||
|
||
return valueLength === range.text.length;
|
||
}
|
||
|
||
return true;
|
||
},
|
||
|
||
destroy: function destroy() {
|
||
this.$hint.off('.aa');
|
||
this.$input.off('.aa');
|
||
|
||
this.$hint = this.$input = this.$overflowHelper = null;
|
||
}
|
||
});
|
||
|
||
// helper functions
|
||
// ----------------
|
||
|
||
function buildOverflowHelper($input) {
|
||
return DOM.element('<pre aria-hidden="true"></pre>')
|
||
.css({
|
||
// position helper off-screen
|
||
position: 'absolute',
|
||
visibility: 'hidden',
|
||
// avoid line breaks and whitespace collapsing
|
||
whiteSpace: 'pre',
|
||
// use same font css as input to calculate accurate width
|
||
fontFamily: $input.css('font-family'),
|
||
fontSize: $input.css('font-size'),
|
||
fontStyle: $input.css('font-style'),
|
||
fontVariant: $input.css('font-variant'),
|
||
fontWeight: $input.css('font-weight'),
|
||
wordSpacing: $input.css('word-spacing'),
|
||
letterSpacing: $input.css('letter-spacing'),
|
||
textIndent: $input.css('text-indent'),
|
||
textRendering: $input.css('text-rendering'),
|
||
textTransform: $input.css('text-transform')
|
||
})
|
||
.insertAfter($input);
|
||
}
|
||
|
||
function areQueriesEquivalent(a, b) {
|
||
return Input.normalizeQuery(a) === Input.normalizeQuery(b);
|
||
}
|
||
|
||
function withModifier($e) {
|
||
return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
|
||
}
|
||
|
||
module.exports = Input;
|
||
|
||
|
||
/***/ }),
|
||
/* 53 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
var types = [
|
||
__webpack_require__(54),
|
||
__webpack_require__(55),
|
||
__webpack_require__(56),
|
||
__webpack_require__(57),
|
||
__webpack_require__(58)
|
||
];
|
||
var draining;
|
||
var currentQueue;
|
||
var queueIndex = -1;
|
||
var queue = [];
|
||
var scheduled = false;
|
||
function cleanUpNextTick() {
|
||
if (!draining || !currentQueue) {
|
||
return;
|
||
}
|
||
draining = false;
|
||
if (currentQueue.length) {
|
||
queue = currentQueue.concat(queue);
|
||
} else {
|
||
queueIndex = -1;
|
||
}
|
||
if (queue.length) {
|
||
nextTick();
|
||
}
|
||
}
|
||
|
||
//named nextTick for less confusing stack traces
|
||
function nextTick() {
|
||
if (draining) {
|
||
return;
|
||
}
|
||
scheduled = false;
|
||
draining = true;
|
||
var len = queue.length;
|
||
var timeout = setTimeout(cleanUpNextTick);
|
||
while (len) {
|
||
currentQueue = queue;
|
||
queue = [];
|
||
while (currentQueue && ++queueIndex < len) {
|
||
currentQueue[queueIndex].run();
|
||
}
|
||
queueIndex = -1;
|
||
len = queue.length;
|
||
}
|
||
currentQueue = null;
|
||
queueIndex = -1;
|
||
draining = false;
|
||
clearTimeout(timeout);
|
||
}
|
||
var scheduleDrain;
|
||
var i = -1;
|
||
var len = types.length;
|
||
while (++i < len) {
|
||
if (types[i] && types[i].test && types[i].test()) {
|
||
scheduleDrain = types[i].install(nextTick);
|
||
break;
|
||
}
|
||
}
|
||
// v8 likes predictible objects
|
||
function Item(fun, array) {
|
||
this.fun = fun;
|
||
this.array = array;
|
||
}
|
||
Item.prototype.run = function () {
|
||
var fun = this.fun;
|
||
var array = this.array;
|
||
switch (array.length) {
|
||
case 0:
|
||
return fun();
|
||
case 1:
|
||
return fun(array[0]);
|
||
case 2:
|
||
return fun(array[0], array[1]);
|
||
case 3:
|
||
return fun(array[0], array[1], array[2]);
|
||
default:
|
||
return fun.apply(null, array);
|
||
}
|
||
|
||
};
|
||
module.exports = immediate;
|
||
function immediate(task) {
|
||
var args = new Array(arguments.length - 1);
|
||
if (arguments.length > 1) {
|
||
for (var i = 1; i < arguments.length; i++) {
|
||
args[i - 1] = arguments[i];
|
||
}
|
||
}
|
||
queue.push(new Item(task, args));
|
||
if (!scheduled && !draining) {
|
||
scheduled = true;
|
||
scheduleDrain();
|
||
}
|
||
}
|
||
|
||
|
||
/***/ }),
|
||
/* 54 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
/* WEBPACK VAR INJECTION */(function(process) {
|
||
exports.test = function () {
|
||
// Don't get fooled by e.g. browserify environments.
|
||
return (typeof process !== 'undefined') && !process.browser;
|
||
};
|
||
|
||
exports.install = function (func) {
|
||
return function () {
|
||
process.nextTick(func);
|
||
};
|
||
};
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9)))
|
||
|
||
/***/ }),
|
||
/* 55 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
/* WEBPACK VAR INJECTION */(function(global) {
|
||
//based off rsvp https://github.com/tildeio/rsvp.js
|
||
//license https://github.com/tildeio/rsvp.js/blob/master/LICENSE
|
||
//https://github.com/tildeio/rsvp.js/blob/master/lib/rsvp/asap.js
|
||
|
||
var Mutation = global.MutationObserver || global.WebKitMutationObserver;
|
||
|
||
exports.test = function () {
|
||
return Mutation;
|
||
};
|
||
|
||
exports.install = function (handle) {
|
||
var called = 0;
|
||
var observer = new Mutation(handle);
|
||
var element = global.document.createTextNode('');
|
||
observer.observe(element, {
|
||
characterData: true
|
||
});
|
||
return function () {
|
||
element.data = (called = ++called % 2);
|
||
};
|
||
};
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
|
||
|
||
/***/ }),
|
||
/* 56 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
/* WEBPACK VAR INJECTION */(function(global) {
|
||
|
||
exports.test = function () {
|
||
if (global.setImmediate) {
|
||
// we can only get here in IE10
|
||
// which doesn't handel postMessage well
|
||
return false;
|
||
}
|
||
return typeof global.MessageChannel !== 'undefined';
|
||
};
|
||
|
||
exports.install = function (func) {
|
||
var channel = new global.MessageChannel();
|
||
channel.port1.onmessage = func;
|
||
return function () {
|
||
channel.port2.postMessage(0);
|
||
};
|
||
};
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
|
||
|
||
/***/ }),
|
||
/* 57 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
/* WEBPACK VAR INJECTION */(function(global) {
|
||
|
||
exports.test = function () {
|
||
return 'document' in global && 'onreadystatechange' in global.document.createElement('script');
|
||
};
|
||
|
||
exports.install = function (handle) {
|
||
return function () {
|
||
|
||
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
|
||
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
|
||
var scriptEl = global.document.createElement('script');
|
||
scriptEl.onreadystatechange = function () {
|
||
handle();
|
||
|
||
scriptEl.onreadystatechange = null;
|
||
scriptEl.parentNode.removeChild(scriptEl);
|
||
scriptEl = null;
|
||
};
|
||
global.document.documentElement.appendChild(scriptEl);
|
||
|
||
return handle;
|
||
};
|
||
};
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
|
||
|
||
/***/ }),
|
||
/* 58 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
exports.test = function () {
|
||
return true;
|
||
};
|
||
|
||
exports.install = function (t) {
|
||
return function () {
|
||
setTimeout(t, 0);
|
||
};
|
||
};
|
||
|
||
/***/ }),
|
||
/* 59 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var _ = __webpack_require__(0);
|
||
var DOM = __webpack_require__(1);
|
||
var EventEmitter = __webpack_require__(10);
|
||
var Dataset = __webpack_require__(60);
|
||
var css = __webpack_require__(11);
|
||
|
||
// constructor
|
||
// -----------
|
||
|
||
function Dropdown(o) {
|
||
var that = this;
|
||
var onSuggestionClick;
|
||
var onSuggestionMouseEnter;
|
||
var onSuggestionMouseLeave;
|
||
|
||
o = o || {};
|
||
|
||
if (!o.menu) {
|
||
_.error('menu is required');
|
||
}
|
||
|
||
if (!_.isArray(o.datasets) && !_.isObject(o.datasets)) {
|
||
_.error('1 or more datasets required');
|
||
}
|
||
if (!o.datasets) {
|
||
_.error('datasets is required');
|
||
}
|
||
|
||
this.isOpen = false;
|
||
this.isEmpty = true;
|
||
this.minLength = o.minLength || 0;
|
||
this.templates = {};
|
||
this.appendTo = o.appendTo || false;
|
||
this.css = _.mixin({}, css, o.appendTo ? css.appendTo : {});
|
||
this.cssClasses = o.cssClasses = _.mixin({}, css.defaultClasses, o.cssClasses || {});
|
||
this.cssClasses.prefix =
|
||
o.cssClasses.formattedPrefix || _.formatPrefix(this.cssClasses.prefix, this.cssClasses.noPrefix);
|
||
|
||
// bound functions
|
||
onSuggestionClick = _.bind(this._onSuggestionClick, this);
|
||
onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);
|
||
onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);
|
||
|
||
var cssClass = _.className(this.cssClasses.prefix, this.cssClasses.suggestion);
|
||
this.$menu = DOM.element(o.menu)
|
||
.on('mouseenter.aa', cssClass, onSuggestionMouseEnter)
|
||
.on('mouseleave.aa', cssClass, onSuggestionMouseLeave)
|
||
.on('click.aa', cssClass, onSuggestionClick);
|
||
|
||
this.$container = o.appendTo ? o.wrapper : this.$menu;
|
||
|
||
if (o.templates && o.templates.header) {
|
||
this.templates.header = _.templatify(o.templates.header);
|
||
this.$menu.prepend(this.templates.header());
|
||
}
|
||
|
||
if (o.templates && o.templates.empty) {
|
||
this.templates.empty = _.templatify(o.templates.empty);
|
||
this.$empty = DOM.element('<div class="' +
|
||
_.className(this.cssClasses.prefix, this.cssClasses.empty, true) + '">' +
|
||
'</div>');
|
||
this.$menu.append(this.$empty);
|
||
this.$empty.hide();
|
||
}
|
||
|
||
this.datasets = _.map(o.datasets, function(oDataset) {
|
||
return initializeDataset(that.$menu, oDataset, o.cssClasses);
|
||
});
|
||
_.each(this.datasets, function(dataset) {
|
||
var root = dataset.getRoot();
|
||
if (root && root.parent().length === 0) {
|
||
that.$menu.append(root);
|
||
}
|
||
dataset.onSync('rendered', that._onRendered, that);
|
||
});
|
||
|
||
if (o.templates && o.templates.footer) {
|
||
this.templates.footer = _.templatify(o.templates.footer);
|
||
this.$menu.append(this.templates.footer());
|
||
}
|
||
|
||
var self = this;
|
||
DOM.element(window).resize(function() {
|
||
self._redraw();
|
||
});
|
||
}
|
||
|
||
// instance methods
|
||
// ----------------
|
||
|
||
_.mixin(Dropdown.prototype, EventEmitter, {
|
||
|
||
// ### private
|
||
|
||
_onSuggestionClick: function onSuggestionClick($e) {
|
||
this.trigger('suggestionClicked', DOM.element($e.currentTarget));
|
||
},
|
||
|
||
_onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {
|
||
var elt = DOM.element($e.currentTarget);
|
||
if (elt.hasClass(_.className(this.cssClasses.prefix, this.cssClasses.cursor, true))) {
|
||
// we're already on the cursor
|
||
// => we're probably entering it again after leaving it for a nested div
|
||
return;
|
||
}
|
||
this._removeCursor();
|
||
|
||
// Fixes iOS double tap behaviour, by modifying the DOM right before the
|
||
// native href clicks happens, iOS will requires another tap to follow
|
||
// a suggestion that has an <a href> element inside
|
||
// https://www.google.com/search?q=ios+double+tap+bug+href
|
||
var suggestion = this;
|
||
setTimeout(function() {
|
||
// this exact line, when inside the main loop, will trigger a double tap bug
|
||
// on iOS devices
|
||
suggestion._setCursor(elt, false);
|
||
}, 0);
|
||
},
|
||
|
||
_onSuggestionMouseLeave: function onSuggestionMouseLeave($e) {
|
||
// $e.relatedTarget is the `EventTarget` the pointing device entered to
|
||
if ($e.relatedTarget) {
|
||
var elt = DOM.element($e.relatedTarget);
|
||
if (elt.closest('.' + _.className(this.cssClasses.prefix, this.cssClasses.cursor, true)).length > 0) {
|
||
// our father is a cursor
|
||
// => it means we're just leaving the suggestion for a nested div
|
||
return;
|
||
}
|
||
}
|
||
this._removeCursor();
|
||
this.trigger('cursorRemoved');
|
||
},
|
||
|
||
_onRendered: function onRendered(e, query) {
|
||
this.isEmpty = _.every(this.datasets, isDatasetEmpty);
|
||
|
||
if (this.isEmpty) {
|
||
if (query.length >= this.minLength) {
|
||
this.trigger('empty');
|
||
}
|
||
|
||
if (this.$empty) {
|
||
if (query.length < this.minLength) {
|
||
this._hide();
|
||
} else {
|
||
var html = this.templates.empty({
|
||
query: this.datasets[0] && this.datasets[0].query
|
||
});
|
||
this.$empty.html(html);
|
||
this.$empty.show();
|
||
this._show();
|
||
}
|
||
} else if (_.any(this.datasets, hasEmptyTemplate)) {
|
||
if (query.length < this.minLength) {
|
||
this._hide();
|
||
} else {
|
||
this._show();
|
||
}
|
||
} else {
|
||
this._hide();
|
||
}
|
||
} else if (this.isOpen) {
|
||
if (this.$empty) {
|
||
this.$empty.empty();
|
||
this.$empty.hide();
|
||
}
|
||
|
||
if (query.length >= this.minLength) {
|
||
this._show();
|
||
} else {
|
||
this._hide();
|
||
}
|
||
}
|
||
|
||
this.trigger('datasetRendered');
|
||
|
||
function isDatasetEmpty(dataset) {
|
||
return dataset.isEmpty();
|
||
}
|
||
|
||
function hasEmptyTemplate(dataset) {
|
||
return dataset.templates && dataset.templates.empty;
|
||
}
|
||
},
|
||
|
||
_hide: function() {
|
||
this.$container.hide();
|
||
},
|
||
|
||
_show: function() {
|
||
// can't use jQuery#show because $menu is a span element we want
|
||
// display: block; not dislay: inline;
|
||
this.$container.css('display', 'block');
|
||
|
||
this._redraw();
|
||
|
||
this.trigger('shown');
|
||
},
|
||
|
||
_redraw: function redraw() {
|
||
if (!this.isOpen || !this.appendTo) return;
|
||
|
||
this.trigger('redrawn');
|
||
},
|
||
|
||
_getSuggestions: function getSuggestions() {
|
||
return this.$menu.find(_.className(this.cssClasses.prefix, this.cssClasses.suggestion));
|
||
},
|
||
|
||
_getCursor: function getCursor() {
|
||
return this.$menu.find(_.className(this.cssClasses.prefix, this.cssClasses.cursor)).first();
|
||
},
|
||
|
||
_setCursor: function setCursor($el, updateInput) {
|
||
$el.first()
|
||
.addClass(_.className(this.cssClasses.prefix, this.cssClasses.cursor, true))
|
||
.attr('aria-selected', 'true');
|
||
this.trigger('cursorMoved', updateInput);
|
||
},
|
||
|
||
_removeCursor: function removeCursor() {
|
||
this._getCursor()
|
||
.removeClass(_.className(this.cssClasses.prefix, this.cssClasses.cursor, true))
|
||
.removeAttr('aria-selected');
|
||
},
|
||
|
||
_moveCursor: function moveCursor(increment) {
|
||
var $suggestions;
|
||
var $oldCursor;
|
||
var newCursorIndex;
|
||
var $newCursor;
|
||
|
||
if (!this.isOpen) {
|
||
return;
|
||
}
|
||
|
||
$oldCursor = this._getCursor();
|
||
$suggestions = this._getSuggestions();
|
||
|
||
this._removeCursor();
|
||
|
||
// shifting before and after modulo to deal with -1 index
|
||
newCursorIndex = $suggestions.index($oldCursor) + increment;
|
||
newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;
|
||
|
||
if (newCursorIndex === -1) {
|
||
this.trigger('cursorRemoved');
|
||
|
||
return;
|
||
} else if (newCursorIndex < -1) {
|
||
newCursorIndex = $suggestions.length - 1;
|
||
}
|
||
|
||
this._setCursor($newCursor = $suggestions.eq(newCursorIndex), true);
|
||
|
||
// in the case of scrollable overflow
|
||
// make sure the cursor is visible in the menu
|
||
this._ensureVisible($newCursor);
|
||
},
|
||
|
||
_ensureVisible: function ensureVisible($el) {
|
||
var elTop;
|
||
var elBottom;
|
||
var menuScrollTop;
|
||
var menuHeight;
|
||
|
||
elTop = $el.position().top;
|
||
elBottom = elTop + $el.height() +
|
||
parseInt($el.css('margin-top'), 10) +
|
||
parseInt($el.css('margin-bottom'), 10);
|
||
menuScrollTop = this.$menu.scrollTop();
|
||
menuHeight = this.$menu.height() +
|
||
parseInt(this.$menu.css('padding-top'), 10) +
|
||
parseInt(this.$menu.css('padding-bottom'), 10);
|
||
|
||
if (elTop < 0) {
|
||
this.$menu.scrollTop(menuScrollTop + elTop);
|
||
} else if (menuHeight < elBottom) {
|
||
this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));
|
||
}
|
||
},
|
||
|
||
// ### public
|
||
|
||
close: function close() {
|
||
if (this.isOpen) {
|
||
this.isOpen = false;
|
||
|
||
this._removeCursor();
|
||
this._hide();
|
||
|
||
this.trigger('closed');
|
||
}
|
||
},
|
||
|
||
open: function open() {
|
||
if (!this.isOpen) {
|
||
this.isOpen = true;
|
||
|
||
if (!this.isEmpty) {
|
||
this._show();
|
||
}
|
||
|
||
this.trigger('opened');
|
||
}
|
||
},
|
||
|
||
setLanguageDirection: function setLanguageDirection(dir) {
|
||
this.$menu.css(dir === 'ltr' ? this.css.ltr : this.css.rtl);
|
||
},
|
||
|
||
moveCursorUp: function moveCursorUp() {
|
||
this._moveCursor(-1);
|
||
},
|
||
|
||
moveCursorDown: function moveCursorDown() {
|
||
this._moveCursor(+1);
|
||
},
|
||
|
||
getDatumForSuggestion: function getDatumForSuggestion($el) {
|
||
var datum = null;
|
||
|
||
if ($el.length) {
|
||
datum = {
|
||
raw: Dataset.extractDatum($el),
|
||
value: Dataset.extractValue($el),
|
||
datasetName: Dataset.extractDatasetName($el)
|
||
};
|
||
}
|
||
|
||
return datum;
|
||
},
|
||
|
||
getCurrentCursor: function getCurrentCursor() {
|
||
return this._getCursor().first();
|
||
},
|
||
|
||
getDatumForCursor: function getDatumForCursor() {
|
||
return this.getDatumForSuggestion(this._getCursor().first());
|
||
},
|
||
|
||
getDatumForTopSuggestion: function getDatumForTopSuggestion() {
|
||
return this.getDatumForSuggestion(this._getSuggestions().first());
|
||
},
|
||
|
||
cursorTopSuggestion: function cursorTopSuggestion() {
|
||
this._setCursor(this._getSuggestions().first(), false);
|
||
},
|
||
|
||
update: function update(query) {
|
||
_.each(this.datasets, updateDataset);
|
||
|
||
function updateDataset(dataset) {
|
||
dataset.update(query);
|
||
}
|
||
},
|
||
|
||
empty: function empty() {
|
||
_.each(this.datasets, clearDataset);
|
||
this.isEmpty = true;
|
||
|
||
function clearDataset(dataset) {
|
||
dataset.clear();
|
||
}
|
||
},
|
||
|
||
isVisible: function isVisible() {
|
||
return this.isOpen && !this.isEmpty;
|
||
},
|
||
|
||
destroy: function destroy() {
|
||
this.$menu.off('.aa');
|
||
|
||
this.$menu = null;
|
||
|
||
_.each(this.datasets, destroyDataset);
|
||
|
||
function destroyDataset(dataset) {
|
||
dataset.destroy();
|
||
}
|
||
}
|
||
});
|
||
|
||
// helper functions
|
||
// ----------------
|
||
Dropdown.Dataset = Dataset;
|
||
|
||
function initializeDataset($menu, oDataset, cssClasses) {
|
||
return new Dropdown.Dataset(_.mixin({$menu: $menu, cssClasses: cssClasses}, oDataset));
|
||
}
|
||
|
||
module.exports = Dropdown;
|
||
|
||
|
||
/***/ }),
|
||
/* 60 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var datasetKey = 'aaDataset';
|
||
var valueKey = 'aaValue';
|
||
var datumKey = 'aaDatum';
|
||
|
||
var _ = __webpack_require__(0);
|
||
var DOM = __webpack_require__(1);
|
||
var html = __webpack_require__(17);
|
||
var css = __webpack_require__(11);
|
||
var EventEmitter = __webpack_require__(10);
|
||
|
||
// constructor
|
||
// -----------
|
||
|
||
function Dataset(o) {
|
||
o = o || {};
|
||
o.templates = o.templates || {};
|
||
|
||
if (!o.source) {
|
||
_.error('missing source');
|
||
}
|
||
|
||
if (o.name && !isValidName(o.name)) {
|
||
_.error('invalid dataset name: ' + o.name);
|
||
}
|
||
|
||
// tracks the last query the dataset was updated for
|
||
this.query = null;
|
||
this._isEmpty = true;
|
||
|
||
this.highlight = !!o.highlight;
|
||
this.name = typeof o.name === 'undefined' || o.name === null ? _.getUniqueId() : o.name;
|
||
|
||
this.source = o.source;
|
||
this.displayFn = getDisplayFn(o.display || o.displayKey);
|
||
|
||
this.debounce = o.debounce;
|
||
|
||
this.cache = o.cache !== false;
|
||
|
||
this.templates = getTemplates(o.templates, this.displayFn);
|
||
|
||
this.css = _.mixin({}, css, o.appendTo ? css.appendTo : {});
|
||
this.cssClasses = o.cssClasses = _.mixin({}, css.defaultClasses, o.cssClasses || {});
|
||
this.cssClasses.prefix =
|
||
o.cssClasses.formattedPrefix || _.formatPrefix(this.cssClasses.prefix, this.cssClasses.noPrefix);
|
||
|
||
var clazz = _.className(this.cssClasses.prefix, this.cssClasses.dataset);
|
||
this.$el = o.$menu && o.$menu.find(clazz + '-' + this.name).length > 0 ?
|
||
DOM.element(o.$menu.find(clazz + '-' + this.name)[0]) :
|
||
DOM.element(
|
||
html.dataset.replace('%CLASS%', this.name)
|
||
.replace('%PREFIX%', this.cssClasses.prefix)
|
||
.replace('%DATASET%', this.cssClasses.dataset)
|
||
);
|
||
|
||
this.$menu = o.$menu;
|
||
this.clearCachedSuggestions();
|
||
}
|
||
|
||
// static methods
|
||
// --------------
|
||
|
||
Dataset.extractDatasetName = function extractDatasetName(el) {
|
||
return DOM.element(el).data(datasetKey);
|
||
};
|
||
|
||
Dataset.extractValue = function extractValue(el) {
|
||
return DOM.element(el).data(valueKey);
|
||
};
|
||
|
||
Dataset.extractDatum = function extractDatum(el) {
|
||
var datum = DOM.element(el).data(datumKey);
|
||
if (typeof datum === 'string') {
|
||
// Zepto has an automatic deserialization of the
|
||
// JSON encoded data attribute
|
||
datum = JSON.parse(datum);
|
||
}
|
||
return datum;
|
||
};
|
||
|
||
// instance methods
|
||
// ----------------
|
||
|
||
_.mixin(Dataset.prototype, EventEmitter, {
|
||
|
||
// ### private
|
||
|
||
_render: function render(query, suggestions) {
|
||
if (!this.$el) {
|
||
return;
|
||
}
|
||
var that = this;
|
||
|
||
var hasSuggestions;
|
||
var renderArgs = [].slice.call(arguments, 2);
|
||
this.$el.empty();
|
||
|
||
hasSuggestions = suggestions && suggestions.length;
|
||
this._isEmpty = !hasSuggestions;
|
||
|
||
if (!hasSuggestions && this.templates.empty) {
|
||
this.$el
|
||
.html(getEmptyHtml.apply(this, renderArgs))
|
||
.prepend(that.templates.header ? getHeaderHtml.apply(this, renderArgs) : null)
|
||
.append(that.templates.footer ? getFooterHtml.apply(this, renderArgs) : null);
|
||
} else if (hasSuggestions) {
|
||
this.$el
|
||
.html(getSuggestionsHtml.apply(this, renderArgs))
|
||
.prepend(that.templates.header ? getHeaderHtml.apply(this, renderArgs) : null)
|
||
.append(that.templates.footer ? getFooterHtml.apply(this, renderArgs) : null);
|
||
} else if (suggestions && !Array.isArray(suggestions)) {
|
||
throw new TypeError('suggestions must be an array');
|
||
}
|
||
|
||
if (this.$menu) {
|
||
this.$menu.addClass(
|
||
this.cssClasses.prefix + (hasSuggestions ? 'with' : 'without') + '-' + this.name
|
||
).removeClass(
|
||
this.cssClasses.prefix + (hasSuggestions ? 'without' : 'with') + '-' + this.name
|
||
);
|
||
}
|
||
|
||
this.trigger('rendered', query);
|
||
|
||
function getEmptyHtml() {
|
||
var args = [].slice.call(arguments, 0);
|
||
args = [{query: query, isEmpty: true}].concat(args);
|
||
return that.templates.empty.apply(this, args);
|
||
}
|
||
|
||
function getSuggestionsHtml() {
|
||
var args = [].slice.call(arguments, 0);
|
||
var $suggestions;
|
||
var nodes;
|
||
var self = this;
|
||
|
||
var suggestionsHtml = html.suggestions.
|
||
replace('%PREFIX%', this.cssClasses.prefix).
|
||
replace('%SUGGESTIONS%', this.cssClasses.suggestions);
|
||
$suggestions = DOM
|
||
.element(suggestionsHtml)
|
||
.css(this.css.suggestions);
|
||
|
||
// jQuery#append doesn't support arrays as the first argument
|
||
// until version 1.8, see http://bugs.jquery.com/ticket/11231
|
||
nodes = _.map(suggestions, getSuggestionNode);
|
||
$suggestions.append.apply($suggestions, nodes);
|
||
|
||
return $suggestions;
|
||
|
||
function getSuggestionNode(suggestion) {
|
||
var $el;
|
||
|
||
var suggestionHtml = html.suggestion.
|
||
replace('%PREFIX%', self.cssClasses.prefix).
|
||
replace('%SUGGESTION%', self.cssClasses.suggestion);
|
||
$el = DOM.element(suggestionHtml)
|
||
.attr({
|
||
role: 'option',
|
||
id: ['option', Math.floor(Math.random() * 100000000)].join('-')
|
||
})
|
||
.append(that.templates.suggestion.apply(this, [suggestion].concat(args)));
|
||
|
||
$el.data(datasetKey, that.name);
|
||
$el.data(valueKey, that.displayFn(suggestion) || undefined); // this led to undefined return value
|
||
$el.data(datumKey, JSON.stringify(suggestion));
|
||
$el.children().each(function() { DOM.element(this).css(self.css.suggestionChild); });
|
||
|
||
return $el;
|
||
}
|
||
}
|
||
|
||
function getHeaderHtml() {
|
||
var args = [].slice.call(arguments, 0);
|
||
args = [{query: query, isEmpty: !hasSuggestions}].concat(args);
|
||
return that.templates.header.apply(this, args);
|
||
}
|
||
|
||
function getFooterHtml() {
|
||
var args = [].slice.call(arguments, 0);
|
||
args = [{query: query, isEmpty: !hasSuggestions}].concat(args);
|
||
return that.templates.footer.apply(this, args);
|
||
}
|
||
},
|
||
|
||
// ### public
|
||
|
||
getRoot: function getRoot() {
|
||
return this.$el;
|
||
},
|
||
|
||
update: function update(query) {
|
||
function handleSuggestions(suggestions) {
|
||
// if the update has been canceled or if the query has changed
|
||
// do not render the suggestions as they've become outdated
|
||
if (!this.canceled && query === this.query) {
|
||
// concat all the other arguments that could have been passed
|
||
// to the render function, and forward them to _render
|
||
var extraArgs = [].slice.call(arguments, 1);
|
||
this.cacheSuggestions(query, suggestions, extraArgs);
|
||
this._render.apply(this, [query, suggestions].concat(extraArgs));
|
||
}
|
||
}
|
||
|
||
this.query = query;
|
||
this.canceled = false;
|
||
|
||
if (this.shouldFetchFromCache(query)) {
|
||
handleSuggestions.apply(this, [this.cachedSuggestions].concat(this.cachedRenderExtraArgs));
|
||
} else {
|
||
var that = this;
|
||
var execSource = function() {
|
||
// When the call is debounced the condition avoid to do a useless
|
||
// request with the last character when the input has been cleared
|
||
if (!that.canceled) {
|
||
that.source(query, handleSuggestions.bind(that));
|
||
}
|
||
};
|
||
|
||
if (this.debounce) {
|
||
var later = function() {
|
||
that.debounceTimeout = null;
|
||
execSource();
|
||
};
|
||
clearTimeout(this.debounceTimeout);
|
||
this.debounceTimeout = setTimeout(later, this.debounce);
|
||
} else {
|
||
execSource();
|
||
}
|
||
}
|
||
},
|
||
|
||
cacheSuggestions: function cacheSuggestions(query, suggestions, extraArgs) {
|
||
this.cachedQuery = query;
|
||
this.cachedSuggestions = suggestions;
|
||
this.cachedRenderExtraArgs = extraArgs;
|
||
},
|
||
|
||
shouldFetchFromCache: function shouldFetchFromCache(query) {
|
||
return this.cache &&
|
||
this.cachedQuery === query &&
|
||
this.cachedSuggestions &&
|
||
this.cachedSuggestions.length;
|
||
},
|
||
|
||
clearCachedSuggestions: function clearCachedSuggestions() {
|
||
delete this.cachedQuery;
|
||
delete this.cachedSuggestions;
|
||
delete this.cachedRenderExtraArgs;
|
||
},
|
||
|
||
cancel: function cancel() {
|
||
this.canceled = true;
|
||
},
|
||
|
||
clear: function clear() {
|
||
this.cancel();
|
||
this.$el.empty();
|
||
this.trigger('rendered', '');
|
||
},
|
||
|
||
isEmpty: function isEmpty() {
|
||
return this._isEmpty;
|
||
},
|
||
|
||
destroy: function destroy() {
|
||
this.clearCachedSuggestions();
|
||
this.$el = null;
|
||
}
|
||
});
|
||
|
||
// helper functions
|
||
// ----------------
|
||
|
||
function getDisplayFn(display) {
|
||
display = display || 'value';
|
||
|
||
return _.isFunction(display) ? display : displayFn;
|
||
|
||
function displayFn(obj) {
|
||
return obj[display];
|
||
}
|
||
}
|
||
|
||
function getTemplates(templates, displayFn) {
|
||
return {
|
||
empty: templates.empty && _.templatify(templates.empty),
|
||
header: templates.header && _.templatify(templates.header),
|
||
footer: templates.footer && _.templatify(templates.footer),
|
||
suggestion: templates.suggestion || suggestionTemplate
|
||
};
|
||
|
||
function suggestionTemplate(context) {
|
||
return '<p>' + displayFn(context) + '</p>';
|
||
}
|
||
}
|
||
|
||
function isValidName(str) {
|
||
// dashes, underscores, letters, and numbers
|
||
return (/^[_a-zA-Z0-9-]+$/).test(str);
|
||
}
|
||
|
||
module.exports = Dataset;
|
||
|
||
|
||
/***/ }),
|
||
/* 61 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
module.exports = {
|
||
hits: __webpack_require__(62),
|
||
popularIn: __webpack_require__(63)
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 62 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var _ = __webpack_require__(0);
|
||
var version = __webpack_require__(18);
|
||
var parseAlgoliaClientVersion = __webpack_require__(19);
|
||
|
||
module.exports = function search(index, params) {
|
||
var algoliaVersion = parseAlgoliaClientVersion(index.as._ua);
|
||
if (algoliaVersion && algoliaVersion[0] >= 3 && algoliaVersion[1] > 20) {
|
||
params = params || {};
|
||
params.additionalUA = 'autocomplete.js ' + version;
|
||
}
|
||
return sourceFn;
|
||
|
||
function sourceFn(query, cb) {
|
||
index.search(query, params, function(error, content) {
|
||
if (error) {
|
||
_.error(error.message);
|
||
return;
|
||
}
|
||
cb(content.hits, content);
|
||
});
|
||
}
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 63 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
var _ = __webpack_require__(0);
|
||
var version = __webpack_require__(18);
|
||
var parseAlgoliaClientVersion = __webpack_require__(19);
|
||
|
||
module.exports = function popularIn(index, params, details, options) {
|
||
var algoliaVersion = parseAlgoliaClientVersion(index.as._ua);
|
||
if (algoliaVersion && algoliaVersion[0] >= 3 && algoliaVersion[1] > 20) {
|
||
params = params || {};
|
||
params.additionalUA = 'autocomplete.js ' + version;
|
||
}
|
||
if (!details.source) {
|
||
return _.error("Missing 'source' key");
|
||
}
|
||
var source = _.isFunction(details.source) ? details.source : function(hit) { return hit[details.source]; };
|
||
|
||
if (!details.index) {
|
||
return _.error("Missing 'index' key");
|
||
}
|
||
var detailsIndex = details.index;
|
||
|
||
options = options || {};
|
||
|
||
return sourceFn;
|
||
|
||
function sourceFn(query, cb) {
|
||
index.search(query, params, function(error, content) {
|
||
if (error) {
|
||
_.error(error.message);
|
||
return;
|
||
}
|
||
|
||
if (content.hits.length > 0) {
|
||
var first = content.hits[0];
|
||
|
||
var detailsParams = _.mixin({hitsPerPage: 0}, details);
|
||
delete detailsParams.source; // not a query parameter
|
||
delete detailsParams.index; // not a query parameter
|
||
|
||
var detailsAlgoliaVersion = parseAlgoliaClientVersion(detailsIndex.as._ua);
|
||
if (detailsAlgoliaVersion && detailsAlgoliaVersion[0] >= 3 && detailsAlgoliaVersion[1] > 20) {
|
||
params.additionalUA = 'autocomplete.js ' + version;
|
||
}
|
||
|
||
detailsIndex.search(source(first), detailsParams, function(error2, content2) {
|
||
if (error2) {
|
||
_.error(error2.message);
|
||
return;
|
||
}
|
||
|
||
var suggestions = [];
|
||
|
||
// add the 'all department' entry before others
|
||
if (options.includeAll) {
|
||
var label = options.allTitle || 'All departments';
|
||
suggestions.push(_.mixin({
|
||
facet: {value: label, count: content2.nbHits}
|
||
}, _.cloneDeep(first)));
|
||
}
|
||
|
||
// enrich the first hit iterating over the facets
|
||
_.each(content2.facets, function(values, facet) {
|
||
_.each(values, function(count, value) {
|
||
suggestions.push(_.mixin({
|
||
facet: {facet: facet, value: value, count: count}
|
||
}, _.cloneDeep(first)));
|
||
});
|
||
});
|
||
|
||
// append all other hits
|
||
for (var i = 1; i < content.hits.length; ++i) {
|
||
suggestions.push(content.hits[i]);
|
||
}
|
||
|
||
cb(suggestions, content);
|
||
});
|
||
|
||
return;
|
||
}
|
||
|
||
cb([]);
|
||
});
|
||
}
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
/* 64 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
Object.defineProperty(exports, "__esModule", {
|
||
value: true
|
||
});
|
||
var prefix = 'algolia-docsearch';
|
||
var suggestionPrefix = prefix + '-suggestion';
|
||
var footerPrefix = prefix + '-footer';
|
||
|
||
/* eslint-disable max-len */
|
||
|
||
var templates = {
|
||
suggestion: '\n <a class="' + suggestionPrefix + '\n {{#isCategoryHeader}}' + suggestionPrefix + '__main{{/isCategoryHeader}}\n {{#isSubCategoryHeader}}' + suggestionPrefix + '__secondary{{/isSubCategoryHeader}}\n "\n aria-label="Link to the result"\n href="{{{url}}}"\n >\n <div class="' + suggestionPrefix + '--category-header">\n <span class="' + suggestionPrefix + '--category-header-lvl0">{{{category}}}</span>\n </div>\n <div class="' + suggestionPrefix + '--wrapper">\n <div class="' + suggestionPrefix + '--subcategory-column">\n <span class="' + suggestionPrefix + '--subcategory-column-text">{{{subcategory}}}</span>\n </div>\n {{#isTextOrSubcategoryNonEmpty}}\n <div class="' + suggestionPrefix + '--content">\n <div class="' + suggestionPrefix + '--subcategory-inline">{{{subcategory}}}</div>\n <div class="' + suggestionPrefix + '--title">{{{title}}}</div>\n {{#text}}<div class="' + suggestionPrefix + '--text">{{{text}}}</div>{{/text}}\n </div>\n {{/isTextOrSubcategoryNonEmpty}}\n </div>\n </a>\n ',
|
||
suggestionSimple: '\n <div class="' + suggestionPrefix + '\n {{#isCategoryHeader}}' + suggestionPrefix + '__main{{/isCategoryHeader}}\n {{#isSubCategoryHeader}}' + suggestionPrefix + '__secondary{{/isSubCategoryHeader}}\n suggestion-layout-simple\n ">\n <div class="' + suggestionPrefix + '--category-header">\n {{^isLvl0}}\n <span class="' + suggestionPrefix + '--category-header-lvl0 ' + suggestionPrefix + '--category-header-item">{{{category}}}</span>\n {{^isLvl1}}\n {{^isLvl1EmptyOrDuplicate}}\n <span class="' + suggestionPrefix + '--category-header-lvl1 ' + suggestionPrefix + '--category-header-item">\n {{{subcategory}}}\n </span>\n {{/isLvl1EmptyOrDuplicate}}\n {{/isLvl1}}\n {{/isLvl0}}\n <div class="' + suggestionPrefix + '--title ' + suggestionPrefix + '--category-header-item">\n {{#isLvl2}}\n {{{title}}}\n {{/isLvl2}}\n {{#isLvl1}}\n {{{subcategory}}}\n {{/isLvl1}}\n {{#isLvl0}}\n {{{category}}}\n {{/isLvl0}}\n </div>\n </div>\n <div class="' + suggestionPrefix + '--wrapper">\n {{#text}}\n <div class="' + suggestionPrefix + '--content">\n <div class="' + suggestionPrefix + '--text">{{{text}}}</div>\n </div>\n {{/text}}\n </div>\n </div>\n ',
|
||
footer: '\n <div class="' + footerPrefix + '">\n Search by <a class="' + footerPrefix + '--logo" href="https://www.algolia.com/docsearch">Algolia</a>\n </div>\n ',
|
||
empty: '\n <div class="' + suggestionPrefix + '">\n <div class="' + suggestionPrefix + '--wrapper">\n <div class="' + suggestionPrefix + '--content ' + suggestionPrefix + '--no-results">\n <div class="' + suggestionPrefix + '--title">\n <div class="' + suggestionPrefix + '--text">\n No results found for query <b>"{{query}}"</b>\n </div>\n </div>\n </div>\n </div>\n </div>\n ',
|
||
searchBox: '\n <form novalidate="novalidate" onsubmit="return false;" class="searchbox">\n <div role="search" class="searchbox__wrapper">\n <input id="docsearch" type="search" name="search" placeholder="Search the docs" autocomplete="off" required="required" class="searchbox__input"/>\n <button type="submit" title="Submit your search query." class="searchbox__submit" >\n <svg width=12 height=12 role="img" aria-label="Search">\n <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-search-13"></use>\n </svg>\n </button>\n <button type="reset" title="Clear the search query." class="searchbox__reset hide">\n <svg width=12 height=12 role="img" aria-label="Reset">\n <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-clear-3"></use>\n </svg>\n </button>\n </div>\n</form>\n\n<div class="svg-icons" style="height: 0; width: 0; position: absolute; visibility: hidden">\n <svg xmlns="http://www.w3.org/2000/svg">\n <symbol id="sbx-icon-clear-3" viewBox="0 0 40 40"><path d="M16.228 20L1.886 5.657 0 3.772 3.772 0l1.885 1.886L20 16.228 34.343 1.886 36.228 0 40 3.772l-1.886 1.885L23.772 20l14.342 14.343L40 36.228 36.228 40l-1.885-1.886L20 23.772 5.657 38.114 3.772 40 0 36.228l1.886-1.885L16.228 20z" fill-rule="evenodd"></symbol>\n <symbol id="sbx-icon-search-13" viewBox="0 0 40 40"><path d="M26.806 29.012a16.312 16.312 0 0 1-10.427 3.746C7.332 32.758 0 25.425 0 16.378 0 7.334 7.333 0 16.38 0c9.045 0 16.378 7.333 16.378 16.38 0 3.96-1.406 7.593-3.746 10.426L39.547 37.34c.607.608.61 1.59-.004 2.203a1.56 1.56 0 0 1-2.202.004L26.807 29.012zm-10.427.627c7.322 0 13.26-5.938 13.26-13.26 0-7.324-5.938-13.26-13.26-13.26-7.324 0-13.26 5.936-13.26 13.26 0 7.322 5.936 13.26 13.26 13.26z" fill-rule="evenodd"></symbol>\n </svg>\n</div>\n '
|
||
};
|
||
|
||
exports.default = templates;
|
||
|
||
/***/ }),
|
||
/* 65 */
|
||
/***/ (function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
|
||
Object.defineProperty(exports, "__esModule", {
|
||
value: true
|
||
});
|
||
|
||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
||
|
||
var _zepto = __webpack_require__(20);
|
||
|
||
var _zepto2 = _interopRequireDefault(_zepto);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var utils = {
|
||
/*
|
||
* Move the content of an object key one level higher.
|
||
* eg.
|
||
* {
|
||
* name: 'My name',
|
||
* hierarchy: {
|
||
* lvl0: 'Foo',
|
||
* lvl1: 'Bar'
|
||
* }
|
||
* }
|
||
* Will be converted to
|
||
* {
|
||
* name: 'My name',
|
||
* lvl0: 'Foo',
|
||
* lvl1: 'Bar'
|
||
* }
|
||
* @param {Object} object Main object
|
||
* @param {String} property Main object key to move up
|
||
* @return {Object}
|
||
* @throws Error when key is not an attribute of Object or is not an object itself
|
||
*/
|
||
mergeKeyWithParent: function mergeKeyWithParent(object, property) {
|
||
if (object[property] === undefined) {
|
||
return object;
|
||
}
|
||
if (_typeof(object[property]) !== 'object') {
|
||
return object;
|
||
}
|
||
var newObject = _zepto2.default.extend({}, object, object[property]);
|
||
delete newObject[property];
|
||
return newObject;
|
||
},
|
||
|
||
/*
|
||
* Group all objects of a collection by the value of the specified attribute
|
||
* If the attribute is a string, use the lowercase form.
|
||
*
|
||
* eg.
|
||
* groupBy([
|
||
* {name: 'Tim', category: 'dev'},
|
||
* {name: 'Vincent', category: 'dev'},
|
||
* {name: 'Ben', category: 'sales'},
|
||
* {name: 'Jeremy', category: 'sales'},
|
||
* {name: 'AlexS', category: 'dev'},
|
||
* {name: 'AlexK', category: 'sales'}
|
||
* ], 'category');
|
||
* =>
|
||
* {
|
||
* 'devs': [
|
||
* {name: 'Tim', category: 'dev'},
|
||
* {name: 'Vincent', category: 'dev'},
|
||
* {name: 'AlexS', category: 'dev'}
|
||
* ],
|
||
* 'sales': [
|
||
* {name: 'Ben', category: 'sales'},
|
||
* {name: 'Jeremy', category: 'sales'},
|
||
* {name: 'AlexK', category: 'sales'}
|
||
* ]
|
||
* }
|
||
* @param {array} collection Array of objects to group
|
||
* @param {String} property The attribute on which apply the grouping
|
||
* @return {array}
|
||
* @throws Error when one of the element does not have the specified property
|
||
*/
|
||
groupBy: function groupBy(collection, property) {
|
||
var newCollection = {};
|
||
_zepto2.default.each(collection, function (index, item) {
|
||
if (item[property] === undefined) {
|
||
throw new Error('[groupBy]: Object has no key ' + property);
|
||
}
|
||
var key = item[property];
|
||
if (typeof key === 'string') {
|
||
key = key.toLowerCase();
|
||
}
|
||
// fix #171 the given data type of docsearch hits might be conflict with the properties of the native Object,
|
||
// such as the constructor, so we need to do this check.
|
||
if (!Object.prototype.hasOwnProperty.call(newCollection, key)) {
|
||
newCollection[key] = [];
|
||
}
|
||
newCollection[key].push(item);
|
||
});
|
||
return newCollection;
|
||
},
|
||
|
||
/*
|
||
* Return an array of all the values of the specified object
|
||
* eg.
|
||
* values({
|
||
* foo: 42,
|
||
* bar: true,
|
||
* baz: 'yep'
|
||
* })
|
||
* =>
|
||
* [42, true, yep]
|
||
* @param {object} object Object to extract values from
|
||
* @return {array}
|
||
*/
|
||
values: function values(object) {
|
||
return Object.keys(object).map(function (key) {
|
||
return object[key];
|
||
});
|
||
},
|
||
|
||
/*
|
||
* Flattens an array
|
||
* eg.
|
||
* flatten([1, 2, [3, 4], [5, 6]])
|
||
* =>
|
||
* [1, 2, 3, 4, 5, 6]
|
||
* @param {array} array Array to flatten
|
||
* @return {array}
|
||
*/
|
||
flatten: function flatten(array) {
|
||
var results = [];
|
||
array.forEach(function (value) {
|
||
if (!Array.isArray(value)) {
|
||
results.push(value);
|
||
return;
|
||
}
|
||
value.forEach(function (subvalue) {
|
||
results.push(subvalue);
|
||
});
|
||
});
|
||
return results;
|
||
},
|
||
|
||
/*
|
||
* Flatten all values of an object into an array, marking each first element of
|
||
* each group with a specific flag
|
||
* eg.
|
||
* flattenAndFlagFirst({
|
||
* 'devs': [
|
||
* {name: 'Tim', category: 'dev'},
|
||
* {name: 'Vincent', category: 'dev'},
|
||
* {name: 'AlexS', category: 'dev'}
|
||
* ],
|
||
* 'sales': [
|
||
* {name: 'Ben', category: 'sales'},
|
||
* {name: 'Jeremy', category: 'sales'},
|
||
* {name: 'AlexK', category: 'sales'}
|
||
* ]
|
||
* , 'isTop');
|
||
* =>
|
||
* [
|
||
* {name: 'Tim', category: 'dev', isTop: true},
|
||
* {name: 'Vincent', category: 'dev', isTop: false},
|
||
* {name: 'AlexS', category: 'dev', isTop: false},
|
||
* {name: 'Ben', category: 'sales', isTop: true},
|
||
* {name: 'Jeremy', category: 'sales', isTop: false},
|
||
* {name: 'AlexK', category: 'sales', isTop: false}
|
||
* ]
|
||
* @param {object} object Object to flatten
|
||
* @param {string} flag Flag to set to true on first element of each group
|
||
* @return {array}
|
||
*/
|
||
flattenAndFlagFirst: function flattenAndFlagFirst(object, flag) {
|
||
var values = this.values(object).map(function (collection) {
|
||
return collection.map(function (item, index) {
|
||
// eslint-disable-next-line no-param-reassign
|
||
item[flag] = index === 0;
|
||
return item;
|
||
});
|
||
});
|
||
return this.flatten(values);
|
||
},
|
||
|
||
/*
|
||
* Removes all empty strings, null, false and undefined elements array
|
||
* eg.
|
||
* compact([42, false, null, undefined, '', [], 'foo']);
|
||
* =>
|
||
* [42, [], 'foo']
|
||
* @param {array} array Array to compact
|
||
* @return {array}
|
||
*/
|
||
compact: function compact(array) {
|
||
var results = [];
|
||
array.forEach(function (value) {
|
||
if (!value) {
|
||
return;
|
||
}
|
||
results.push(value);
|
||
});
|
||
return results;
|
||
},
|
||
|
||
/*
|
||
* Returns the highlighted value of the specified key in the specified object.
|
||
* If no highlighted value is available, will return the key value directly
|
||
* eg.
|
||
* getHighlightedValue({
|
||
* _highlightResult: {
|
||
* text: {
|
||
* value: '<mark>foo</mark>'
|
||
* }
|
||
* },
|
||
* text: 'foo'
|
||
* }, 'text');
|
||
* =>
|
||
* '<mark>foo</mark>'
|
||
* @param {object} object Hit object returned by the Algolia API
|
||
* @param {string} property Object key to look for
|
||
* @return {string}
|
||
**/
|
||
getHighlightedValue: function getHighlightedValue(object, property) {
|
||
if (object._highlightResult && object._highlightResult.hierarchy_camel && object._highlightResult.hierarchy_camel[property] && object._highlightResult.hierarchy_camel[property].matchLevel && object._highlightResult.hierarchy_camel[property].matchLevel !== 'none' && object._highlightResult.hierarchy_camel[property].value) {
|
||
return object._highlightResult.hierarchy_camel[property].value;
|
||
}
|
||
if (object._highlightResult && object._highlightResult && object._highlightResult[property] && object._highlightResult[property].value) {
|
||
return object._highlightResult[property].value;
|
||
}
|
||
return object[property];
|
||
},
|
||
|
||
/*
|
||
* Returns the snippeted value of the specified key in the specified object.
|
||
* If no highlighted value is available, will return the key value directly.
|
||
* Will add starting and ending ellipsis (…) if we detect that a sentence is
|
||
* incomplete
|
||
* eg.
|
||
* getSnippetedValue({
|
||
* _snippetResult: {
|
||
* text: {
|
||
* value: '<mark>This is an unfinished sentence</mark>'
|
||
* }
|
||
* },
|
||
* text: 'This is an unfinished sentence'
|
||
* }, 'text');
|
||
* =>
|
||
* '<mark>This is an unfinished sentence</mark>…'
|
||
* @param {object} object Hit object returned by the Algolia API
|
||
* @param {string} property Object key to look for
|
||
* @return {string}
|
||
**/
|
||
getSnippetedValue: function getSnippetedValue(object, property) {
|
||
if (!object._snippetResult || !object._snippetResult[property] || !object._snippetResult[property].value) {
|
||
return object[property];
|
||
}
|
||
var snippet = object._snippetResult[property].value;
|
||
|
||
if (snippet[0] !== snippet[0].toUpperCase()) {
|
||
snippet = '\u2026' + snippet;
|
||
}
|
||
if (['.', '!', '?'].indexOf(snippet[snippet.length - 1]) === -1) {
|
||
snippet = snippet + '\u2026';
|
||
}
|
||
return snippet;
|
||
},
|
||
|
||
/*
|
||
* Deep clone an object.
|
||
* Note: This will not clone functions and dates
|
||
* @param {object} object Object to clone
|
||
* @return {object}
|
||
*/
|
||
deepClone: function deepClone(object) {
|
||
return JSON.parse(JSON.stringify(object));
|
||
}
|
||
};
|
||
|
||
exports.default = utils;
|
||
|
||
/***/ })
|
||
/******/ ]);
|
||
});
|
||
//# sourceMappingURL=docsearch.js.map
|