mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-30 19:42:00 +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
|