[6a3a178] | 1 | /**
|
---|
| 2 | * lodash (Custom Build) <https://lodash.com/>
|
---|
| 3 | * Build: `lodash modularize exports="npm" -o ./`
|
---|
| 4 | * Copyright jQuery Foundation and other contributors <https://jquery.org/>
|
---|
| 5 | * Released under MIT license <https://lodash.com/license>
|
---|
| 6 | * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
---|
| 7 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
---|
| 8 | */
|
---|
| 9 |
|
---|
| 10 | /** Used as the `TypeError` message for "Functions" methods. */
|
---|
| 11 | var FUNC_ERROR_TEXT = 'Expected a function';
|
---|
| 12 |
|
---|
| 13 | /** Used as references for various `Number` constants. */
|
---|
| 14 | var NAN = 0 / 0;
|
---|
| 15 |
|
---|
| 16 | /** `Object#toString` result references. */
|
---|
| 17 | var symbolTag = '[object Symbol]';
|
---|
| 18 |
|
---|
| 19 | /** Used to match leading and trailing whitespace. */
|
---|
| 20 | var reTrim = /^\s+|\s+$/g;
|
---|
| 21 |
|
---|
| 22 | /** Used to detect bad signed hexadecimal string values. */
|
---|
| 23 | var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
|
---|
| 24 |
|
---|
| 25 | /** Used to detect binary string values. */
|
---|
| 26 | var reIsBinary = /^0b[01]+$/i;
|
---|
| 27 |
|
---|
| 28 | /** Used to detect octal string values. */
|
---|
| 29 | var reIsOctal = /^0o[0-7]+$/i;
|
---|
| 30 |
|
---|
| 31 | /** Built-in method references without a dependency on `root`. */
|
---|
| 32 | var freeParseInt = parseInt;
|
---|
| 33 |
|
---|
| 34 | /** Detect free variable `global` from Node.js. */
|
---|
| 35 | var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
|
---|
| 36 |
|
---|
| 37 | /** Detect free variable `self`. */
|
---|
| 38 | var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
|
---|
| 39 |
|
---|
| 40 | /** Used as a reference to the global object. */
|
---|
| 41 | var root = freeGlobal || freeSelf || Function('return this')();
|
---|
| 42 |
|
---|
| 43 | /** Used for built-in method references. */
|
---|
| 44 | var objectProto = Object.prototype;
|
---|
| 45 |
|
---|
| 46 | /**
|
---|
| 47 | * Used to resolve the
|
---|
| 48 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
---|
| 49 | * of values.
|
---|
| 50 | */
|
---|
| 51 | var objectToString = objectProto.toString;
|
---|
| 52 |
|
---|
| 53 | /* Built-in method references for those with the same name as other `lodash` methods. */
|
---|
| 54 | var nativeMax = Math.max,
|
---|
| 55 | nativeMin = Math.min;
|
---|
| 56 |
|
---|
| 57 | /**
|
---|
| 58 | * Gets the timestamp of the number of milliseconds that have elapsed since
|
---|
| 59 | * the Unix epoch (1 January 1970 00:00:00 UTC).
|
---|
| 60 | *
|
---|
| 61 | * @static
|
---|
| 62 | * @memberOf _
|
---|
| 63 | * @since 2.4.0
|
---|
| 64 | * @category Date
|
---|
| 65 | * @returns {number} Returns the timestamp.
|
---|
| 66 | * @example
|
---|
| 67 | *
|
---|
| 68 | * _.defer(function(stamp) {
|
---|
| 69 | * console.log(_.now() - stamp);
|
---|
| 70 | * }, _.now());
|
---|
| 71 | * // => Logs the number of milliseconds it took for the deferred invocation.
|
---|
| 72 | */
|
---|
| 73 | var now = function() {
|
---|
| 74 | return root.Date.now();
|
---|
| 75 | };
|
---|
| 76 |
|
---|
| 77 | /**
|
---|
| 78 | * Creates a debounced function that delays invoking `func` until after `wait`
|
---|
| 79 | * milliseconds have elapsed since the last time the debounced function was
|
---|
| 80 | * invoked. The debounced function comes with a `cancel` method to cancel
|
---|
| 81 | * delayed `func` invocations and a `flush` method to immediately invoke them.
|
---|
| 82 | * Provide `options` to indicate whether `func` should be invoked on the
|
---|
| 83 | * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
|
---|
| 84 | * with the last arguments provided to the debounced function. Subsequent
|
---|
| 85 | * calls to the debounced function return the result of the last `func`
|
---|
| 86 | * invocation.
|
---|
| 87 | *
|
---|
| 88 | * **Note:** If `leading` and `trailing` options are `true`, `func` is
|
---|
| 89 | * invoked on the trailing edge of the timeout only if the debounced function
|
---|
| 90 | * is invoked more than once during the `wait` timeout.
|
---|
| 91 | *
|
---|
| 92 | * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
---|
| 93 | * until to the next tick, similar to `setTimeout` with a timeout of `0`.
|
---|
| 94 | *
|
---|
| 95 | * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
---|
| 96 | * for details over the differences between `_.debounce` and `_.throttle`.
|
---|
| 97 | *
|
---|
| 98 | * @static
|
---|
| 99 | * @memberOf _
|
---|
| 100 | * @since 0.1.0
|
---|
| 101 | * @category Function
|
---|
| 102 | * @param {Function} func The function to debounce.
|
---|
| 103 | * @param {number} [wait=0] The number of milliseconds to delay.
|
---|
| 104 | * @param {Object} [options={}] The options object.
|
---|
| 105 | * @param {boolean} [options.leading=false]
|
---|
| 106 | * Specify invoking on the leading edge of the timeout.
|
---|
| 107 | * @param {number} [options.maxWait]
|
---|
| 108 | * The maximum time `func` is allowed to be delayed before it's invoked.
|
---|
| 109 | * @param {boolean} [options.trailing=true]
|
---|
| 110 | * Specify invoking on the trailing edge of the timeout.
|
---|
| 111 | * @returns {Function} Returns the new debounced function.
|
---|
| 112 | * @example
|
---|
| 113 | *
|
---|
| 114 | * // Avoid costly calculations while the window size is in flux.
|
---|
| 115 | * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
|
---|
| 116 | *
|
---|
| 117 | * // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
---|
| 118 | * jQuery(element).on('click', _.debounce(sendMail, 300, {
|
---|
| 119 | * 'leading': true,
|
---|
| 120 | * 'trailing': false
|
---|
| 121 | * }));
|
---|
| 122 | *
|
---|
| 123 | * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
---|
| 124 | * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
|
---|
| 125 | * var source = new EventSource('/stream');
|
---|
| 126 | * jQuery(source).on('message', debounced);
|
---|
| 127 | *
|
---|
| 128 | * // Cancel the trailing debounced invocation.
|
---|
| 129 | * jQuery(window).on('popstate', debounced.cancel);
|
---|
| 130 | */
|
---|
| 131 | function debounce(func, wait, options) {
|
---|
| 132 | var lastArgs,
|
---|
| 133 | lastThis,
|
---|
| 134 | maxWait,
|
---|
| 135 | result,
|
---|
| 136 | timerId,
|
---|
| 137 | lastCallTime,
|
---|
| 138 | lastInvokeTime = 0,
|
---|
| 139 | leading = false,
|
---|
| 140 | maxing = false,
|
---|
| 141 | trailing = true;
|
---|
| 142 |
|
---|
| 143 | if (typeof func != 'function') {
|
---|
| 144 | throw new TypeError(FUNC_ERROR_TEXT);
|
---|
| 145 | }
|
---|
| 146 | wait = toNumber(wait) || 0;
|
---|
| 147 | if (isObject(options)) {
|
---|
| 148 | leading = !!options.leading;
|
---|
| 149 | maxing = 'maxWait' in options;
|
---|
| 150 | maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
|
---|
| 151 | trailing = 'trailing' in options ? !!options.trailing : trailing;
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | function invokeFunc(time) {
|
---|
| 155 | var args = lastArgs,
|
---|
| 156 | thisArg = lastThis;
|
---|
| 157 |
|
---|
| 158 | lastArgs = lastThis = undefined;
|
---|
| 159 | lastInvokeTime = time;
|
---|
| 160 | result = func.apply(thisArg, args);
|
---|
| 161 | return result;
|
---|
| 162 | }
|
---|
| 163 |
|
---|
| 164 | function leadingEdge(time) {
|
---|
| 165 | // Reset any `maxWait` timer.
|
---|
| 166 | lastInvokeTime = time;
|
---|
| 167 | // Start the timer for the trailing edge.
|
---|
| 168 | timerId = setTimeout(timerExpired, wait);
|
---|
| 169 | // Invoke the leading edge.
|
---|
| 170 | return leading ? invokeFunc(time) : result;
|
---|
| 171 | }
|
---|
| 172 |
|
---|
| 173 | function remainingWait(time) {
|
---|
| 174 | var timeSinceLastCall = time - lastCallTime,
|
---|
| 175 | timeSinceLastInvoke = time - lastInvokeTime,
|
---|
| 176 | result = wait - timeSinceLastCall;
|
---|
| 177 |
|
---|
| 178 | return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | function shouldInvoke(time) {
|
---|
| 182 | var timeSinceLastCall = time - lastCallTime,
|
---|
| 183 | timeSinceLastInvoke = time - lastInvokeTime;
|
---|
| 184 |
|
---|
| 185 | // Either this is the first call, activity has stopped and we're at the
|
---|
| 186 | // trailing edge, the system time has gone backwards and we're treating
|
---|
| 187 | // it as the trailing edge, or we've hit the `maxWait` limit.
|
---|
| 188 | return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
|
---|
| 189 | (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
|
---|
| 190 | }
|
---|
| 191 |
|
---|
| 192 | function timerExpired() {
|
---|
| 193 | var time = now();
|
---|
| 194 | if (shouldInvoke(time)) {
|
---|
| 195 | return trailingEdge(time);
|
---|
| 196 | }
|
---|
| 197 | // Restart the timer.
|
---|
| 198 | timerId = setTimeout(timerExpired, remainingWait(time));
|
---|
| 199 | }
|
---|
| 200 |
|
---|
| 201 | function trailingEdge(time) {
|
---|
| 202 | timerId = undefined;
|
---|
| 203 |
|
---|
| 204 | // Only invoke if we have `lastArgs` which means `func` has been
|
---|
| 205 | // debounced at least once.
|
---|
| 206 | if (trailing && lastArgs) {
|
---|
| 207 | return invokeFunc(time);
|
---|
| 208 | }
|
---|
| 209 | lastArgs = lastThis = undefined;
|
---|
| 210 | return result;
|
---|
| 211 | }
|
---|
| 212 |
|
---|
| 213 | function cancel() {
|
---|
| 214 | if (timerId !== undefined) {
|
---|
| 215 | clearTimeout(timerId);
|
---|
| 216 | }
|
---|
| 217 | lastInvokeTime = 0;
|
---|
| 218 | lastArgs = lastCallTime = lastThis = timerId = undefined;
|
---|
| 219 | }
|
---|
| 220 |
|
---|
| 221 | function flush() {
|
---|
| 222 | return timerId === undefined ? result : trailingEdge(now());
|
---|
| 223 | }
|
---|
| 224 |
|
---|
| 225 | function debounced() {
|
---|
| 226 | var time = now(),
|
---|
| 227 | isInvoking = shouldInvoke(time);
|
---|
| 228 |
|
---|
| 229 | lastArgs = arguments;
|
---|
| 230 | lastThis = this;
|
---|
| 231 | lastCallTime = time;
|
---|
| 232 |
|
---|
| 233 | if (isInvoking) {
|
---|
| 234 | if (timerId === undefined) {
|
---|
| 235 | return leadingEdge(lastCallTime);
|
---|
| 236 | }
|
---|
| 237 | if (maxing) {
|
---|
| 238 | // Handle invocations in a tight loop.
|
---|
| 239 | timerId = setTimeout(timerExpired, wait);
|
---|
| 240 | return invokeFunc(lastCallTime);
|
---|
| 241 | }
|
---|
| 242 | }
|
---|
| 243 | if (timerId === undefined) {
|
---|
| 244 | timerId = setTimeout(timerExpired, wait);
|
---|
| 245 | }
|
---|
| 246 | return result;
|
---|
| 247 | }
|
---|
| 248 | debounced.cancel = cancel;
|
---|
| 249 | debounced.flush = flush;
|
---|
| 250 | return debounced;
|
---|
| 251 | }
|
---|
| 252 |
|
---|
| 253 | /**
|
---|
| 254 | * Checks if `value` is the
|
---|
| 255 | * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
---|
| 256 | * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
---|
| 257 | *
|
---|
| 258 | * @static
|
---|
| 259 | * @memberOf _
|
---|
| 260 | * @since 0.1.0
|
---|
| 261 | * @category Lang
|
---|
| 262 | * @param {*} value The value to check.
|
---|
| 263 | * @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
---|
| 264 | * @example
|
---|
| 265 | *
|
---|
| 266 | * _.isObject({});
|
---|
| 267 | * // => true
|
---|
| 268 | *
|
---|
| 269 | * _.isObject([1, 2, 3]);
|
---|
| 270 | * // => true
|
---|
| 271 | *
|
---|
| 272 | * _.isObject(_.noop);
|
---|
| 273 | * // => true
|
---|
| 274 | *
|
---|
| 275 | * _.isObject(null);
|
---|
| 276 | * // => false
|
---|
| 277 | */
|
---|
| 278 | function isObject(value) {
|
---|
| 279 | var type = typeof value;
|
---|
| 280 | return !!value && (type == 'object' || type == 'function');
|
---|
| 281 | }
|
---|
| 282 |
|
---|
| 283 | /**
|
---|
| 284 | * Checks if `value` is object-like. A value is object-like if it's not `null`
|
---|
| 285 | * and has a `typeof` result of "object".
|
---|
| 286 | *
|
---|
| 287 | * @static
|
---|
| 288 | * @memberOf _
|
---|
| 289 | * @since 4.0.0
|
---|
| 290 | * @category Lang
|
---|
| 291 | * @param {*} value The value to check.
|
---|
| 292 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
|
---|
| 293 | * @example
|
---|
| 294 | *
|
---|
| 295 | * _.isObjectLike({});
|
---|
| 296 | * // => true
|
---|
| 297 | *
|
---|
| 298 | * _.isObjectLike([1, 2, 3]);
|
---|
| 299 | * // => true
|
---|
| 300 | *
|
---|
| 301 | * _.isObjectLike(_.noop);
|
---|
| 302 | * // => false
|
---|
| 303 | *
|
---|
| 304 | * _.isObjectLike(null);
|
---|
| 305 | * // => false
|
---|
| 306 | */
|
---|
| 307 | function isObjectLike(value) {
|
---|
| 308 | return !!value && typeof value == 'object';
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | /**
|
---|
| 312 | * Checks if `value` is classified as a `Symbol` primitive or object.
|
---|
| 313 | *
|
---|
| 314 | * @static
|
---|
| 315 | * @memberOf _
|
---|
| 316 | * @since 4.0.0
|
---|
| 317 | * @category Lang
|
---|
| 318 | * @param {*} value The value to check.
|
---|
| 319 | * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
|
---|
| 320 | * @example
|
---|
| 321 | *
|
---|
| 322 | * _.isSymbol(Symbol.iterator);
|
---|
| 323 | * // => true
|
---|
| 324 | *
|
---|
| 325 | * _.isSymbol('abc');
|
---|
| 326 | * // => false
|
---|
| 327 | */
|
---|
| 328 | function isSymbol(value) {
|
---|
| 329 | return typeof value == 'symbol' ||
|
---|
| 330 | (isObjectLike(value) && objectToString.call(value) == symbolTag);
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 | /**
|
---|
| 334 | * Converts `value` to a number.
|
---|
| 335 | *
|
---|
| 336 | * @static
|
---|
| 337 | * @memberOf _
|
---|
| 338 | * @since 4.0.0
|
---|
| 339 | * @category Lang
|
---|
| 340 | * @param {*} value The value to process.
|
---|
| 341 | * @returns {number} Returns the number.
|
---|
| 342 | * @example
|
---|
| 343 | *
|
---|
| 344 | * _.toNumber(3.2);
|
---|
| 345 | * // => 3.2
|
---|
| 346 | *
|
---|
| 347 | * _.toNumber(Number.MIN_VALUE);
|
---|
| 348 | * // => 5e-324
|
---|
| 349 | *
|
---|
| 350 | * _.toNumber(Infinity);
|
---|
| 351 | * // => Infinity
|
---|
| 352 | *
|
---|
| 353 | * _.toNumber('3.2');
|
---|
| 354 | * // => 3.2
|
---|
| 355 | */
|
---|
| 356 | function toNumber(value) {
|
---|
| 357 | if (typeof value == 'number') {
|
---|
| 358 | return value;
|
---|
| 359 | }
|
---|
| 360 | if (isSymbol(value)) {
|
---|
| 361 | return NAN;
|
---|
| 362 | }
|
---|
| 363 | if (isObject(value)) {
|
---|
| 364 | var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
|
---|
| 365 | value = isObject(other) ? (other + '') : other;
|
---|
| 366 | }
|
---|
| 367 | if (typeof value != 'string') {
|
---|
| 368 | return value === 0 ? value : +value;
|
---|
| 369 | }
|
---|
| 370 | value = value.replace(reTrim, '');
|
---|
| 371 | var isBinary = reIsBinary.test(value);
|
---|
| 372 | return (isBinary || reIsOctal.test(value))
|
---|
| 373 | ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
|
---|
| 374 | : (reIsBadHex.test(value) ? NAN : +value);
|
---|
| 375 | }
|
---|
| 376 |
|
---|
| 377 | module.exports = debounce;
|
---|