UNPKG

1.77 MBJavaScriptView Raw
1/**
2 * vis-network - network
3 * http://visjs.org/
4 *
5 * A dynamic, browser-based visualization library.
6 *
7 * @version 6.4.0
8 * @date 2019-11-10T19:38:00Z
9 *
10 * @copyright (c) 2011-2017 Almende B.V, http://almende.com
11 * @copyright (c) 2018-2019 visjs contributors, https://github.com/visjs
12 *
13 * @license
14 * vis.js is dual licensed under both
15 *
16 * 1. The Apache 2.0 License
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * and
20 *
21 * 2. The MIT License
22 * http://opensource.org/licenses/MIT
23 *
24 * vis.js may be distributed under either license.
25 */
26(function (global, factory) {
27 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
28 typeof define === 'function' && define.amd ? define(['exports'], factory) :
29 (global = global || self, factory(global.vis = global.vis || {}));
30}(this, (function (exports) { 'use strict';
31
32 var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
33
34 function commonjsRequire () {
35 throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
36 }
37
38 function unwrapExports (x) {
39 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
40 }
41
42 function createCommonjsModule(fn, module) {
43 return module = { exports: {} }, fn(module, module.exports), module.exports;
44 }
45
46 function getCjsExportFromNamespace (n) {
47 return n && n['default'] || n;
48 }
49
50 var check = function (it) {
51 return it && it.Math == Math && it;
52 }; // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
53
54
55 var global_1 = // eslint-disable-next-line no-undef
56 check(typeof globalThis == 'object' && globalThis) || check(typeof window == 'object' && window) || check(typeof self == 'object' && self) || check(typeof commonjsGlobal == 'object' && commonjsGlobal) || // eslint-disable-next-line no-new-func
57 Function('return this')();
58
59 var fails = function (exec) {
60 try {
61 return !!exec();
62 } catch (error) {
63 return true;
64 }
65 };
66
67 var descriptors = !fails(function () {
68 return Object.defineProperty({}, 'a', {
69 get: function () {
70 return 7;
71 }
72 }).a != 7;
73 });
74
75 var nativePropertyIsEnumerable = {}.propertyIsEnumerable;
76 var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; // Nashorn ~ JDK8 bug
77
78 var NASHORN_BUG = getOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({
79 1: 2
80 }, 1); // `Object.prototype.propertyIsEnumerable` method implementation
81 // https://tc39.github.io/ecma262/#sec-object.prototype.propertyisenumerable
82
83 var f = NASHORN_BUG ? function propertyIsEnumerable(V) {
84 var descriptor = getOwnPropertyDescriptor(this, V);
85 return !!descriptor && descriptor.enumerable;
86 } : nativePropertyIsEnumerable;
87 var objectPropertyIsEnumerable = {
88 f: f
89 };
90
91 var createPropertyDescriptor = function (bitmap, value) {
92 return {
93 enumerable: !(bitmap & 1),
94 configurable: !(bitmap & 2),
95 writable: !(bitmap & 4),
96 value: value
97 };
98 };
99
100 var toString = {}.toString;
101
102 var classofRaw = function (it) {
103 return toString.call(it).slice(8, -1);
104 };
105
106 var split = ''.split; // fallback for non-array-like ES3 and non-enumerable old V8 strings
107
108 var indexedObject = fails(function () {
109 // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
110 // eslint-disable-next-line no-prototype-builtins
111 return !Object('z').propertyIsEnumerable(0);
112 }) ? function (it) {
113 return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
114 } : Object;
115
116 // `RequireObjectCoercible` abstract operation
117 // https://tc39.github.io/ecma262/#sec-requireobjectcoercible
118 var requireObjectCoercible = function (it) {
119 if (it == undefined) throw TypeError("Can't call method on " + it);
120 return it;
121 };
122
123 var toIndexedObject = function (it) {
124 return indexedObject(requireObjectCoercible(it));
125 };
126
127 var isObject = function (it) {
128 return typeof it === 'object' ? it !== null : typeof it === 'function';
129 };
130
131 // https://tc39.github.io/ecma262/#sec-toprimitive
132 // instead of the ES6 spec version, we didn't implement @@toPrimitive case
133 // and the second argument - flag - preferred type is a string
134
135 var toPrimitive = function (input, PREFERRED_STRING) {
136 if (!isObject(input)) return input;
137 var fn, val;
138 if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
139 if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val;
140 if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
141 throw TypeError("Can't convert object to primitive value");
142 };
143
144 var hasOwnProperty = {}.hasOwnProperty;
145
146 var has = function (it, key) {
147 return hasOwnProperty.call(it, key);
148 };
149
150 var document$1 = global_1.document; // typeof document.createElement is 'object' in old IE
151
152 var EXISTS = isObject(document$1) && isObject(document$1.createElement);
153
154 var documentCreateElement = function (it) {
155 return EXISTS ? document$1.createElement(it) : {};
156 };
157
158 var ie8DomDefine = !descriptors && !fails(function () {
159 return Object.defineProperty(documentCreateElement('div'), 'a', {
160 get: function () {
161 return 7;
162 }
163 }).a != 7;
164 });
165
166 var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; // `Object.getOwnPropertyDescriptor` method
167 // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor
168
169 var f$1 = descriptors ? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
170 O = toIndexedObject(O);
171 P = toPrimitive(P, true);
172 if (ie8DomDefine) try {
173 return nativeGetOwnPropertyDescriptor(O, P);
174 } catch (error) {
175 /* empty */
176 }
177 if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
178 };
179 var objectGetOwnPropertyDescriptor = {
180 f: f$1
181 };
182
183 var anObject = function (it) {
184 if (!isObject(it)) {
185 throw TypeError(String(it) + ' is not an object');
186 }
187
188 return it;
189 };
190
191 var nativeDefineProperty = Object.defineProperty; // `Object.defineProperty` method
192 // https://tc39.github.io/ecma262/#sec-object.defineproperty
193
194 var f$2 = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) {
195 anObject(O);
196 P = toPrimitive(P, true);
197 anObject(Attributes);
198 if (ie8DomDefine) try {
199 return nativeDefineProperty(O, P, Attributes);
200 } catch (error) {
201 /* empty */
202 }
203 if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
204 if ('value' in Attributes) O[P] = Attributes.value;
205 return O;
206 };
207 var objectDefineProperty = {
208 f: f$2
209 };
210
211 var createNonEnumerableProperty = descriptors ? function (object, key, value) {
212 return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
213 } : function (object, key, value) {
214 object[key] = value;
215 return object;
216 };
217
218 var setGlobal = function (key, value) {
219 try {
220 createNonEnumerableProperty(global_1, key, value);
221 } catch (error) {
222 global_1[key] = value;
223 }
224
225 return value;
226 };
227
228 var SHARED = '__core-js_shared__';
229 var store = global_1[SHARED] || setGlobal(SHARED, {});
230 var sharedStore = store;
231
232 var shared = createCommonjsModule(function (module) {
233 (module.exports = function (key, value) {
234 return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
235 })('versions', []).push({
236 version: '3.3.4',
237 mode: 'global',
238 copyright: '© 2019 Denis Pushkarev (zloirock.ru)'
239 });
240 });
241
242 var functionToString = shared('native-function-to-string', Function.toString);
243
244 var WeakMap = global_1.WeakMap;
245 var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(functionToString.call(WeakMap));
246
247 var id = 0;
248 var postfix = Math.random();
249
250 var uid = function (key) {
251 return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36);
252 };
253
254 var keys = shared('keys');
255
256 var sharedKey = function (key) {
257 return keys[key] || (keys[key] = uid(key));
258 };
259
260 var hiddenKeys = {};
261
262 var WeakMap$1 = global_1.WeakMap;
263 var set, get, has$1;
264
265 var enforce = function (it) {
266 return has$1(it) ? get(it) : set(it, {});
267 };
268
269 var getterFor = function (TYPE) {
270 return function (it) {
271 var state;
272
273 if (!isObject(it) || (state = get(it)).type !== TYPE) {
274 throw TypeError('Incompatible receiver, ' + TYPE + ' required');
275 }
276
277 return state;
278 };
279 };
280
281 if (nativeWeakMap) {
282 var store$1 = new WeakMap$1();
283 var wmget = store$1.get;
284 var wmhas = store$1.has;
285 var wmset = store$1.set;
286
287 set = function (it, metadata) {
288 wmset.call(store$1, it, metadata);
289 return metadata;
290 };
291
292 get = function (it) {
293 return wmget.call(store$1, it) || {};
294 };
295
296 has$1 = function (it) {
297 return wmhas.call(store$1, it);
298 };
299 } else {
300 var STATE = sharedKey('state');
301 hiddenKeys[STATE] = true;
302
303 set = function (it, metadata) {
304 createNonEnumerableProperty(it, STATE, metadata);
305 return metadata;
306 };
307
308 get = function (it) {
309 return has(it, STATE) ? it[STATE] : {};
310 };
311
312 has$1 = function (it) {
313 return has(it, STATE);
314 };
315 }
316
317 var internalState = {
318 set: set,
319 get: get,
320 has: has$1,
321 enforce: enforce,
322 getterFor: getterFor
323 };
324
325 var redefine = createCommonjsModule(function (module) {
326 var getInternalState = internalState.get;
327 var enforceInternalState = internalState.enforce;
328 var TEMPLATE = String(functionToString).split('toString');
329 shared('inspectSource', function (it) {
330 return functionToString.call(it);
331 });
332 (module.exports = function (O, key, value, options) {
333 var unsafe = options ? !!options.unsafe : false;
334 var simple = options ? !!options.enumerable : false;
335 var noTargetGet = options ? !!options.noTargetGet : false;
336
337 if (typeof value == 'function') {
338 if (typeof key == 'string' && !has(value, 'name')) createNonEnumerableProperty(value, 'name', key);
339 enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : '');
340 }
341
342 if (O === global_1) {
343 if (simple) O[key] = value;else setGlobal(key, value);
344 return;
345 } else if (!unsafe) {
346 delete O[key];
347 } else if (!noTargetGet && O[key]) {
348 simple = true;
349 }
350
351 if (simple) O[key] = value;else createNonEnumerableProperty(O, key, value); // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
352 })(Function.prototype, 'toString', function toString() {
353 return typeof this == 'function' && getInternalState(this).source || functionToString.call(this);
354 });
355 });
356
357 var path = global_1;
358
359 var aFunction = function (variable) {
360 return typeof variable == 'function' ? variable : undefined;
361 };
362
363 var getBuiltIn = function (namespace, method) {
364 return arguments.length < 2 ? aFunction(path[namespace]) || aFunction(global_1[namespace]) : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method];
365 };
366
367 var ceil = Math.ceil;
368 var floor = Math.floor; // `ToInteger` abstract operation
369 // https://tc39.github.io/ecma262/#sec-tointeger
370
371 var toInteger = function (argument) {
372 return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument);
373 };
374
375 var min = Math.min; // `ToLength` abstract operation
376 // https://tc39.github.io/ecma262/#sec-tolength
377
378 var toLength = function (argument) {
379 return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
380 };
381
382 var max = Math.max;
383 var min$1 = Math.min; // Helper for a popular repeating case of the spec:
384 // Let integer be ? ToInteger(index).
385 // If integer < 0, let result be max((length + integer), 0); else let result be min(length, length).
386
387 var toAbsoluteIndex = function (index, length) {
388 var integer = toInteger(index);
389 return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
390 };
391
392 var createMethod = function (IS_INCLUDES) {
393 return function ($this, el, fromIndex) {
394 var O = toIndexedObject($this);
395 var length = toLength(O.length);
396 var index = toAbsoluteIndex(fromIndex, length);
397 var value; // Array#includes uses SameValueZero equality algorithm
398 // eslint-disable-next-line no-self-compare
399
400 if (IS_INCLUDES && el != el) while (length > index) {
401 value = O[index++]; // eslint-disable-next-line no-self-compare
402
403 if (value != value) return true; // Array#indexOf ignores holes, Array#includes - not
404 } else for (; length > index; index++) {
405 if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
406 }
407 return !IS_INCLUDES && -1;
408 };
409 };
410
411 var arrayIncludes = {
412 // `Array.prototype.includes` method
413 // https://tc39.github.io/ecma262/#sec-array.prototype.includes
414 includes: createMethod(true),
415 // `Array.prototype.indexOf` method
416 // https://tc39.github.io/ecma262/#sec-array.prototype.indexof
417 indexOf: createMethod(false)
418 };
419
420 var indexOf = arrayIncludes.indexOf;
421
422 var objectKeysInternal = function (object, names) {
423 var O = toIndexedObject(object);
424 var i = 0;
425 var result = [];
426 var key;
427
428 for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key); // Don't enum bug & hidden keys
429
430
431 while (names.length > i) if (has(O, key = names[i++])) {
432 ~indexOf(result, key) || result.push(key);
433 }
434
435 return result;
436 };
437
438 // IE8- don't enum bug keys
439 var enumBugKeys = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'];
440
441 var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype'); // `Object.getOwnPropertyNames` method
442 // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
443
444 var f$3 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
445 return objectKeysInternal(O, hiddenKeys$1);
446 };
447
448 var objectGetOwnPropertyNames = {
449 f: f$3
450 };
451
452 var f$4 = Object.getOwnPropertySymbols;
453 var objectGetOwnPropertySymbols = {
454 f: f$4
455 };
456
457 var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
458 var keys = objectGetOwnPropertyNames.f(anObject(it));
459 var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
460 return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
461 };
462
463 var copyConstructorProperties = function (target, source) {
464 var keys = ownKeys(source);
465 var defineProperty = objectDefineProperty.f;
466 var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
467
468 for (var i = 0; i < keys.length; i++) {
469 var key = keys[i];
470 if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
471 }
472 };
473
474 var replacement = /#|\.prototype\./;
475
476 var isForced = function (feature, detection) {
477 var value = data[normalize(feature)];
478 return value == POLYFILL ? true : value == NATIVE ? false : typeof detection == 'function' ? fails(detection) : !!detection;
479 };
480
481 var normalize = isForced.normalize = function (string) {
482 return String(string).replace(replacement, '.').toLowerCase();
483 };
484
485 var data = isForced.data = {};
486 var NATIVE = isForced.NATIVE = 'N';
487 var POLYFILL = isForced.POLYFILL = 'P';
488 var isForced_1 = isForced;
489
490 var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
491 /*
492 options.target - name of the target object
493 options.global - target is the global object
494 options.stat - export as static methods of target
495 options.proto - export as prototype methods of target
496 options.real - real prototype method for the `pure` version
497 options.forced - export even if the native feature is available
498 options.bind - bind methods to the target, required for the `pure` version
499 options.wrap - wrap constructors to preventing global pollution, required for the `pure` version
500 options.unsafe - use the simple assignment of property instead of delete + defineProperty
501 options.sham - add a flag to not completely full polyfills
502 options.enumerable - export as enumerable property
503 options.noTargetGet - prevent calling a getter on target
504 */
505
506 var _export = function (options, source) {
507 var TARGET = options.target;
508 var GLOBAL = options.global;
509 var STATIC = options.stat;
510 var FORCED, target, key, targetProperty, sourceProperty, descriptor;
511
512 if (GLOBAL) {
513 target = global_1;
514 } else if (STATIC) {
515 target = global_1[TARGET] || setGlobal(TARGET, {});
516 } else {
517 target = (global_1[TARGET] || {}).prototype;
518 }
519
520 if (target) for (key in source) {
521 sourceProperty = source[key];
522
523 if (options.noTargetGet) {
524 descriptor = getOwnPropertyDescriptor$1(target, key);
525 targetProperty = descriptor && descriptor.value;
526 } else targetProperty = target[key];
527
528 FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced); // contained in target
529
530 if (!FORCED && targetProperty !== undefined) {
531 if (typeof sourceProperty === typeof targetProperty) continue;
532 copyConstructorProperties(sourceProperty, targetProperty);
533 } // add a flag to not completely full polyfills
534
535
536 if (options.sham || targetProperty && targetProperty.sham) {
537 createNonEnumerableProperty(sourceProperty, 'sham', true);
538 } // extend global
539
540
541 redefine(target, key, sourceProperty, options);
542 }
543 };
544
545 var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
546 // Chrome 38 Symbol has incorrect toString conversion
547 // eslint-disable-next-line no-undef
548 return !String(Symbol());
549 });
550
551 var Symbol$1 = global_1.Symbol;
552 var store$2 = shared('wks');
553
554 var wellKnownSymbol = function (name) {
555 return store$2[name] || (store$2[name] = nativeSymbol && Symbol$1[name] || (nativeSymbol ? Symbol$1 : uid)('Symbol.' + name));
556 };
557
558 var TO_STRING_TAG = wellKnownSymbol('toStringTag'); // ES3 wrong here
559
560 var CORRECT_ARGUMENTS = classofRaw(function () {
561 return arguments;
562 }()) == 'Arguments'; // fallback for IE11 Script Access Denied error
563
564 var tryGet = function (it, key) {
565 try {
566 return it[key];
567 } catch (error) {
568 /* empty */
569 }
570 }; // getting tag from ES6+ `Object.prototype.toString`
571
572
573 var classof = function (it) {
574 var O, tag, result;
575 return it === undefined ? 'Undefined' : it === null ? 'Null' // @@toStringTag case
576 : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG)) == 'string' ? tag // builtinTag case
577 : CORRECT_ARGUMENTS ? classofRaw(O) // ES3 arguments fallback
578 : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
579 };
580
581 // https://tc39.github.io/ecma262/#sec-toobject
582
583 var toObject = function (argument) {
584 return Object(requireObjectCoercible(argument));
585 };
586
587 var correctPrototypeGetter = !fails(function () {
588 function F() {
589 /* empty */
590 }
591
592 F.prototype.constructor = null;
593 return Object.getPrototypeOf(new F()) !== F.prototype;
594 });
595
596 var IE_PROTO = sharedKey('IE_PROTO');
597 var ObjectPrototype = Object.prototype; // `Object.getPrototypeOf` method
598 // https://tc39.github.io/ecma262/#sec-object.getprototypeof
599
600 var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
601 O = toObject(O);
602 if (has(O, IE_PROTO)) return O[IE_PROTO];
603
604 if (typeof O.constructor == 'function' && O instanceof O.constructor) {
605 return O.constructor.prototype;
606 }
607
608 return O instanceof Object ? ObjectPrototype : null;
609 };
610
611 var aPossiblePrototype = function (it) {
612 if (!isObject(it) && it !== null) {
613 throw TypeError("Can't set " + String(it) + ' as a prototype');
614 }
615
616 return it;
617 };
618
619 // https://tc39.github.io/ecma262/#sec-object.setprototypeof
620 // Works with __proto__ only. Old v8 can't work with null proto objects.
621
622 /* eslint-disable no-proto */
623
624 var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
625 var CORRECT_SETTER = false;
626 var test = {};
627 var setter;
628
629 try {
630 setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
631 setter.call(test, []);
632 CORRECT_SETTER = test instanceof Array;
633 } catch (error) {
634 /* empty */
635 }
636
637 return function setPrototypeOf(O, proto) {
638 anObject(O);
639 aPossiblePrototype(proto);
640 if (CORRECT_SETTER) setter.call(O, proto);else O.__proto__ = proto;
641 return O;
642 };
643 }() : undefined);
644
645 var defineProperty = objectDefineProperty.f;
646 var DataView = global_1.DataView;
647 var DataViewPrototype = DataView && DataView.prototype;
648 var Int8Array = global_1.Int8Array;
649 var Int8ArrayPrototype = Int8Array && Int8Array.prototype;
650 var Uint8ClampedArray = global_1.Uint8ClampedArray;
651 var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
652 var TypedArray = Int8Array && objectGetPrototypeOf(Int8Array);
653 var TypedArrayPrototype = Int8ArrayPrototype && objectGetPrototypeOf(Int8ArrayPrototype);
654 var ObjectPrototype$1 = Object.prototype;
655 var isPrototypeOf = ObjectPrototype$1.isPrototypeOf;
656 var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
657 var TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG');
658 var NATIVE_ARRAY_BUFFER = !!(global_1.ArrayBuffer && DataView); // Fixing native typed arrays in Opera Presto crashes the browser, see #595
659
660 var NATIVE_ARRAY_BUFFER_VIEWS = NATIVE_ARRAY_BUFFER && !!objectSetPrototypeOf && classof(global_1.opera) !== 'Opera';
661 var TYPED_ARRAY_TAG_REQIRED = false;
662 var NAME;
663 var TypedArrayConstructorsList = {
664 Int8Array: 1,
665 Uint8Array: 1,
666 Uint8ClampedArray: 1,
667 Int16Array: 2,
668 Uint16Array: 2,
669 Int32Array: 4,
670 Uint32Array: 4,
671 Float32Array: 4,
672 Float64Array: 8
673 };
674
675 var isView = function isView(it) {
676 var klass = classof(it);
677 return klass === 'DataView' || has(TypedArrayConstructorsList, klass);
678 };
679
680 var isTypedArray = function (it) {
681 return isObject(it) && has(TypedArrayConstructorsList, classof(it));
682 };
683
684 var aTypedArray = function (it) {
685 if (isTypedArray(it)) return it;
686 throw TypeError('Target is not a typed array');
687 };
688
689 var aTypedArrayConstructor = function (C) {
690 if (objectSetPrototypeOf) {
691 if (isPrototypeOf.call(TypedArray, C)) return C;
692 } else for (var ARRAY in TypedArrayConstructorsList) if (has(TypedArrayConstructorsList, NAME)) {
693 var TypedArrayConstructor = global_1[ARRAY];
694
695 if (TypedArrayConstructor && (C === TypedArrayConstructor || isPrototypeOf.call(TypedArrayConstructor, C))) {
696 return C;
697 }
698 }
699
700 throw TypeError('Target is not a typed array constructor');
701 };
702
703 var exportProto = function (KEY, property, forced) {
704 if (!descriptors) return;
705 if (forced) for (var ARRAY in TypedArrayConstructorsList) {
706 var TypedArrayConstructor = global_1[ARRAY];
707
708 if (TypedArrayConstructor && has(TypedArrayConstructor.prototype, KEY)) {
709 delete TypedArrayConstructor.prototype[KEY];
710 }
711 }
712
713 if (!TypedArrayPrototype[KEY] || forced) {
714 redefine(TypedArrayPrototype, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && Int8ArrayPrototype[KEY] || property);
715 }
716 };
717
718 var exportStatic = function (KEY, property, forced) {
719 var ARRAY, TypedArrayConstructor;
720 if (!descriptors) return;
721
722 if (objectSetPrototypeOf) {
723 if (forced) for (ARRAY in TypedArrayConstructorsList) {
724 TypedArrayConstructor = global_1[ARRAY];
725
726 if (TypedArrayConstructor && has(TypedArrayConstructor, KEY)) {
727 delete TypedArrayConstructor[KEY];
728 }
729 }
730
731 if (!TypedArray[KEY] || forced) {
732 // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
733 try {
734 return redefine(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && Int8Array[KEY] || property);
735 } catch (error) {
736 /* empty */
737 }
738 } else return;
739 }
740
741 for (ARRAY in TypedArrayConstructorsList) {
742 TypedArrayConstructor = global_1[ARRAY];
743
744 if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
745 redefine(TypedArrayConstructor, KEY, property);
746 }
747 }
748 };
749
750 for (NAME in TypedArrayConstructorsList) {
751 if (!global_1[NAME]) NATIVE_ARRAY_BUFFER_VIEWS = false;
752 } // WebKit bug - typed arrays constructors prototype is Object.prototype
753
754
755 if (!NATIVE_ARRAY_BUFFER_VIEWS || typeof TypedArray != 'function' || TypedArray === Function.prototype) {
756 // eslint-disable-next-line no-shadow
757 TypedArray = function TypedArray() {
758 throw TypeError('Incorrect invocation');
759 };
760
761 if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
762 if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME], TypedArray);
763 }
764 }
765
766 if (!NATIVE_ARRAY_BUFFER_VIEWS || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype$1) {
767 TypedArrayPrototype = TypedArray.prototype;
768 if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
769 if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME].prototype, TypedArrayPrototype);
770 }
771 } // WebKit bug - one more object in Uint8ClampedArray prototype chain
772
773
774 if (NATIVE_ARRAY_BUFFER_VIEWS && objectGetPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) {
775 objectSetPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype);
776 }
777
778 if (descriptors && !has(TypedArrayPrototype, TO_STRING_TAG$1)) {
779 TYPED_ARRAY_TAG_REQIRED = true;
780 defineProperty(TypedArrayPrototype, TO_STRING_TAG$1, {
781 get: function () {
782 return isObject(this) ? this[TYPED_ARRAY_TAG] : undefined;
783 }
784 });
785
786 for (NAME in TypedArrayConstructorsList) if (global_1[NAME]) {
787 createNonEnumerableProperty(global_1[NAME], TYPED_ARRAY_TAG, NAME);
788 }
789 } // WebKit bug - the same parent prototype for typed arrays and data view
790
791
792 if (NATIVE_ARRAY_BUFFER && objectSetPrototypeOf && objectGetPrototypeOf(DataViewPrototype) !== ObjectPrototype$1) {
793 objectSetPrototypeOf(DataViewPrototype, ObjectPrototype$1);
794 }
795
796 var arrayBufferViewCore = {
797 NATIVE_ARRAY_BUFFER: NATIVE_ARRAY_BUFFER,
798 NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS,
799 TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQIRED && TYPED_ARRAY_TAG,
800 aTypedArray: aTypedArray,
801 aTypedArrayConstructor: aTypedArrayConstructor,
802 exportProto: exportProto,
803 exportStatic: exportStatic,
804 isView: isView,
805 isTypedArray: isTypedArray,
806 TypedArray: TypedArray,
807 TypedArrayPrototype: TypedArrayPrototype
808 };
809
810 var redefineAll = function (target, src, options) {
811 for (var key in src) redefine(target, key, src[key], options);
812
813 return target;
814 };
815
816 var anInstance = function (it, Constructor, name) {
817 if (!(it instanceof Constructor)) {
818 throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
819 }
820
821 return it;
822 };
823
824 // https://tc39.github.io/ecma262/#sec-toindex
825
826 var toIndex = function (it) {
827 if (it === undefined) return 0;
828 var number = toInteger(it);
829 var length = toLength(number);
830 if (number !== length) throw RangeError('Wrong length or index');
831 return length;
832 };
833
834 // https://tc39.github.io/ecma262/#sec-array.prototype.fill
835
836
837 var arrayFill = function fill(value
838 /* , start = 0, end = @length */
839 ) {
840 var O = toObject(this);
841 var length = toLength(O.length);
842 var argumentsLength = arguments.length;
843 var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);
844 var end = argumentsLength > 2 ? arguments[2] : undefined;
845 var endPos = end === undefined ? length : toAbsoluteIndex(end, length);
846
847 while (endPos > index) O[index++] = value;
848
849 return O;
850 };
851
852 var defineProperty$1 = objectDefineProperty.f;
853 var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag');
854
855 var setToStringTag = function (it, TAG, STATIC) {
856 if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG$2)) {
857 defineProperty$1(it, TO_STRING_TAG$2, {
858 configurable: true,
859 value: TAG
860 });
861 }
862 };
863
864 var NATIVE_ARRAY_BUFFER$1 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER;
865 var getOwnPropertyNames = objectGetOwnPropertyNames.f;
866 var defineProperty$2 = objectDefineProperty.f;
867 var getInternalState = internalState.get;
868 var setInternalState = internalState.set;
869 var ARRAY_BUFFER = 'ArrayBuffer';
870 var DATA_VIEW = 'DataView';
871 var PROTOTYPE = 'prototype';
872 var WRONG_LENGTH = 'Wrong length';
873 var WRONG_INDEX = 'Wrong index';
874 var NativeArrayBuffer = global_1[ARRAY_BUFFER];
875 var $ArrayBuffer = NativeArrayBuffer;
876 var $DataView = global_1[DATA_VIEW];
877 var Math$1 = global_1.Math;
878 var RangeError$1 = global_1.RangeError; // eslint-disable-next-line no-shadow-restricted-names
879
880 var Infinity$1 = 1 / 0;
881 var abs = Math$1.abs;
882 var pow = Math$1.pow;
883 var floor$1 = Math$1.floor;
884 var log = Math$1.log;
885 var LN2 = Math$1.LN2; // IEEE754 conversions based on https://github.com/feross/ieee754
886
887 var packIEEE754 = function (number, mantissaLength, bytes) {
888 var buffer = new Array(bytes);
889 var exponentLength = bytes * 8 - mantissaLength - 1;
890 var eMax = (1 << exponentLength) - 1;
891 var eBias = eMax >> 1;
892 var rt = mantissaLength === 23 ? pow(2, -24) - pow(2, -77) : 0;
893 var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
894 var index = 0;
895 var exponent, mantissa, c;
896 number = abs(number); // eslint-disable-next-line no-self-compare
897
898 if (number != number || number === Infinity$1) {
899 // eslint-disable-next-line no-self-compare
900 mantissa = number != number ? 1 : 0;
901 exponent = eMax;
902 } else {
903 exponent = floor$1(log(number) / LN2);
904
905 if (number * (c = pow(2, -exponent)) < 1) {
906 exponent--;
907 c *= 2;
908 }
909
910 if (exponent + eBias >= 1) {
911 number += rt / c;
912 } else {
913 number += rt * pow(2, 1 - eBias);
914 }
915
916 if (number * c >= 2) {
917 exponent++;
918 c /= 2;
919 }
920
921 if (exponent + eBias >= eMax) {
922 mantissa = 0;
923 exponent = eMax;
924 } else if (exponent + eBias >= 1) {
925 mantissa = (number * c - 1) * pow(2, mantissaLength);
926 exponent = exponent + eBias;
927 } else {
928 mantissa = number * pow(2, eBias - 1) * pow(2, mantissaLength);
929 exponent = 0;
930 }
931 }
932
933 for (; mantissaLength >= 8; buffer[index++] = mantissa & 255, mantissa /= 256, mantissaLength -= 8);
934
935 exponent = exponent << mantissaLength | mantissa;
936 exponentLength += mantissaLength;
937
938 for (; exponentLength > 0; buffer[index++] = exponent & 255, exponent /= 256, exponentLength -= 8);
939
940 buffer[--index] |= sign * 128;
941 return buffer;
942 };
943
944 var unpackIEEE754 = function (buffer, mantissaLength) {
945 var bytes = buffer.length;
946 var exponentLength = bytes * 8 - mantissaLength - 1;
947 var eMax = (1 << exponentLength) - 1;
948 var eBias = eMax >> 1;
949 var nBits = exponentLength - 7;
950 var index = bytes - 1;
951 var sign = buffer[index--];
952 var exponent = sign & 127;
953 var mantissa;
954 sign >>= 7;
955
956 for (; nBits > 0; exponent = exponent * 256 + buffer[index], index--, nBits -= 8);
957
958 mantissa = exponent & (1 << -nBits) - 1;
959 exponent >>= -nBits;
960 nBits += mantissaLength;
961
962 for (; nBits > 0; mantissa = mantissa * 256 + buffer[index], index--, nBits -= 8);
963
964 if (exponent === 0) {
965 exponent = 1 - eBias;
966 } else if (exponent === eMax) {
967 return mantissa ? NaN : sign ? -Infinity$1 : Infinity$1;
968 } else {
969 mantissa = mantissa + pow(2, mantissaLength);
970 exponent = exponent - eBias;
971 }
972
973 return (sign ? -1 : 1) * mantissa * pow(2, exponent - mantissaLength);
974 };
975
976 var unpackInt32 = function (buffer) {
977 return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
978 };
979
980 var packInt8 = function (number) {
981 return [number & 0xFF];
982 };
983
984 var packInt16 = function (number) {
985 return [number & 0xFF, number >> 8 & 0xFF];
986 };
987
988 var packInt32 = function (number) {
989 return [number & 0xFF, number >> 8 & 0xFF, number >> 16 & 0xFF, number >> 24 & 0xFF];
990 };
991
992 var packFloat32 = function (number) {
993 return packIEEE754(number, 23, 4);
994 };
995
996 var packFloat64 = function (number) {
997 return packIEEE754(number, 52, 8);
998 };
999
1000 var addGetter = function (Constructor, key) {
1001 defineProperty$2(Constructor[PROTOTYPE], key, {
1002 get: function () {
1003 return getInternalState(this)[key];
1004 }
1005 });
1006 };
1007
1008 var get$1 = function (view, count, index, isLittleEndian) {
1009 var numIndex = +index;
1010 var intIndex = toIndex(numIndex);
1011 var store = getInternalState(view);
1012 if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
1013 var bytes = getInternalState(store.buffer).bytes;
1014 var start = intIndex + store.byteOffset;
1015 var pack = bytes.slice(start, start + count);
1016 return isLittleEndian ? pack : pack.reverse();
1017 };
1018
1019 var set$1 = function (view, count, index, conversion, value, isLittleEndian) {
1020 var numIndex = +index;
1021 var intIndex = toIndex(numIndex);
1022 var store = getInternalState(view);
1023 if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
1024 var bytes = getInternalState(store.buffer).bytes;
1025 var start = intIndex + store.byteOffset;
1026 var pack = conversion(+value);
1027
1028 for (var i = 0; i < count; i++) bytes[start + i] = pack[isLittleEndian ? i : count - i - 1];
1029 };
1030
1031 if (!NATIVE_ARRAY_BUFFER$1) {
1032 $ArrayBuffer = function ArrayBuffer(length) {
1033 anInstance(this, $ArrayBuffer, ARRAY_BUFFER);
1034 var byteLength = toIndex(length);
1035 setInternalState(this, {
1036 bytes: arrayFill.call(new Array(byteLength), 0),
1037 byteLength: byteLength
1038 });
1039 if (!descriptors) this.byteLength = byteLength;
1040 };
1041
1042 $DataView = function DataView(buffer, byteOffset, byteLength) {
1043 anInstance(this, $DataView, DATA_VIEW);
1044 anInstance(buffer, $ArrayBuffer, DATA_VIEW);
1045 var bufferLength = getInternalState(buffer).byteLength;
1046 var offset = toInteger(byteOffset);
1047 if (offset < 0 || offset > bufferLength) throw RangeError$1('Wrong offset');
1048 byteLength = byteLength === undefined ? bufferLength - offset : toLength(byteLength);
1049 if (offset + byteLength > bufferLength) throw RangeError$1(WRONG_LENGTH);
1050 setInternalState(this, {
1051 buffer: buffer,
1052 byteLength: byteLength,
1053 byteOffset: offset
1054 });
1055
1056 if (!descriptors) {
1057 this.buffer = buffer;
1058 this.byteLength = byteLength;
1059 this.byteOffset = offset;
1060 }
1061 };
1062
1063 if (descriptors) {
1064 addGetter($ArrayBuffer, 'byteLength');
1065 addGetter($DataView, 'buffer');
1066 addGetter($DataView, 'byteLength');
1067 addGetter($DataView, 'byteOffset');
1068 }
1069
1070 redefineAll($DataView[PROTOTYPE], {
1071 getInt8: function getInt8(byteOffset) {
1072 return get$1(this, 1, byteOffset)[0] << 24 >> 24;
1073 },
1074 getUint8: function getUint8(byteOffset) {
1075 return get$1(this, 1, byteOffset)[0];
1076 },
1077 getInt16: function getInt16(byteOffset
1078 /* , littleEndian */
1079 ) {
1080 var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
1081 return (bytes[1] << 8 | bytes[0]) << 16 >> 16;
1082 },
1083 getUint16: function getUint16(byteOffset
1084 /* , littleEndian */
1085 ) {
1086 var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
1087 return bytes[1] << 8 | bytes[0];
1088 },
1089 getInt32: function getInt32(byteOffset
1090 /* , littleEndian */
1091 ) {
1092 return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined));
1093 },
1094 getUint32: function getUint32(byteOffset
1095 /* , littleEndian */
1096 ) {
1097 return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined)) >>> 0;
1098 },
1099 getFloat32: function getFloat32(byteOffset
1100 /* , littleEndian */
1101 ) {
1102 return unpackIEEE754(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 23);
1103 },
1104 getFloat64: function getFloat64(byteOffset
1105 /* , littleEndian */
1106 ) {
1107 return unpackIEEE754(get$1(this, 8, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 52);
1108 },
1109 setInt8: function setInt8(byteOffset, value) {
1110 set$1(this, 1, byteOffset, packInt8, value);
1111 },
1112 setUint8: function setUint8(byteOffset, value) {
1113 set$1(this, 1, byteOffset, packInt8, value);
1114 },
1115 setInt16: function setInt16(byteOffset, value
1116 /* , littleEndian */
1117 ) {
1118 set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
1119 },
1120 setUint16: function setUint16(byteOffset, value
1121 /* , littleEndian */
1122 ) {
1123 set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
1124 },
1125 setInt32: function setInt32(byteOffset, value
1126 /* , littleEndian */
1127 ) {
1128 set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
1129 },
1130 setUint32: function setUint32(byteOffset, value
1131 /* , littleEndian */
1132 ) {
1133 set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
1134 },
1135 setFloat32: function setFloat32(byteOffset, value
1136 /* , littleEndian */
1137 ) {
1138 set$1(this, 4, byteOffset, packFloat32, value, arguments.length > 2 ? arguments[2] : undefined);
1139 },
1140 setFloat64: function setFloat64(byteOffset, value
1141 /* , littleEndian */
1142 ) {
1143 set$1(this, 8, byteOffset, packFloat64, value, arguments.length > 2 ? arguments[2] : undefined);
1144 }
1145 });
1146 } else {
1147 if (!fails(function () {
1148 NativeArrayBuffer(1);
1149 }) || !fails(function () {
1150 new NativeArrayBuffer(-1); // eslint-disable-line no-new
1151 }) || fails(function () {
1152 new NativeArrayBuffer(); // eslint-disable-line no-new
1153
1154 new NativeArrayBuffer(1.5); // eslint-disable-line no-new
1155
1156 new NativeArrayBuffer(NaN); // eslint-disable-line no-new
1157
1158 return NativeArrayBuffer.name != ARRAY_BUFFER;
1159 })) {
1160 $ArrayBuffer = function ArrayBuffer(length) {
1161 anInstance(this, $ArrayBuffer);
1162 return new NativeArrayBuffer(toIndex(length));
1163 };
1164
1165 var ArrayBufferPrototype = $ArrayBuffer[PROTOTYPE] = NativeArrayBuffer[PROTOTYPE];
1166
1167 for (var keys$1 = getOwnPropertyNames(NativeArrayBuffer), j = 0, key; keys$1.length > j;) {
1168 if (!((key = keys$1[j++]) in $ArrayBuffer)) {
1169 createNonEnumerableProperty($ArrayBuffer, key, NativeArrayBuffer[key]);
1170 }
1171 }
1172
1173 ArrayBufferPrototype.constructor = $ArrayBuffer;
1174 } // iOS Safari 7.x bug
1175
1176
1177 var testView = new $DataView(new $ArrayBuffer(2));
1178 var nativeSetInt8 = $DataView[PROTOTYPE].setInt8;
1179 testView.setInt8(0, 2147483648);
1180 testView.setInt8(1, 2147483649);
1181 if (testView.getInt8(0) || !testView.getInt8(1)) redefineAll($DataView[PROTOTYPE], {
1182 setInt8: function setInt8(byteOffset, value) {
1183 nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
1184 },
1185 setUint8: function setUint8(byteOffset, value) {
1186 nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
1187 }
1188 }, {
1189 unsafe: true
1190 });
1191 }
1192
1193 setToStringTag($ArrayBuffer, ARRAY_BUFFER);
1194 setToStringTag($DataView, DATA_VIEW);
1195 var arrayBuffer = {
1196 ArrayBuffer: $ArrayBuffer,
1197 DataView: $DataView
1198 };
1199
1200 var aFunction$1 = function (it) {
1201 if (typeof it != 'function') {
1202 throw TypeError(String(it) + ' is not a function');
1203 }
1204
1205 return it;
1206 };
1207
1208 var SPECIES = wellKnownSymbol('species'); // `SpeciesConstructor` abstract operation
1209 // https://tc39.github.io/ecma262/#sec-speciesconstructor
1210
1211 var speciesConstructor = function (O, defaultConstructor) {
1212 var C = anObject(O).constructor;
1213 var S;
1214 return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? defaultConstructor : aFunction$1(S);
1215 };
1216
1217 var ArrayBuffer = arrayBuffer.ArrayBuffer;
1218 var DataView$1 = arrayBuffer.DataView;
1219 var nativeArrayBufferSlice = ArrayBuffer.prototype.slice;
1220 var INCORRECT_SLICE = fails(function () {
1221 return !new ArrayBuffer(2).slice(1, undefined).byteLength;
1222 }); // `ArrayBuffer.prototype.slice` method
1223 // https://tc39.github.io/ecma262/#sec-arraybuffer.prototype.slice
1224
1225 _export({
1226 target: 'ArrayBuffer',
1227 proto: true,
1228 unsafe: true,
1229 forced: INCORRECT_SLICE
1230 }, {
1231 slice: function slice(start, end) {
1232 if (nativeArrayBufferSlice !== undefined && end === undefined) {
1233 return nativeArrayBufferSlice.call(anObject(this), start); // FF fix
1234 }
1235
1236 var length = anObject(this).byteLength;
1237 var first = toAbsoluteIndex(start, length);
1238 var fin = toAbsoluteIndex(end === undefined ? length : end, length);
1239 var result = new (speciesConstructor(this, ArrayBuffer))(toLength(fin - first));
1240 var viewSource = new DataView$1(this);
1241 var viewTarget = new DataView$1(result);
1242 var index = 0;
1243
1244 while (first < fin) {
1245 viewTarget.setUint8(index++, viewSource.getUint8(first++));
1246 }
1247
1248 return result;
1249 }
1250 });
1251
1252 var NATIVE_ARRAY_BUFFER$2 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER; // `DataView` constructor
1253 // https://tc39.github.io/ecma262/#sec-dataview-constructor
1254
1255 _export({
1256 global: true,
1257 forced: !NATIVE_ARRAY_BUFFER$2
1258 }, {
1259 DataView: arrayBuffer.DataView
1260 });
1261
1262 var TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');
1263 var test = {};
1264 test[TO_STRING_TAG$3] = 'z'; // `Object.prototype.toString` method implementation
1265 // https://tc39.github.io/ecma262/#sec-object.prototype.tostring
1266
1267 var objectToString = String(test) !== '[object z]' ? function toString() {
1268 return '[object ' + classof(this) + ']';
1269 } : test.toString;
1270
1271 var ObjectPrototype$2 = Object.prototype; // `Object.prototype.toString` method
1272 // https://tc39.github.io/ecma262/#sec-object.prototype.tostring
1273
1274 if (objectToString !== ObjectPrototype$2.toString) {
1275 redefine(ObjectPrototype$2, 'toString', objectToString, {
1276 unsafe: true
1277 });
1278 }
1279
1280 /*
1281 * Canvas shapes used by Network
1282 */
1283
1284 if (typeof CanvasRenderingContext2D !== "undefined") {
1285 CanvasRenderingContext2D.prototype.circle = function (x, y, r) {
1286 this.beginPath();
1287 this.arc(x, y, r, 0, 2 * Math.PI, false);
1288 this.closePath();
1289 };
1290
1291 CanvasRenderingContext2D.prototype.square = function (x, y, r) {
1292 this.beginPath();
1293 this.rect(x - r, y - r, r * 2, r * 2);
1294 this.closePath();
1295 };
1296
1297 CanvasRenderingContext2D.prototype.triangle = function (x, y, r) {
1298 this.beginPath(); // the change in radius and the offset is here to center the shape
1299
1300 r *= 1.15;
1301 y += 0.275 * r;
1302 var s = r * 2;
1303 var s2 = s / 2;
1304 var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
1305
1306 var h = Math.sqrt(s * s - s2 * s2); // height
1307
1308 this.moveTo(x, y - (h - ir));
1309 this.lineTo(x + s2, y + ir);
1310 this.lineTo(x - s2, y + ir);
1311 this.lineTo(x, y - (h - ir));
1312 this.closePath();
1313 };
1314
1315 CanvasRenderingContext2D.prototype.triangleDown = function (x, y, r) {
1316 this.beginPath(); // the change in radius and the offset is here to center the shape
1317
1318 r *= 1.15;
1319 y -= 0.275 * r;
1320 var s = r * 2;
1321 var s2 = s / 2;
1322 var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
1323
1324 var h = Math.sqrt(s * s - s2 * s2); // height
1325
1326 this.moveTo(x, y + (h - ir));
1327 this.lineTo(x + s2, y - ir);
1328 this.lineTo(x - s2, y - ir);
1329 this.lineTo(x, y + (h - ir));
1330 this.closePath();
1331 };
1332
1333 CanvasRenderingContext2D.prototype.star = function (x, y, r) {
1334 // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
1335 this.beginPath(); // the change in radius and the offset is here to center the shape
1336
1337 r *= 0.82;
1338 y += 0.1 * r;
1339
1340 for (var n = 0; n < 10; n++) {
1341 var radius = n % 2 === 0 ? r * 1.3 : r * 0.5;
1342 this.lineTo(x + radius * Math.sin(n * 2 * Math.PI / 10), y - radius * Math.cos(n * 2 * Math.PI / 10));
1343 }
1344
1345 this.closePath();
1346 };
1347
1348 CanvasRenderingContext2D.prototype.diamond = function (x, y, r) {
1349 this.beginPath();
1350 this.lineTo(x, y + r);
1351 this.lineTo(x + r, y);
1352 this.lineTo(x, y - r);
1353 this.lineTo(x - r, y);
1354 this.closePath();
1355 };
1356
1357 CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h, r) {
1358 var r2d = Math.PI / 180;
1359
1360 if (w - 2 * r < 0) {
1361 r = w / 2;
1362 } //ensure that the radius isn't too large for x
1363
1364
1365 if (h - 2 * r < 0) {
1366 r = h / 2;
1367 } //ensure that the radius isn't too large for y
1368
1369
1370 this.beginPath();
1371 this.moveTo(x + r, y);
1372 this.lineTo(x + w - r, y);
1373 this.arc(x + w - r, y + r, r, r2d * 270, r2d * 360, false);
1374 this.lineTo(x + w, y + h - r);
1375 this.arc(x + w - r, y + h - r, r, 0, r2d * 90, false);
1376 this.lineTo(x + r, y + h);
1377 this.arc(x + r, y + h - r, r, r2d * 90, r2d * 180, false);
1378 this.lineTo(x, y + r);
1379 this.arc(x + r, y + r, r, r2d * 180, r2d * 270, false);
1380 this.closePath();
1381 };
1382
1383 CanvasRenderingContext2D.prototype.ellipse_vis = function (x, y, w, h) {
1384 var kappa = 0.5522848,
1385 ox = w / 2 * kappa,
1386 // control point offset horizontal
1387 oy = h / 2 * kappa,
1388 // control point offset vertical
1389 xe = x + w,
1390 // x-end
1391 ye = y + h,
1392 // y-end
1393 xm = x + w / 2,
1394 // x-middle
1395 ym = y + h / 2; // y-middle
1396
1397 this.beginPath();
1398 this.moveTo(x, ym);
1399 this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
1400 this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
1401 this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
1402 this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
1403 this.closePath();
1404 };
1405
1406 CanvasRenderingContext2D.prototype.database = function (x, y, w, h) {
1407 var f = 1 / 3;
1408 var wEllipse = w;
1409 var hEllipse = h * f;
1410 var kappa = 0.5522848,
1411 ox = wEllipse / 2 * kappa,
1412 // control point offset horizontal
1413 oy = hEllipse / 2 * kappa,
1414 // control point offset vertical
1415 xe = x + wEllipse,
1416 // x-end
1417 ye = y + hEllipse,
1418 // y-end
1419 xm = x + wEllipse / 2,
1420 // x-middle
1421 ym = y + hEllipse / 2,
1422 // y-middle
1423 ymb = y + (h - hEllipse / 2),
1424 // y-midlle, bottom ellipse
1425 yeb = y + h; // y-end, bottom ellipse
1426
1427 this.beginPath();
1428 this.moveTo(xe, ym);
1429 this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
1430 this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
1431 this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
1432 this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
1433 this.lineTo(xe, ymb);
1434 this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb);
1435 this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb);
1436 this.lineTo(x, ym);
1437 };
1438
1439 CanvasRenderingContext2D.prototype.dashedLine = function (x, y, x2, y2, pattern) {
1440 this.beginPath();
1441 this.moveTo(x, y);
1442 var patternLength = pattern.length;
1443 var dx = x2 - x;
1444 var dy = y2 - y;
1445 var slope = dy / dx;
1446 var distRemaining = Math.sqrt(dx * dx + dy * dy);
1447 var patternIndex = 0;
1448 var draw = true;
1449 var xStep = 0;
1450 var dashLength = +pattern[0];
1451
1452 while (distRemaining >= 0.1) {
1453 dashLength = +pattern[patternIndex++ % patternLength];
1454
1455 if (dashLength > distRemaining) {
1456 dashLength = distRemaining;
1457 }
1458
1459 xStep = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
1460 xStep = dx < 0 ? -xStep : xStep;
1461 x += xStep;
1462 y += slope * xStep;
1463
1464 if (draw === true) {
1465 this.lineTo(x, y);
1466 } else {
1467 this.moveTo(x, y);
1468 }
1469
1470 distRemaining -= dashLength;
1471 draw = !draw;
1472 }
1473 };
1474
1475 CanvasRenderingContext2D.prototype.hexagon = function (x, y, r) {
1476 this.beginPath();
1477 var sides = 6;
1478 var a = Math.PI * 2 / sides;
1479 this.moveTo(x + r, y);
1480
1481 for (var i = 1; i < sides; i++) {
1482 this.lineTo(x + r * Math.cos(a * i), y + r * Math.sin(a * i));
1483 }
1484
1485 this.closePath();
1486 };
1487 }
1488
1489 var componentEmitter = createCommonjsModule(function (module) {
1490 /**
1491 * Expose `Emitter`.
1492 */
1493 {
1494 module.exports = Emitter;
1495 }
1496 /**
1497 * Initialize a new `Emitter`.
1498 *
1499 * @api public
1500 */
1501
1502
1503 function Emitter(obj) {
1504 if (obj) return mixin(obj);
1505 }
1506 /**
1507 * Mixin the emitter properties.
1508 *
1509 * @param {Object} obj
1510 * @return {Object}
1511 * @api private
1512 */
1513
1514 function mixin(obj) {
1515 for (var key in Emitter.prototype) {
1516 obj[key] = Emitter.prototype[key];
1517 }
1518
1519 return obj;
1520 }
1521 /**
1522 * Listen on the given `event` with `fn`.
1523 *
1524 * @param {String} event
1525 * @param {Function} fn
1526 * @return {Emitter}
1527 * @api public
1528 */
1529
1530
1531 Emitter.prototype.on = Emitter.prototype.addEventListener = function (event, fn) {
1532 this._callbacks = this._callbacks || {};
1533 (this._callbacks['$' + event] = this._callbacks['$' + event] || []).push(fn);
1534 return this;
1535 };
1536 /**
1537 * Adds an `event` listener that will be invoked a single
1538 * time then automatically removed.
1539 *
1540 * @param {String} event
1541 * @param {Function} fn
1542 * @return {Emitter}
1543 * @api public
1544 */
1545
1546
1547 Emitter.prototype.once = function (event, fn) {
1548 function on() {
1549 this.off(event, on);
1550 fn.apply(this, arguments);
1551 }
1552
1553 on.fn = fn;
1554 this.on(event, on);
1555 return this;
1556 };
1557 /**
1558 * Remove the given callback for `event` or all
1559 * registered callbacks.
1560 *
1561 * @param {String} event
1562 * @param {Function} fn
1563 * @return {Emitter}
1564 * @api public
1565 */
1566
1567
1568 Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function (event, fn) {
1569 this._callbacks = this._callbacks || {}; // all
1570
1571 if (0 == arguments.length) {
1572 this._callbacks = {};
1573 return this;
1574 } // specific event
1575
1576
1577 var callbacks = this._callbacks['$' + event];
1578 if (!callbacks) return this; // remove all handlers
1579
1580 if (1 == arguments.length) {
1581 delete this._callbacks['$' + event];
1582 return this;
1583 } // remove specific handler
1584
1585
1586 var cb;
1587
1588 for (var i = 0; i < callbacks.length; i++) {
1589 cb = callbacks[i];
1590
1591 if (cb === fn || cb.fn === fn) {
1592 callbacks.splice(i, 1);
1593 break;
1594 }
1595 } // Remove event specific arrays for event types that no
1596 // one is subscribed for to avoid memory leak.
1597
1598
1599 if (callbacks.length === 0) {
1600 delete this._callbacks['$' + event];
1601 }
1602
1603 return this;
1604 };
1605 /**
1606 * Emit `event` with the given args.
1607 *
1608 * @param {String} event
1609 * @param {Mixed} ...
1610 * @return {Emitter}
1611 */
1612
1613
1614 Emitter.prototype.emit = function (event) {
1615 this._callbacks = this._callbacks || {};
1616 var args = new Array(arguments.length - 1),
1617 callbacks = this._callbacks['$' + event];
1618
1619 for (var i = 1; i < arguments.length; i++) {
1620 args[i - 1] = arguments[i];
1621 }
1622
1623 if (callbacks) {
1624 callbacks = callbacks.slice(0);
1625
1626 for (var i = 0, len = callbacks.length; i < len; ++i) {
1627 callbacks[i].apply(this, args);
1628 }
1629 }
1630
1631 return this;
1632 };
1633 /**
1634 * Return array of callbacks for `event`.
1635 *
1636 * @param {String} event
1637 * @return {Array}
1638 * @api public
1639 */
1640
1641
1642 Emitter.prototype.listeners = function (event) {
1643 this._callbacks = this._callbacks || {};
1644 return this._callbacks['$' + event] || [];
1645 };
1646 /**
1647 * Check if this emitter has `event` handlers.
1648 *
1649 * @param {String} event
1650 * @return {Boolean}
1651 * @api public
1652 */
1653
1654
1655 Emitter.prototype.hasListeners = function (event) {
1656 return !!this.listeners(event).length;
1657 };
1658 });
1659
1660 var commonjsGlobal$1 = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
1661
1662 function commonjsRequire$1() {
1663 throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
1664 }
1665
1666 function createCommonjsModule$1(fn, module) {
1667 return module = {
1668 exports: {}
1669 }, fn(module, module.exports), module.exports;
1670 }
1671
1672 var _global = createCommonjsModule$1(function (module) {
1673 // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
1674 var global = module.exports = typeof window != 'undefined' && window.Math == Math ? window : typeof self != 'undefined' && self.Math == Math ? self // eslint-disable-next-line no-new-func
1675 : Function('return this')();
1676 if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef
1677 });
1678
1679 var _core = createCommonjsModule$1(function (module) {
1680 var core = module.exports = {
1681 version: '2.6.9'
1682 };
1683 if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
1684 });
1685
1686 var _core_1 = _core.version;
1687 var _library = false;
1688
1689 var _shared = createCommonjsModule$1(function (module) {
1690 var SHARED = '__core-js_shared__';
1691 var store = _global[SHARED] || (_global[SHARED] = {});
1692 (module.exports = function (key, value) {
1693 return store[key] || (store[key] = value !== undefined ? value : {});
1694 })('versions', []).push({
1695 version: _core.version,
1696 mode: 'global',
1697 copyright: '© 2019 Denis Pushkarev (zloirock.ru)'
1698 });
1699 });
1700
1701 var id$1 = 0;
1702 var px = Math.random();
1703
1704 var _uid = function (key) {
1705 return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id$1 + px).toString(36));
1706 };
1707
1708 var _wks = createCommonjsModule$1(function (module) {
1709 var store = _shared('wks');
1710
1711 var Symbol = _global.Symbol;
1712 var USE_SYMBOL = typeof Symbol == 'function';
1713
1714 var $exports = module.exports = function (name) {
1715 return store[name] || (store[name] = USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : _uid)('Symbol.' + name));
1716 };
1717
1718 $exports.store = store;
1719 });
1720
1721 var f$5 = _wks;
1722 var _wksExt = {
1723 f: f$5
1724 };
1725
1726 var _isObject = function (it) {
1727 return typeof it === 'object' ? it !== null : typeof it === 'function';
1728 };
1729
1730 var _anObject = function (it) {
1731 if (!_isObject(it)) throw TypeError(it + ' is not an object!');
1732 return it;
1733 };
1734
1735 var _fails = function (exec) {
1736 try {
1737 return !!exec();
1738 } catch (e) {
1739 return true;
1740 }
1741 };
1742
1743 var _descriptors = !_fails(function () {
1744 return Object.defineProperty({}, 'a', {
1745 get: function () {
1746 return 7;
1747 }
1748 }).a != 7;
1749 });
1750
1751 var document$1$1 = _global.document; // typeof document.createElement is 'object' in old IE
1752
1753 var is = _isObject(document$1$1) && _isObject(document$1$1.createElement);
1754
1755 var _domCreate = function (it) {
1756 return is ? document$1$1.createElement(it) : {};
1757 };
1758
1759 var _ie8DomDefine = !_descriptors && !_fails(function () {
1760 return Object.defineProperty(_domCreate('div'), 'a', {
1761 get: function () {
1762 return 7;
1763 }
1764 }).a != 7;
1765 }); // instead of the ES6 spec version, we didn't implement @@toPrimitive case
1766 // and the second argument - flag - preferred type is a string
1767
1768
1769 var _toPrimitive = function (it, S) {
1770 if (!_isObject(it)) return it;
1771 var fn, val;
1772 if (S && typeof (fn = it.toString) == 'function' && !_isObject(val = fn.call(it))) return val;
1773 if (typeof (fn = it.valueOf) == 'function' && !_isObject(val = fn.call(it))) return val;
1774 if (!S && typeof (fn = it.toString) == 'function' && !_isObject(val = fn.call(it))) return val;
1775 throw TypeError("Can't convert object to primitive value");
1776 };
1777
1778 var dP = Object.defineProperty;
1779 var f$1$1 = _descriptors ? Object.defineProperty : function defineProperty(O, P, Attributes) {
1780 _anObject(O);
1781
1782 P = _toPrimitive(P, true);
1783
1784 _anObject(Attributes);
1785
1786 if (_ie8DomDefine) try {
1787 return dP(O, P, Attributes);
1788 } catch (e) {
1789 /* empty */
1790 }
1791 if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!');
1792 if ('value' in Attributes) O[P] = Attributes.value;
1793 return O;
1794 };
1795 var _objectDp = {
1796 f: f$1$1
1797 };
1798 var defineProperty$3 = _objectDp.f;
1799
1800 var _wksDefine = function (name) {
1801 var $Symbol = _core.Symbol || (_core.Symbol = _global.Symbol || {});
1802 if (name.charAt(0) != '_' && !(name in $Symbol)) defineProperty$3($Symbol, name, {
1803 value: _wksExt.f(name)
1804 });
1805 };
1806
1807 _wksDefine('asyncIterator');
1808
1809 var hasOwnProperty$1 = {}.hasOwnProperty;
1810
1811 var _has = function (it, key) {
1812 return hasOwnProperty$1.call(it, key);
1813 };
1814
1815 var _propertyDesc = function (bitmap, value) {
1816 return {
1817 enumerable: !(bitmap & 1),
1818 configurable: !(bitmap & 2),
1819 writable: !(bitmap & 4),
1820 value: value
1821 };
1822 };
1823
1824 var _hide = _descriptors ? function (object, key, value) {
1825 return _objectDp.f(object, key, _propertyDesc(1, value));
1826 } : function (object, key, value) {
1827 object[key] = value;
1828 return object;
1829 };
1830
1831 var _functionToString = _shared('native-function-to-string', Function.toString);
1832
1833 var _redefine = createCommonjsModule$1(function (module) {
1834 var SRC = _uid('src');
1835
1836 var TO_STRING = 'toString';
1837
1838 var TPL = ('' + _functionToString).split(TO_STRING);
1839
1840 _core.inspectSource = function (it) {
1841 return _functionToString.call(it);
1842 };
1843
1844 (module.exports = function (O, key, val, safe) {
1845 var isFunction = typeof val == 'function';
1846 if (isFunction) _has(val, 'name') || _hide(val, 'name', key);
1847 if (O[key] === val) return;
1848 if (isFunction) _has(val, SRC) || _hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key)));
1849
1850 if (O === _global) {
1851 O[key] = val;
1852 } else if (!safe) {
1853 delete O[key];
1854
1855 _hide(O, key, val);
1856 } else if (O[key]) {
1857 O[key] = val;
1858 } else {
1859 _hide(O, key, val);
1860 } // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
1861
1862 })(Function.prototype, TO_STRING, function toString() {
1863 return typeof this == 'function' && this[SRC] || _functionToString.call(this);
1864 });
1865 });
1866
1867 var _aFunction = function (it) {
1868 if (typeof it != 'function') throw TypeError(it + ' is not a function!');
1869 return it;
1870 };
1871
1872 var _ctx = function (fn, that, length) {
1873 _aFunction(fn);
1874
1875 if (that === undefined) return fn;
1876
1877 switch (length) {
1878 case 1:
1879 return function (a) {
1880 return fn.call(that, a);
1881 };
1882
1883 case 2:
1884 return function (a, b) {
1885 return fn.call(that, a, b);
1886 };
1887
1888 case 3:
1889 return function (a, b, c) {
1890 return fn.call(that, a, b, c);
1891 };
1892 }
1893
1894 return function ()
1895 /* ...args */
1896 {
1897 return fn.apply(that, arguments);
1898 };
1899 };
1900
1901 var PROTOTYPE$1 = 'prototype';
1902
1903 var $export = function (type, name, source) {
1904 var IS_FORCED = type & $export.F;
1905 var IS_GLOBAL = type & $export.G;
1906 var IS_STATIC = type & $export.S;
1907 var IS_PROTO = type & $export.P;
1908 var IS_BIND = type & $export.B;
1909 var target = IS_GLOBAL ? _global : IS_STATIC ? _global[name] || (_global[name] = {}) : (_global[name] || {})[PROTOTYPE$1];
1910 var exports = IS_GLOBAL ? _core : _core[name] || (_core[name] = {});
1911 var expProto = exports[PROTOTYPE$1] || (exports[PROTOTYPE$1] = {});
1912 var key, own, out, exp;
1913 if (IS_GLOBAL) source = name;
1914
1915 for (key in source) {
1916 // contains in native
1917 own = !IS_FORCED && target && target[key] !== undefined; // export native or passed
1918
1919 out = (own ? target : source)[key]; // bind timers to global for call from export context
1920
1921 exp = IS_BIND && own ? _ctx(out, _global) : IS_PROTO && typeof out == 'function' ? _ctx(Function.call, out) : out; // extend global
1922
1923 if (target) _redefine(target, key, out, type & $export.U); // export
1924
1925 if (exports[key] != out) _hide(exports, key, exp);
1926 if (IS_PROTO && expProto[key] != out) expProto[key] = out;
1927 }
1928 };
1929
1930 _global.core = _core; // type bitmap
1931
1932 $export.F = 1; // forced
1933
1934 $export.G = 2; // global
1935
1936 $export.S = 4; // static
1937
1938 $export.P = 8; // proto
1939
1940 $export.B = 16; // bind
1941
1942 $export.W = 32; // wrap
1943
1944 $export.U = 64; // safe
1945
1946 $export.R = 128; // real proto method for `library`
1947
1948 var _export$1 = $export;
1949
1950 var _meta = createCommonjsModule$1(function (module) {
1951 var META = _uid('meta');
1952
1953 var setDesc = _objectDp.f;
1954 var id = 0;
1955
1956 var isExtensible = Object.isExtensible || function () {
1957 return true;
1958 };
1959
1960 var FREEZE = !_fails(function () {
1961 return isExtensible(Object.preventExtensions({}));
1962 });
1963
1964 var setMeta = function (it) {
1965 setDesc(it, META, {
1966 value: {
1967 i: 'O' + ++id,
1968 // object ID
1969 w: {} // weak collections IDs
1970
1971 }
1972 });
1973 };
1974
1975 var fastKey = function (it, create) {
1976 // return primitive with prefix
1977 if (!_isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
1978
1979 if (!_has(it, META)) {
1980 // can't set metadata to uncaught frozen object
1981 if (!isExtensible(it)) return 'F'; // not necessary to add metadata
1982
1983 if (!create) return 'E'; // add missing metadata
1984
1985 setMeta(it); // return object ID
1986 }
1987
1988 return it[META].i;
1989 };
1990
1991 var getWeak = function (it, create) {
1992 if (!_has(it, META)) {
1993 // can't set metadata to uncaught frozen object
1994 if (!isExtensible(it)) return true; // not necessary to add metadata
1995
1996 if (!create) return false; // add missing metadata
1997
1998 setMeta(it); // return hash weak collections IDs
1999 }
2000
2001 return it[META].w;
2002 }; // add metadata on freeze-family methods calling
2003
2004
2005 var onFreeze = function (it) {
2006 if (FREEZE && meta.NEED && isExtensible(it) && !_has(it, META)) setMeta(it);
2007 return it;
2008 };
2009
2010 var meta = module.exports = {
2011 KEY: META,
2012 NEED: false,
2013 fastKey: fastKey,
2014 getWeak: getWeak,
2015 onFreeze: onFreeze
2016 };
2017 });
2018
2019 var _meta_1 = _meta.KEY;
2020 var _meta_2 = _meta.NEED;
2021 var _meta_3 = _meta.fastKey;
2022 var _meta_4 = _meta.getWeak;
2023 var _meta_5 = _meta.onFreeze;
2024 var def = _objectDp.f;
2025
2026 var TAG = _wks('toStringTag');
2027
2028 var _setToStringTag = function (it, tag, stat) {
2029 if (it && !_has(it = stat ? it : it.prototype, TAG)) def(it, TAG, {
2030 configurable: true,
2031 value: tag
2032 });
2033 };
2034
2035 var toString$1 = {}.toString;
2036
2037 var _cof = function (it) {
2038 return toString$1.call(it).slice(8, -1);
2039 }; // eslint-disable-next-line no-prototype-builtins
2040
2041
2042 var _iobject = Object('z').propertyIsEnumerable(0) ? Object : function (it) {
2043 return _cof(it) == 'String' ? it.split('') : Object(it);
2044 }; // 7.2.1 RequireObjectCoercible(argument)
2045
2046
2047 var _defined = function (it) {
2048 if (it == undefined) throw TypeError("Can't call method on " + it);
2049 return it;
2050 };
2051
2052 var _toIobject = function (it) {
2053 return _iobject(_defined(it));
2054 }; // 7.1.4 ToInteger
2055
2056
2057 var ceil$1 = Math.ceil;
2058 var floor$2 = Math.floor;
2059
2060 var _toInteger = function (it) {
2061 return isNaN(it = +it) ? 0 : (it > 0 ? floor$2 : ceil$1)(it);
2062 };
2063
2064 var min$2 = Math.min;
2065
2066 var _toLength = function (it) {
2067 return it > 0 ? min$2(_toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991
2068 };
2069
2070 var max$1 = Math.max;
2071 var min$1$1 = Math.min;
2072
2073 var _toAbsoluteIndex = function (index, length) {
2074 index = _toInteger(index);
2075 return index < 0 ? max$1(index + length, 0) : min$1$1(index, length);
2076 }; // true -> Array#includes
2077
2078
2079 var _arrayIncludes = function (IS_INCLUDES) {
2080 return function ($this, el, fromIndex) {
2081 var O = _toIobject($this);
2082
2083 var length = _toLength(O.length);
2084
2085 var index = _toAbsoluteIndex(fromIndex, length);
2086
2087 var value; // Array#includes uses SameValueZero equality algorithm
2088 // eslint-disable-next-line no-self-compare
2089
2090 if (IS_INCLUDES && el != el) while (length > index) {
2091 value = O[index++]; // eslint-disable-next-line no-self-compare
2092
2093 if (value != value) return true; // Array#indexOf ignores holes, Array#includes - not
2094 } else for (; length > index; index++) if (IS_INCLUDES || index in O) {
2095 if (O[index] === el) return IS_INCLUDES || index || 0;
2096 }
2097 return !IS_INCLUDES && -1;
2098 };
2099 };
2100
2101 var shared$1 = _shared('keys');
2102
2103 var _sharedKey = function (key) {
2104 return shared$1[key] || (shared$1[key] = _uid(key));
2105 };
2106
2107 var arrayIndexOf = _arrayIncludes(false);
2108
2109 var IE_PROTO$1 = _sharedKey('IE_PROTO');
2110
2111 var _objectKeysInternal = function (object, names) {
2112 var O = _toIobject(object);
2113
2114 var i = 0;
2115 var result = [];
2116 var key;
2117
2118 for (key in O) if (key != IE_PROTO$1) _has(O, key) && result.push(key); // Don't enum bug & hidden keys
2119
2120
2121 while (names.length > i) if (_has(O, key = names[i++])) {
2122 ~arrayIndexOf(result, key) || result.push(key);
2123 }
2124
2125 return result;
2126 }; // IE 8- don't enum bug keys
2127
2128
2129 var _enumBugKeys = 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'.split(',');
2130
2131 var _objectKeys = Object.keys || function keys(O) {
2132 return _objectKeysInternal(O, _enumBugKeys);
2133 };
2134
2135 var f$2$1 = Object.getOwnPropertySymbols;
2136 var _objectGops = {
2137 f: f$2$1
2138 };
2139 var f$3$1 = {}.propertyIsEnumerable;
2140 var _objectPie = {
2141 f: f$3$1
2142 };
2143
2144 var _enumKeys = function (it) {
2145 var result = _objectKeys(it);
2146
2147 var getSymbols = _objectGops.f;
2148
2149 if (getSymbols) {
2150 var symbols = getSymbols(it);
2151 var isEnum = _objectPie.f;
2152 var i = 0;
2153 var key;
2154
2155 while (symbols.length > i) if (isEnum.call(it, key = symbols[i++])) result.push(key);
2156 }
2157
2158 return result;
2159 };
2160
2161 var _isArray = Array.isArray || function isArray(arg) {
2162 return _cof(arg) == 'Array';
2163 };
2164
2165 var _toObject = function (it) {
2166 return Object(_defined(it));
2167 };
2168
2169 var _objectDps = _descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
2170 _anObject(O);
2171
2172 var keys = _objectKeys(Properties);
2173
2174 var length = keys.length;
2175 var i = 0;
2176 var P;
2177
2178 while (length > i) _objectDp.f(O, P = keys[i++], Properties[P]);
2179
2180 return O;
2181 };
2182
2183 var document$2 = _global.document;
2184
2185 var _html = document$2 && document$2.documentElement;
2186
2187 var IE_PROTO$1$1 = _sharedKey('IE_PROTO');
2188
2189 var Empty = function () {
2190 /* empty */
2191 };
2192
2193 var PROTOTYPE$1$1 = 'prototype'; // Create object with fake `null` prototype: use iframe Object with cleared prototype
2194
2195 var createDict = function () {
2196 // Thrash, waste and sodomy: IE GC bug
2197 var iframe = _domCreate('iframe');
2198
2199 var i = _enumBugKeys.length;
2200 var lt = '<';
2201 var gt = '>';
2202 var iframeDocument;
2203 iframe.style.display = 'none';
2204
2205 _html.appendChild(iframe);
2206
2207 iframe.src = 'javascript:'; // eslint-disable-line no-script-url
2208 // createDict = iframe.contentWindow.Object;
2209 // html.removeChild(iframe);
2210
2211 iframeDocument = iframe.contentWindow.document;
2212 iframeDocument.open();
2213 iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt);
2214 iframeDocument.close();
2215 createDict = iframeDocument.F;
2216
2217 while (i--) delete createDict[PROTOTYPE$1$1][_enumBugKeys[i]];
2218
2219 return createDict();
2220 };
2221
2222 var _objectCreate = Object.create || function create(O, Properties) {
2223 var result;
2224
2225 if (O !== null) {
2226 Empty[PROTOTYPE$1$1] = _anObject(O);
2227 result = new Empty();
2228 Empty[PROTOTYPE$1$1] = null; // add "__proto__" for Object.getPrototypeOf polyfill
2229
2230 result[IE_PROTO$1$1] = O;
2231 } else result = createDict();
2232
2233 return Properties === undefined ? result : _objectDps(result, Properties);
2234 };
2235
2236 var hiddenKeys$2 = _enumBugKeys.concat('length', 'prototype');
2237
2238 var f$4$1 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
2239 return _objectKeysInternal(O, hiddenKeys$2);
2240 };
2241
2242 var _objectGopn = {
2243 f: f$4$1
2244 };
2245 var gOPN = _objectGopn.f;
2246 var toString$1$1 = {}.toString;
2247 var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : [];
2248
2249 var getWindowNames = function (it) {
2250 try {
2251 return gOPN(it);
2252 } catch (e) {
2253 return windowNames.slice();
2254 }
2255 };
2256
2257 var f$5$1 = function getOwnPropertyNames(it) {
2258 return windowNames && toString$1$1.call(it) == '[object Window]' ? getWindowNames(it) : gOPN(_toIobject(it));
2259 };
2260
2261 var _objectGopnExt = {
2262 f: f$5$1
2263 };
2264 var gOPD = Object.getOwnPropertyDescriptor;
2265 var f$6 = _descriptors ? gOPD : function getOwnPropertyDescriptor(O, P) {
2266 O = _toIobject(O);
2267 P = _toPrimitive(P, true);
2268 if (_ie8DomDefine) try {
2269 return gOPD(O, P);
2270 } catch (e) {
2271 /* empty */
2272 }
2273 if (_has(O, P)) return _propertyDesc(!_objectPie.f.call(O, P), O[P]);
2274 };
2275 var _objectGopd = {
2276 f: f$6
2277 };
2278 var META = _meta.KEY;
2279 var gOPD$1 = _objectGopd.f;
2280 var dP$1 = _objectDp.f;
2281 var gOPN$1 = _objectGopnExt.f;
2282 var $Symbol = _global.Symbol;
2283 var $JSON = _global.JSON;
2284
2285 var _stringify = $JSON && $JSON.stringify;
2286
2287 var PROTOTYPE$2 = 'prototype';
2288
2289 var HIDDEN = _wks('_hidden');
2290
2291 var TO_PRIMITIVE = _wks('toPrimitive');
2292
2293 var isEnum = {}.propertyIsEnumerable;
2294
2295 var SymbolRegistry = _shared('symbol-registry');
2296
2297 var AllSymbols = _shared('symbols');
2298
2299 var OPSymbols = _shared('op-symbols');
2300
2301 var ObjectProto = Object[PROTOTYPE$2];
2302 var USE_NATIVE = typeof $Symbol == 'function' && !!_objectGops.f;
2303 var QObject = _global.QObject; // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
2304
2305 var setter = !QObject || !QObject[PROTOTYPE$2] || !QObject[PROTOTYPE$2].findChild; // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
2306
2307 var setSymbolDesc = _descriptors && _fails(function () {
2308 return _objectCreate(dP$1({}, 'a', {
2309 get: function () {
2310 return dP$1(this, 'a', {
2311 value: 7
2312 }).a;
2313 }
2314 })).a != 7;
2315 }) ? function (it, key, D) {
2316 var protoDesc = gOPD$1(ObjectProto, key);
2317 if (protoDesc) delete ObjectProto[key];
2318 dP$1(it, key, D);
2319 if (protoDesc && it !== ObjectProto) dP$1(ObjectProto, key, protoDesc);
2320 } : dP$1;
2321
2322 var wrap = function (tag) {
2323 var sym = AllSymbols[tag] = _objectCreate($Symbol[PROTOTYPE$2]);
2324
2325 sym._k = tag;
2326 return sym;
2327 };
2328
2329 var isSymbol = USE_NATIVE && typeof $Symbol.iterator == 'symbol' ? function (it) {
2330 return typeof it == 'symbol';
2331 } : function (it) {
2332 return it instanceof $Symbol;
2333 };
2334
2335 var $defineProperty = function defineProperty(it, key, D) {
2336 if (it === ObjectProto) $defineProperty(OPSymbols, key, D);
2337
2338 _anObject(it);
2339
2340 key = _toPrimitive(key, true);
2341
2342 _anObject(D);
2343
2344 if (_has(AllSymbols, key)) {
2345 if (!D.enumerable) {
2346 if (!_has(it, HIDDEN)) dP$1(it, HIDDEN, _propertyDesc(1, {}));
2347 it[HIDDEN][key] = true;
2348 } else {
2349 if (_has(it, HIDDEN) && it[HIDDEN][key]) it[HIDDEN][key] = false;
2350 D = _objectCreate(D, {
2351 enumerable: _propertyDesc(0, false)
2352 });
2353 }
2354
2355 return setSymbolDesc(it, key, D);
2356 }
2357
2358 return dP$1(it, key, D);
2359 };
2360
2361 var $defineProperties = function defineProperties(it, P) {
2362 _anObject(it);
2363
2364 var keys = _enumKeys(P = _toIobject(P));
2365
2366 var i = 0;
2367 var l = keys.length;
2368 var key;
2369
2370 while (l > i) $defineProperty(it, key = keys[i++], P[key]);
2371
2372 return it;
2373 };
2374
2375 var $create = function create(it, P) {
2376 return P === undefined ? _objectCreate(it) : $defineProperties(_objectCreate(it), P);
2377 };
2378
2379 var $propertyIsEnumerable = function propertyIsEnumerable(key) {
2380 var E = isEnum.call(this, key = _toPrimitive(key, true));
2381 if (this === ObjectProto && _has(AllSymbols, key) && !_has(OPSymbols, key)) return false;
2382 return E || !_has(this, key) || !_has(AllSymbols, key) || _has(this, HIDDEN) && this[HIDDEN][key] ? E : true;
2383 };
2384
2385 var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key) {
2386 it = _toIobject(it);
2387 key = _toPrimitive(key, true);
2388 if (it === ObjectProto && _has(AllSymbols, key) && !_has(OPSymbols, key)) return;
2389 var D = gOPD$1(it, key);
2390 if (D && _has(AllSymbols, key) && !(_has(it, HIDDEN) && it[HIDDEN][key])) D.enumerable = true;
2391 return D;
2392 };
2393
2394 var $getOwnPropertyNames = function getOwnPropertyNames(it) {
2395 var names = gOPN$1(_toIobject(it));
2396 var result = [];
2397 var i = 0;
2398 var key;
2399
2400 while (names.length > i) {
2401 if (!_has(AllSymbols, key = names[i++]) && key != HIDDEN && key != META) result.push(key);
2402 }
2403
2404 return result;
2405 };
2406
2407 var $getOwnPropertySymbols = function getOwnPropertySymbols(it) {
2408 var IS_OP = it === ObjectProto;
2409 var names = gOPN$1(IS_OP ? OPSymbols : _toIobject(it));
2410 var result = [];
2411 var i = 0;
2412 var key;
2413
2414 while (names.length > i) {
2415 if (_has(AllSymbols, key = names[i++]) && (IS_OP ? _has(ObjectProto, key) : true)) result.push(AllSymbols[key]);
2416 }
2417
2418 return result;
2419 }; // 19.4.1.1 Symbol([description])
2420
2421
2422 if (!USE_NATIVE) {
2423 $Symbol = function Symbol() {
2424 if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor!');
2425
2426 var tag = _uid(arguments.length > 0 ? arguments[0] : undefined);
2427
2428 var $set = function (value) {
2429 if (this === ObjectProto) $set.call(OPSymbols, value);
2430 if (_has(this, HIDDEN) && _has(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
2431 setSymbolDesc(this, tag, _propertyDesc(1, value));
2432 };
2433
2434 if (_descriptors && setter) setSymbolDesc(ObjectProto, tag, {
2435 configurable: true,
2436 set: $set
2437 });
2438 return wrap(tag);
2439 };
2440
2441 _redefine($Symbol[PROTOTYPE$2], 'toString', function toString() {
2442 return this._k;
2443 });
2444
2445 _objectGopd.f = $getOwnPropertyDescriptor;
2446 _objectDp.f = $defineProperty;
2447 _objectGopn.f = _objectGopnExt.f = $getOwnPropertyNames;
2448 _objectPie.f = $propertyIsEnumerable;
2449 _objectGops.f = $getOwnPropertySymbols;
2450
2451 if (_descriptors && !_library) {
2452 _redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true);
2453 }
2454
2455 _wksExt.f = function (name) {
2456 return wrap(_wks(name));
2457 };
2458 }
2459
2460 _export$1(_export$1.G + _export$1.W + _export$1.F * !USE_NATIVE, {
2461 Symbol: $Symbol
2462 });
2463
2464 for (var es6Symbols = // 19.4.2.2, 19.4.2.3, 19.4.2.4, 19.4.2.6, 19.4.2.8, 19.4.2.9, 19.4.2.10, 19.4.2.11, 19.4.2.12, 19.4.2.13, 19.4.2.14
2465 'hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables'.split(','), j$1 = 0; es6Symbols.length > j$1;) _wks(es6Symbols[j$1++]);
2466
2467 for (var wellKnownSymbols = _objectKeys(_wks.store), k = 0; wellKnownSymbols.length > k;) _wksDefine(wellKnownSymbols[k++]);
2468
2469 _export$1(_export$1.S + _export$1.F * !USE_NATIVE, 'Symbol', {
2470 // 19.4.2.1 Symbol.for(key)
2471 'for': function (key) {
2472 return _has(SymbolRegistry, key += '') ? SymbolRegistry[key] : SymbolRegistry[key] = $Symbol(key);
2473 },
2474 // 19.4.2.5 Symbol.keyFor(sym)
2475 keyFor: function keyFor(sym) {
2476 if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol!');
2477
2478 for (var key in SymbolRegistry) if (SymbolRegistry[key] === sym) return key;
2479 },
2480 useSetter: function () {
2481 setter = true;
2482 },
2483 useSimple: function () {
2484 setter = false;
2485 }
2486 });
2487
2488 _export$1(_export$1.S + _export$1.F * !USE_NATIVE, 'Object', {
2489 // 19.1.2.2 Object.create(O [, Properties])
2490 create: $create,
2491 // 19.1.2.4 Object.defineProperty(O, P, Attributes)
2492 defineProperty: $defineProperty,
2493 // 19.1.2.3 Object.defineProperties(O, Properties)
2494 defineProperties: $defineProperties,
2495 // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)
2496 getOwnPropertyDescriptor: $getOwnPropertyDescriptor,
2497 // 19.1.2.7 Object.getOwnPropertyNames(O)
2498 getOwnPropertyNames: $getOwnPropertyNames,
2499 // 19.1.2.8 Object.getOwnPropertySymbols(O)
2500 getOwnPropertySymbols: $getOwnPropertySymbols
2501 }); // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
2502 // https://bugs.chromium.org/p/v8/issues/detail?id=3443
2503
2504
2505 var FAILS_ON_PRIMITIVES = _fails(function () {
2506 _objectGops.f(1);
2507 });
2508
2509 _export$1(_export$1.S + _export$1.F * FAILS_ON_PRIMITIVES, 'Object', {
2510 getOwnPropertySymbols: function getOwnPropertySymbols(it) {
2511 return _objectGops.f(_toObject(it));
2512 }
2513 }); // 24.3.2 JSON.stringify(value [, replacer [, space]])
2514
2515
2516 $JSON && _export$1(_export$1.S + _export$1.F * (!USE_NATIVE || _fails(function () {
2517 var S = $Symbol(); // MS Edge converts symbol values to JSON as {}
2518 // WebKit converts symbol values to JSON as null
2519 // V8 throws on boxed symbols
2520
2521 return _stringify([S]) != '[null]' || _stringify({
2522 a: S
2523 }) != '{}' || _stringify(Object(S)) != '{}';
2524 })), 'JSON', {
2525 stringify: function stringify(it) {
2526 var args = [it];
2527 var i = 1;
2528 var replacer, $replacer;
2529
2530 while (arguments.length > i) args.push(arguments[i++]);
2531
2532 $replacer = replacer = args[1];
2533 if (!_isObject(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined
2534
2535 if (!_isArray(replacer)) replacer = function (key, value) {
2536 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
2537 if (!isSymbol(value)) return value;
2538 };
2539 args[1] = replacer;
2540 return _stringify.apply($JSON, args);
2541 }
2542 }); // 19.4.3.4 Symbol.prototype[@@toPrimitive](hint)
2543
2544 $Symbol[PROTOTYPE$2][TO_PRIMITIVE] || _hide($Symbol[PROTOTYPE$2], TO_PRIMITIVE, $Symbol[PROTOTYPE$2].valueOf); // 19.4.3.5 Symbol.prototype[@@toStringTag]
2545
2546 _setToStringTag($Symbol, 'Symbol'); // 20.2.1.9 Math[@@toStringTag]
2547
2548
2549 _setToStringTag(Math, 'Math', true); // 24.3.3 JSON[@@toStringTag]
2550
2551
2552 _setToStringTag(_global.JSON, 'JSON', true);
2553
2554 function _typeof(obj) {
2555 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
2556 _typeof = function (obj) {
2557 return typeof obj;
2558 };
2559 } else {
2560 _typeof = function (obj) {
2561 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
2562 };
2563 }
2564
2565 return _typeof(obj);
2566 }
2567
2568 function _defineProperty(obj, key, value) {
2569 if (key in obj) {
2570 Object.defineProperty(obj, key, {
2571 value: value,
2572 enumerable: true,
2573 configurable: true,
2574 writable: true
2575 });
2576 } else {
2577 obj[key] = value;
2578 }
2579
2580 return obj;
2581 }
2582
2583 function ownKeys$1(object, enumerableOnly) {
2584 var keys = Object.keys(object);
2585
2586 if (Object.getOwnPropertySymbols) {
2587 var symbols = Object.getOwnPropertySymbols(object);
2588 if (enumerableOnly) symbols = symbols.filter(function (sym) {
2589 return Object.getOwnPropertyDescriptor(object, sym).enumerable;
2590 });
2591 keys.push.apply(keys, symbols);
2592 }
2593
2594 return keys;
2595 }
2596
2597 function _objectSpread2(target) {
2598 for (var i = 1; i < arguments.length; i++) {
2599 var source = arguments[i] != null ? arguments[i] : {};
2600
2601 if (i % 2) {
2602 ownKeys$1(source, true).forEach(function (key) {
2603 _defineProperty(target, key, source[key]);
2604 });
2605 } else if (Object.getOwnPropertyDescriptors) {
2606 Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
2607 } else {
2608 ownKeys$1(source).forEach(function (key) {
2609 Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
2610 });
2611 }
2612 }
2613
2614 return target;
2615 }
2616
2617 function _toConsumableArray(arr) {
2618 return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
2619 }
2620
2621 function _arrayWithoutHoles(arr) {
2622 if (Array.isArray(arr)) {
2623 for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
2624
2625 return arr2;
2626 }
2627 }
2628
2629 function _iterableToArray(iter) {
2630 if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
2631 }
2632
2633 function _nonIterableSpread() {
2634 throw new TypeError("Invalid attempt to spread non-iterable instance");
2635 }
2636
2637 var _objectSap = function (KEY, exec) {
2638 var fn = (_core.Object || {})[KEY] || Object[KEY];
2639 var exp = {};
2640 exp[KEY] = exec(fn);
2641
2642 _export$1(_export$1.S + _export$1.F * _fails(function () {
2643 fn(1);
2644 }), 'Object', exp);
2645 };
2646
2647 _objectSap('keys', function () {
2648 return function keys(it) {
2649 return _objectKeys(_toObject(it));
2650 };
2651 });
2652
2653 var _flags = function () {
2654 var that = _anObject(this);
2655
2656 var result = '';
2657 if (that.global) result += 'g';
2658 if (that.ignoreCase) result += 'i';
2659 if (that.multiline) result += 'm';
2660 if (that.unicode) result += 'u';
2661 if (that.sticky) result += 'y';
2662 return result;
2663 };
2664
2665 if (_descriptors && /./g.flags != 'g') _objectDp.f(RegExp.prototype, 'flags', {
2666 configurable: true,
2667 get: _flags
2668 });
2669 var TO_STRING = 'toString';
2670 var $toString = /./[TO_STRING];
2671
2672 var define = function (fn) {
2673 _redefine(RegExp.prototype, TO_STRING, fn, true);
2674 }; // 21.2.5.14 RegExp.prototype.toString()
2675
2676
2677 if (_fails(function () {
2678 return $toString.call({
2679 source: 'a',
2680 flags: 'b'
2681 }) != '/a/b';
2682 })) {
2683 define(function toString() {
2684 var R = _anObject(this);
2685
2686 return '/'.concat(R.source, '/', 'flags' in R ? R.flags : !_descriptors && R instanceof RegExp ? _flags.call(R) : undefined);
2687 }); // FF44- RegExp#toString has a wrong name
2688 } else if ($toString.name != TO_STRING) {
2689 define(function toString() {
2690 return $toString.call(this);
2691 });
2692 } // false -> String#codePointAt
2693
2694
2695 var _stringAt = function (TO_STRING) {
2696 return function (that, pos) {
2697 var s = String(_defined(that));
2698
2699 var i = _toInteger(pos);
2700
2701 var l = s.length;
2702 var a, b;
2703 if (i < 0 || i >= l) return TO_STRING ? '' : undefined;
2704 a = s.charCodeAt(i);
2705 return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff ? TO_STRING ? s.charAt(i) : a : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000;
2706 };
2707 };
2708
2709 var at = _stringAt(true); // `AdvanceStringIndex` abstract operation
2710 // https://tc39.github.io/ecma262/#sec-advancestringindex
2711
2712
2713 var _advanceStringIndex = function (S, index, unicode) {
2714 return index + (unicode ? at(S, index).length : 1);
2715 };
2716
2717 var TAG$1 = _wks('toStringTag'); // ES3 wrong here
2718
2719
2720 var ARG = _cof(function () {
2721 return arguments;
2722 }()) == 'Arguments'; // fallback for IE11 Script Access Denied error
2723
2724 var tryGet$1 = function (it, key) {
2725 try {
2726 return it[key];
2727 } catch (e) {
2728 /* empty */
2729 }
2730 };
2731
2732 var _classof = function (it) {
2733 var O, T, B;
2734 return it === undefined ? 'Undefined' : it === null ? 'Null' // @@toStringTag case
2735 : typeof (T = tryGet$1(O = Object(it), TAG$1)) == 'string' ? T // builtinTag case
2736 : ARG ? _cof(O) // ES3 arguments fallback
2737 : (B = _cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;
2738 };
2739
2740 var builtinExec = RegExp.prototype.exec; // `RegExpExec` abstract operation
2741 // https://tc39.github.io/ecma262/#sec-regexpexec
2742
2743 var _regexpExecAbstract = function (R, S) {
2744 var exec = R.exec;
2745
2746 if (typeof exec === 'function') {
2747 var result = exec.call(R, S);
2748
2749 if (typeof result !== 'object') {
2750 throw new TypeError('RegExp exec method returned something other than an Object or null');
2751 }
2752
2753 return result;
2754 }
2755
2756 if (_classof(R) !== 'RegExp') {
2757 throw new TypeError('RegExp#exec called on incompatible receiver');
2758 }
2759
2760 return builtinExec.call(R, S);
2761 };
2762
2763 var nativeExec = RegExp.prototype.exec; // This always refers to the native implementation, because the
2764 // String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js,
2765 // which loads this file before patching the method.
2766
2767 var nativeReplace = String.prototype.replace;
2768 var patchedExec = nativeExec;
2769 var LAST_INDEX = 'lastIndex';
2770
2771 var UPDATES_LAST_INDEX_WRONG = function () {
2772 var re1 = /a/,
2773 re2 = /b*/g;
2774 nativeExec.call(re1, 'a');
2775 nativeExec.call(re2, 'a');
2776 return re1[LAST_INDEX] !== 0 || re2[LAST_INDEX] !== 0;
2777 }(); // nonparticipating capturing group, copied from es5-shim's String#split patch.
2778
2779
2780 var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
2781 var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED;
2782
2783 if (PATCH) {
2784 patchedExec = function exec(str) {
2785 var re = this;
2786 var lastIndex, reCopy, match, i;
2787
2788 if (NPCG_INCLUDED) {
2789 reCopy = new RegExp('^' + re.source + '$(?!\\s)', _flags.call(re));
2790 }
2791
2792 if (UPDATES_LAST_INDEX_WRONG) lastIndex = re[LAST_INDEX];
2793 match = nativeExec.call(re, str);
2794
2795 if (UPDATES_LAST_INDEX_WRONG && match) {
2796 re[LAST_INDEX] = re.global ? match.index + match[0].length : lastIndex;
2797 }
2798
2799 if (NPCG_INCLUDED && match && match.length > 1) {
2800 // Fix browsers whose `exec` methods don't consistently return `undefined`
2801 // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
2802 // eslint-disable-next-line no-loop-func
2803 nativeReplace.call(match[0], reCopy, function () {
2804 for (i = 1; i < arguments.length - 2; i++) {
2805 if (arguments[i] === undefined) match[i] = undefined;
2806 }
2807 });
2808 }
2809
2810 return match;
2811 };
2812 }
2813
2814 var _regexpExec = patchedExec;
2815
2816 _export$1({
2817 target: 'RegExp',
2818 proto: true,
2819 forced: _regexpExec !== /./.exec
2820 }, {
2821 exec: _regexpExec
2822 });
2823
2824 var SPECIES$1 = _wks('species');
2825
2826 var REPLACE_SUPPORTS_NAMED_GROUPS = !_fails(function () {
2827 // #replace needs built-in support for named groups.
2828 // #match works fine because it just return the exec results, even if it has
2829 // a "grops" property.
2830 var re = /./;
2831
2832 re.exec = function () {
2833 var result = [];
2834 result.groups = {
2835 a: '7'
2836 };
2837 return result;
2838 };
2839
2840 return ''.replace(re, '$<a>') !== '7';
2841 });
2842
2843 var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = function () {
2844 // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
2845 var re = /(?:)/;
2846 var originalExec = re.exec;
2847
2848 re.exec = function () {
2849 return originalExec.apply(this, arguments);
2850 };
2851
2852 var result = 'ab'.split(re);
2853 return result.length === 2 && result[0] === 'a' && result[1] === 'b';
2854 }();
2855
2856 var _fixReWks = function (KEY, length, exec) {
2857 var SYMBOL = _wks(KEY);
2858
2859 var DELEGATES_TO_SYMBOL = !_fails(function () {
2860 // String methods call symbol-named RegEp methods
2861 var O = {};
2862
2863 O[SYMBOL] = function () {
2864 return 7;
2865 };
2866
2867 return ''[KEY](O) != 7;
2868 });
2869 var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL ? !_fails(function () {
2870 // Symbol-named RegExp methods call .exec
2871 var execCalled = false;
2872 var re = /a/;
2873
2874 re.exec = function () {
2875 execCalled = true;
2876 return null;
2877 };
2878
2879 if (KEY === 'split') {
2880 // RegExp[@@split] doesn't call the regex's exec method, but first creates
2881 // a new one. We need to return the patched regex when creating the new one.
2882 re.constructor = {};
2883
2884 re.constructor[SPECIES$1] = function () {
2885 return re;
2886 };
2887 }
2888
2889 re[SYMBOL]('');
2890 return !execCalled;
2891 }) : undefined;
2892
2893 if (!DELEGATES_TO_SYMBOL || !DELEGATES_TO_EXEC || KEY === 'replace' && !REPLACE_SUPPORTS_NAMED_GROUPS || KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC) {
2894 var nativeRegExpMethod = /./[SYMBOL];
2895 var fns = exec(_defined, SYMBOL, ''[KEY], function maybeCallNative(nativeMethod, regexp, str, arg2, forceStringMethod) {
2896 if (regexp.exec === _regexpExec) {
2897 if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
2898 // The native String method already delegates to @@method (this
2899 // polyfilled function), leasing to infinite recursion.
2900 // We avoid it by directly calling the native @@method method.
2901 return {
2902 done: true,
2903 value: nativeRegExpMethod.call(regexp, str, arg2)
2904 };
2905 }
2906
2907 return {
2908 done: true,
2909 value: nativeMethod.call(str, regexp, arg2)
2910 };
2911 }
2912
2913 return {
2914 done: false
2915 };
2916 });
2917 var strfn = fns[0];
2918 var rxfn = fns[1];
2919
2920 _redefine(String.prototype, KEY, strfn);
2921
2922 _hide(RegExp.prototype, SYMBOL, length == 2 // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
2923 // 21.2.5.11 RegExp.prototype[@@split](string, limit)
2924 ? function (string, arg) {
2925 return rxfn.call(string, this, arg);
2926 } // 21.2.5.6 RegExp.prototype[@@match](string)
2927 // 21.2.5.9 RegExp.prototype[@@search](string)
2928 : function (string) {
2929 return rxfn.call(string, this);
2930 });
2931 }
2932 };
2933
2934 var max$1$1 = Math.max;
2935 var min$2$1 = Math.min;
2936 var floor$1$1 = Math.floor;
2937 var SUBSTITUTION_SYMBOLS = /\$([$&`']|\d\d?|<[^>]*>)/g;
2938 var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&`']|\d\d?)/g;
2939
2940 var maybeToString = function (it) {
2941 return it === undefined ? it : String(it);
2942 }; // @@replace logic
2943
2944
2945 _fixReWks('replace', 2, function (defined, REPLACE, $replace, maybeCallNative) {
2946 return [// `String.prototype.replace` method
2947 // https://tc39.github.io/ecma262/#sec-string.prototype.replace
2948 function replace(searchValue, replaceValue) {
2949 var O = defined(this);
2950 var fn = searchValue == undefined ? undefined : searchValue[REPLACE];
2951 return fn !== undefined ? fn.call(searchValue, O, replaceValue) : $replace.call(String(O), searchValue, replaceValue);
2952 }, // `RegExp.prototype[@@replace]` method
2953 // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace
2954 function (regexp, replaceValue) {
2955 var res = maybeCallNative($replace, regexp, this, replaceValue);
2956 if (res.done) return res.value;
2957
2958 var rx = _anObject(regexp);
2959
2960 var S = String(this);
2961 var functionalReplace = typeof replaceValue === 'function';
2962 if (!functionalReplace) replaceValue = String(replaceValue);
2963 var global = rx.global;
2964
2965 if (global) {
2966 var fullUnicode = rx.unicode;
2967 rx.lastIndex = 0;
2968 }
2969
2970 var results = [];
2971
2972 while (true) {
2973 var result = _regexpExecAbstract(rx, S);
2974
2975 if (result === null) break;
2976 results.push(result);
2977 if (!global) break;
2978 var matchStr = String(result[0]);
2979 if (matchStr === '') rx.lastIndex = _advanceStringIndex(S, _toLength(rx.lastIndex), fullUnicode);
2980 }
2981
2982 var accumulatedResult = '';
2983 var nextSourcePosition = 0;
2984
2985 for (var i = 0; i < results.length; i++) {
2986 result = results[i];
2987 var matched = String(result[0]);
2988 var position = max$1$1(min$2$1(_toInteger(result.index), S.length), 0);
2989 var captures = []; // NOTE: This is equivalent to
2990 // captures = result.slice(1).map(maybeToString)
2991 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
2992 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
2993 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
2994
2995 for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
2996
2997 var namedCaptures = result.groups;
2998
2999 if (functionalReplace) {
3000 var replacerArgs = [matched].concat(captures, position, S);
3001 if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
3002 var replacement = String(replaceValue.apply(undefined, replacerArgs));
3003 } else {
3004 replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
3005 }
3006
3007 if (position >= nextSourcePosition) {
3008 accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
3009 nextSourcePosition = position + matched.length;
3010 }
3011 }
3012
3013 return accumulatedResult + S.slice(nextSourcePosition);
3014 }]; // https://tc39.github.io/ecma262/#sec-getsubstitution
3015
3016 function getSubstitution(matched, str, position, captures, namedCaptures, replacement) {
3017 var tailPos = position + matched.length;
3018 var m = captures.length;
3019 var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
3020
3021 if (namedCaptures !== undefined) {
3022 namedCaptures = _toObject(namedCaptures);
3023 symbols = SUBSTITUTION_SYMBOLS;
3024 }
3025
3026 return $replace.call(replacement, symbols, function (match, ch) {
3027 var capture;
3028
3029 switch (ch.charAt(0)) {
3030 case '$':
3031 return '$';
3032
3033 case '&':
3034 return matched;
3035
3036 case '`':
3037 return str.slice(0, position);
3038
3039 case "'":
3040 return str.slice(tailPos);
3041
3042 case '<':
3043 capture = namedCaptures[ch.slice(1, -1)];
3044 break;
3045
3046 default:
3047 // \d\d?
3048 var n = +ch;
3049 if (n === 0) return match;
3050
3051 if (n > m) {
3052 var f = floor$1$1(n / 10);
3053 if (f === 0) return match;
3054 if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
3055 return match;
3056 }
3057
3058 capture = captures[n - 1];
3059 }
3060
3061 return capture === undefined ? '' : capture;
3062 });
3063 }
3064 });
3065
3066 var UNSCOPABLES = _wks('unscopables');
3067
3068 var ArrayProto = Array.prototype;
3069 if (ArrayProto[UNSCOPABLES] == undefined) _hide(ArrayProto, UNSCOPABLES, {});
3070
3071 var _addToUnscopables = function (key) {
3072 ArrayProto[UNSCOPABLES][key] = true;
3073 };
3074
3075 var _iterStep = function (done, value) {
3076 return {
3077 value: value,
3078 done: !!done
3079 };
3080 };
3081
3082 var _iterators = {};
3083 var IteratorPrototype = {}; // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
3084
3085 _hide(IteratorPrototype, _wks('iterator'), function () {
3086 return this;
3087 });
3088
3089 var _iterCreate = function (Constructor, NAME, next) {
3090 Constructor.prototype = _objectCreate(IteratorPrototype, {
3091 next: _propertyDesc(1, next)
3092 });
3093
3094 _setToStringTag(Constructor, NAME + ' Iterator');
3095 };
3096
3097 var IE_PROTO$2 = _sharedKey('IE_PROTO');
3098
3099 var ObjectProto$1 = Object.prototype;
3100
3101 var _objectGpo = Object.getPrototypeOf || function (O) {
3102 O = _toObject(O);
3103 if (_has(O, IE_PROTO$2)) return O[IE_PROTO$2];
3104
3105 if (typeof O.constructor == 'function' && O instanceof O.constructor) {
3106 return O.constructor.prototype;
3107 }
3108
3109 return O instanceof Object ? ObjectProto$1 : null;
3110 };
3111
3112 var ITERATOR = _wks('iterator');
3113
3114 var BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next`
3115
3116 var FF_ITERATOR = '@@iterator';
3117 var KEYS = 'keys';
3118 var VALUES = 'values';
3119
3120 var returnThis = function () {
3121 return this;
3122 };
3123
3124 var _iterDefine = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) {
3125 _iterCreate(Constructor, NAME, next);
3126
3127 var getMethod = function (kind) {
3128 if (!BUGGY && kind in proto) return proto[kind];
3129
3130 switch (kind) {
3131 case KEYS:
3132 return function keys() {
3133 return new Constructor(this, kind);
3134 };
3135
3136 case VALUES:
3137 return function values() {
3138 return new Constructor(this, kind);
3139 };
3140 }
3141
3142 return function entries() {
3143 return new Constructor(this, kind);
3144 };
3145 };
3146
3147 var TAG = NAME + ' Iterator';
3148 var DEF_VALUES = DEFAULT == VALUES;
3149 var VALUES_BUG = false;
3150 var proto = Base.prototype;
3151 var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];
3152 var $default = $native || getMethod(DEFAULT);
3153 var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;
3154 var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;
3155 var methods, key, IteratorPrototype; // Fix native
3156
3157 if ($anyNative) {
3158 IteratorPrototype = _objectGpo($anyNative.call(new Base()));
3159
3160 if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) {
3161 // Set @@toStringTag to native iterators
3162 _setToStringTag(IteratorPrototype, TAG, true); // fix for some old engines
3163
3164
3165 if (typeof IteratorPrototype[ITERATOR] != 'function') _hide(IteratorPrototype, ITERATOR, returnThis);
3166 }
3167 } // fix Array#{values, @@iterator}.name in V8 / FF
3168
3169
3170 if (DEF_VALUES && $native && $native.name !== VALUES) {
3171 VALUES_BUG = true;
3172
3173 $default = function values() {
3174 return $native.call(this);
3175 };
3176 } // Define iterator
3177
3178
3179 if (BUGGY || VALUES_BUG || !proto[ITERATOR]) {
3180 _hide(proto, ITERATOR, $default);
3181 } // Plug for library
3182
3183
3184 _iterators[NAME] = $default;
3185 _iterators[TAG] = returnThis;
3186
3187 if (DEFAULT) {
3188 methods = {
3189 values: DEF_VALUES ? $default : getMethod(VALUES),
3190 keys: IS_SET ? $default : getMethod(KEYS),
3191 entries: $entries
3192 };
3193 if (FORCED) for (key in methods) {
3194 if (!(key in proto)) _redefine(proto, key, methods[key]);
3195 } else _export$1(_export$1.P + _export$1.F * (BUGGY || VALUES_BUG), NAME, methods);
3196 }
3197
3198 return methods;
3199 }; // 22.1.3.13 Array.prototype.keys()
3200 // 22.1.3.29 Array.prototype.values()
3201 // 22.1.3.30 Array.prototype[@@iterator]()
3202
3203
3204 var es6_array_iterator = _iterDefine(Array, 'Array', function (iterated, kind) {
3205 this._t = _toIobject(iterated); // target
3206
3207 this._i = 0; // next index
3208
3209 this._k = kind; // kind
3210 // 22.1.5.2.1 %ArrayIteratorPrototype%.next()
3211 }, function () {
3212 var O = this._t;
3213 var kind = this._k;
3214 var index = this._i++;
3215
3216 if (!O || index >= O.length) {
3217 this._t = undefined;
3218 return _iterStep(1);
3219 }
3220
3221 if (kind == 'keys') return _iterStep(0, index);
3222 if (kind == 'values') return _iterStep(0, O[index]);
3223 return _iterStep(0, [index, O[index]]);
3224 }, 'values'); // argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7)
3225
3226
3227 _iterators.Arguments = _iterators.Array;
3228
3229 _addToUnscopables('keys');
3230
3231 _addToUnscopables('values');
3232
3233 _addToUnscopables('entries');
3234
3235 var ITERATOR$1 = _wks('iterator');
3236
3237 var TO_STRING_TAG$4 = _wks('toStringTag');
3238
3239 var ArrayValues = _iterators.Array;
3240 var DOMIterables = {
3241 CSSRuleList: true,
3242 // TODO: Not spec compliant, should be false.
3243 CSSStyleDeclaration: false,
3244 CSSValueList: false,
3245 ClientRectList: false,
3246 DOMRectList: false,
3247 DOMStringList: false,
3248 DOMTokenList: true,
3249 DataTransferItemList: false,
3250 FileList: false,
3251 HTMLAllCollection: false,
3252 HTMLCollection: false,
3253 HTMLFormElement: false,
3254 HTMLSelectElement: false,
3255 MediaList: true,
3256 // TODO: Not spec compliant, should be false.
3257 MimeTypeArray: false,
3258 NamedNodeMap: false,
3259 NodeList: true,
3260 PaintRequestList: false,
3261 Plugin: false,
3262 PluginArray: false,
3263 SVGLengthList: false,
3264 SVGNumberList: false,
3265 SVGPathSegList: false,
3266 SVGPointList: false,
3267 SVGStringList: false,
3268 SVGTransformList: false,
3269 SourceBufferList: false,
3270 StyleSheetList: true,
3271 // TODO: Not spec compliant, should be false.
3272 TextTrackCueList: false,
3273 TextTrackList: false,
3274 TouchList: false
3275 };
3276
3277 for (var collections = _objectKeys(DOMIterables), i = 0; i < collections.length; i++) {
3278 var NAME$1 = collections[i];
3279 var explicit = DOMIterables[NAME$1];
3280 var Collection = _global[NAME$1];
3281 var proto = Collection && Collection.prototype;
3282 var key$1;
3283
3284 if (proto) {
3285 if (!proto[ITERATOR$1]) _hide(proto, ITERATOR$1, ArrayValues);
3286 if (!proto[TO_STRING_TAG$4]) _hide(proto, TO_STRING_TAG$4, NAME$1);
3287 _iterators[NAME$1] = ArrayValues;
3288 if (explicit) for (key$1 in es6_array_iterator) if (!proto[key$1]) _redefine(proto, key$1, es6_array_iterator[key$1], true);
3289 }
3290 }
3291
3292 var test$1 = {};
3293 test$1[_wks('toStringTag')] = 'z';
3294
3295 if (test$1 + '' != '[object z]') {
3296 _redefine(Object.prototype, 'toString', function toString() {
3297 return '[object ' + _classof(this) + ']';
3298 }, true);
3299 }
3300
3301 var isEnum$1 = _objectPie.f;
3302
3303 var _objectToArray = function (isEntries) {
3304 return function (it) {
3305 var O = _toIobject(it);
3306
3307 var keys = _objectKeys(O);
3308
3309 var length = keys.length;
3310 var i = 0;
3311 var result = [];
3312 var key;
3313
3314 while (length > i) {
3315 key = keys[i++];
3316
3317 if (!_descriptors || isEnum$1.call(O, key)) {
3318 result.push(isEntries ? [key, O[key]] : O[key]);
3319 }
3320 }
3321
3322 return result;
3323 };
3324 };
3325
3326 var $values = _objectToArray(false);
3327
3328 _export$1(_export$1.S, 'Object', {
3329 values: function values(it) {
3330 return $values(it);
3331 }
3332 });
3333
3334 var MATCH = _wks('match');
3335
3336 var _isRegexp = function (it) {
3337 var isRegExp;
3338 return _isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : _cof(it) == 'RegExp');
3339 };
3340
3341 var SPECIES$1$1 = _wks('species');
3342
3343 var _speciesConstructor = function (O, D) {
3344 var C = _anObject(O).constructor;
3345
3346 var S;
3347 return C === undefined || (S = _anObject(C)[SPECIES$1$1]) == undefined ? D : _aFunction(S);
3348 };
3349
3350 var $min = Math.min;
3351 var $push = [].push;
3352 var $SPLIT = 'split';
3353 var LENGTH = 'length';
3354 var LAST_INDEX$1 = 'lastIndex';
3355 var MAX_UINT32 = 0xffffffff; // babel-minify transpiles RegExp('x', 'y') -> /x/y and it causes SyntaxError
3356
3357 var SUPPORTS_Y = !_fails(function () {
3358 RegExp(MAX_UINT32, 'y');
3359 }); // @@split logic
3360
3361 _fixReWks('split', 2, function (defined, SPLIT, $split, maybeCallNative) {
3362 var internalSplit;
3363
3364 if ('abbc'[$SPLIT](/(b)*/)[1] == 'c' || 'test'[$SPLIT](/(?:)/, -1)[LENGTH] != 4 || 'ab'[$SPLIT](/(?:ab)*/)[LENGTH] != 2 || '.'[$SPLIT](/(.?)(.?)/)[LENGTH] != 4 || '.'[$SPLIT](/()()/)[LENGTH] > 1 || ''[$SPLIT](/.?/)[LENGTH]) {
3365 // based on es5-shim implementation, need to rework it
3366 internalSplit = function (separator, limit) {
3367 var string = String(this);
3368 if (separator === undefined && limit === 0) return []; // If `separator` is not a regex, use native split
3369
3370 if (!_isRegexp(separator)) return $split.call(string, separator, limit);
3371 var output = [];
3372 var flags = (separator.ignoreCase ? 'i' : '') + (separator.multiline ? 'm' : '') + (separator.unicode ? 'u' : '') + (separator.sticky ? 'y' : '');
3373 var lastLastIndex = 0;
3374 var splitLimit = limit === undefined ? MAX_UINT32 : limit >>> 0; // Make `global` and avoid `lastIndex` issues by working with a copy
3375
3376 var separatorCopy = new RegExp(separator.source, flags + 'g');
3377 var match, lastIndex, lastLength;
3378
3379 while (match = _regexpExec.call(separatorCopy, string)) {
3380 lastIndex = separatorCopy[LAST_INDEX$1];
3381
3382 if (lastIndex > lastLastIndex) {
3383 output.push(string.slice(lastLastIndex, match.index));
3384 if (match[LENGTH] > 1 && match.index < string[LENGTH]) $push.apply(output, match.slice(1));
3385 lastLength = match[0][LENGTH];
3386 lastLastIndex = lastIndex;
3387 if (output[LENGTH] >= splitLimit) break;
3388 }
3389
3390 if (separatorCopy[LAST_INDEX$1] === match.index) separatorCopy[LAST_INDEX$1]++; // Avoid an infinite loop
3391 }
3392
3393 if (lastLastIndex === string[LENGTH]) {
3394 if (lastLength || !separatorCopy.test('')) output.push('');
3395 } else output.push(string.slice(lastLastIndex));
3396
3397 return output[LENGTH] > splitLimit ? output.slice(0, splitLimit) : output;
3398 }; // Chakra, V8
3399
3400 } else if ('0'[$SPLIT](undefined, 0)[LENGTH]) {
3401 internalSplit = function (separator, limit) {
3402 return separator === undefined && limit === 0 ? [] : $split.call(this, separator, limit);
3403 };
3404 } else {
3405 internalSplit = $split;
3406 }
3407
3408 return [// `String.prototype.split` method
3409 // https://tc39.github.io/ecma262/#sec-string.prototype.split
3410 function split(separator, limit) {
3411 var O = defined(this);
3412 var splitter = separator == undefined ? undefined : separator[SPLIT];
3413 return splitter !== undefined ? splitter.call(separator, O, limit) : internalSplit.call(String(O), separator, limit);
3414 }, // `RegExp.prototype[@@split]` method
3415 // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@split
3416 //
3417 // NOTE: This cannot be properly polyfilled in engines that don't support
3418 // the 'y' flag.
3419 function (regexp, limit) {
3420 var res = maybeCallNative(internalSplit, regexp, this, limit, internalSplit !== $split);
3421 if (res.done) return res.value;
3422
3423 var rx = _anObject(regexp);
3424
3425 var S = String(this);
3426
3427 var C = _speciesConstructor(rx, RegExp);
3428
3429 var unicodeMatching = rx.unicode;
3430 var flags = (rx.ignoreCase ? 'i' : '') + (rx.multiline ? 'm' : '') + (rx.unicode ? 'u' : '') + (SUPPORTS_Y ? 'y' : 'g'); // ^(? + rx + ) is needed, in combination with some S slicing, to
3431 // simulate the 'y' flag.
3432
3433 var splitter = new C(SUPPORTS_Y ? rx : '^(?:' + rx.source + ')', flags);
3434 var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
3435 if (lim === 0) return [];
3436 if (S.length === 0) return _regexpExecAbstract(splitter, S) === null ? [S] : [];
3437 var p = 0;
3438 var q = 0;
3439 var A = [];
3440
3441 while (q < S.length) {
3442 splitter.lastIndex = SUPPORTS_Y ? q : 0;
3443
3444 var z = _regexpExecAbstract(splitter, SUPPORTS_Y ? S : S.slice(q));
3445
3446 var e;
3447
3448 if (z === null || (e = $min(_toLength(splitter.lastIndex + (SUPPORTS_Y ? 0 : q)), S.length)) === p) {
3449 q = _advanceStringIndex(S, q, unicodeMatching);
3450 } else {
3451 A.push(S.slice(p, q));
3452 if (A.length === lim) return A;
3453
3454 for (var i = 1; i <= z.length - 1; i++) {
3455 A.push(z[i]);
3456 if (A.length === lim) return A;
3457 }
3458
3459 q = p = e;
3460 }
3461 }
3462
3463 A.push(S.slice(p));
3464 return A;
3465 }];
3466 });
3467
3468 var $assign = Object.assign; // should work with symbols and should have deterministic property order (V8 bug)
3469
3470 var _objectAssign = !$assign || _fails(function () {
3471 var A = {};
3472 var B = {}; // eslint-disable-next-line no-undef
3473
3474 var S = Symbol();
3475 var K = 'abcdefghijklmnopqrst';
3476 A[S] = 7;
3477 K.split('').forEach(function (k) {
3478 B[k] = k;
3479 });
3480 return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;
3481 }) ? function assign(target, source) {
3482 // eslint-disable-line no-unused-vars
3483 var T = _toObject(target);
3484
3485 var aLen = arguments.length;
3486 var index = 1;
3487 var getSymbols = _objectGops.f;
3488 var isEnum = _objectPie.f;
3489
3490 while (aLen > index) {
3491 var S = _iobject(arguments[index++]);
3492
3493 var keys = getSymbols ? _objectKeys(S).concat(getSymbols(S)) : _objectKeys(S);
3494 var length = keys.length;
3495 var j = 0;
3496 var key;
3497
3498 while (length > j) {
3499 key = keys[j++];
3500 if (!_descriptors || isEnum.call(S, key)) T[key] = S[key];
3501 }
3502 }
3503
3504 return T;
3505 } : $assign;
3506
3507 _export$1(_export$1.S + _export$1.F, 'Object', {
3508 assign: _objectAssign
3509 });
3510 /* eslint-disable no-proto */
3511
3512
3513 var check$1 = function (O, proto) {
3514 _anObject(O);
3515
3516 if (!_isObject(proto) && proto !== null) throw TypeError(proto + ": can't set as prototype!");
3517 };
3518
3519 var _setProto = {
3520 set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line
3521 function (test, buggy, set) {
3522 try {
3523 set = _ctx(Function.call, _objectGopd.f(Object.prototype, '__proto__').set, 2);
3524 set(test, []);
3525 buggy = !(test instanceof Array);
3526 } catch (e) {
3527 buggy = true;
3528 }
3529
3530 return function setPrototypeOf(O, proto) {
3531 check$1(O, proto);
3532 if (buggy) O.__proto__ = proto;else set(O, proto);
3533 return O;
3534 };
3535 }({}, false) : undefined),
3536 check: check$1
3537 };
3538 var setPrototypeOf = _setProto.set;
3539
3540 var _inheritIfRequired = function (that, target, C) {
3541 var S = target.constructor;
3542 var P;
3543
3544 if (S !== C && typeof S == 'function' && (P = S.prototype) !== C.prototype && _isObject(P) && setPrototypeOf) {
3545 setPrototypeOf(that, P);
3546 }
3547
3548 return that;
3549 };
3550
3551 var _stringWs = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
3552
3553 var space = '[' + _stringWs + ']';
3554 var non = '\u200b\u0085';
3555 var ltrim = RegExp('^' + space + space + '*');
3556 var rtrim = RegExp(space + space + '*$');
3557
3558 var exporter = function (KEY, exec, ALIAS) {
3559 var exp = {};
3560
3561 var FORCE = _fails(function () {
3562 return !!_stringWs[KEY]() || non[KEY]() != non;
3563 });
3564
3565 var fn = exp[KEY] = FORCE ? exec(trim) : _stringWs[KEY];
3566 if (ALIAS) exp[ALIAS] = fn;
3567
3568 _export$1(_export$1.P + _export$1.F * FORCE, 'String', exp);
3569 }; // 1 -> String#trimLeft
3570 // 2 -> String#trimRight
3571 // 3 -> String#trim
3572
3573
3574 var trim = exporter.trim = function (string, TYPE) {
3575 string = String(_defined(string));
3576 if (TYPE & 1) string = string.replace(ltrim, '');
3577 if (TYPE & 2) string = string.replace(rtrim, '');
3578 return string;
3579 };
3580
3581 var _stringTrim = exporter;
3582 var gOPN$2 = _objectGopn.f;
3583 var gOPD$2 = _objectGopd.f;
3584 var dP$2 = _objectDp.f;
3585 var $trim = _stringTrim.trim;
3586 var NUMBER = 'Number';
3587 var $Number = _global[NUMBER];
3588 var Base = $Number;
3589 var proto$1 = $Number.prototype; // Opera ~12 has broken Object#toString
3590
3591 var BROKEN_COF = _cof(_objectCreate(proto$1)) == NUMBER;
3592 var TRIM = 'trim' in String.prototype; // 7.1.3 ToNumber(argument)
3593
3594 var toNumber = function (argument) {
3595 var it = _toPrimitive(argument, false);
3596
3597 if (typeof it == 'string' && it.length > 2) {
3598 it = TRIM ? it.trim() : $trim(it, 3);
3599 var first = it.charCodeAt(0);
3600 var third, radix, maxCode;
3601
3602 if (first === 43 || first === 45) {
3603 third = it.charCodeAt(2);
3604 if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
3605 } else if (first === 48) {
3606 switch (it.charCodeAt(1)) {
3607 case 66:
3608 case 98:
3609 radix = 2;
3610 maxCode = 49;
3611 break;
3612 // fast equal /^0b[01]+$/i
3613
3614 case 79:
3615 case 111:
3616 radix = 8;
3617 maxCode = 55;
3618 break;
3619 // fast equal /^0o[0-7]+$/i
3620
3621 default:
3622 return +it;
3623 }
3624
3625 for (var digits = it.slice(2), i = 0, l = digits.length, code; i < l; i++) {
3626 code = digits.charCodeAt(i); // parseInt parses a string to a first unavailable symbol
3627 // but ToNumber should return NaN if a string contains unavailable symbols
3628
3629 if (code < 48 || code > maxCode) return NaN;
3630 }
3631
3632 return parseInt(digits, radix);
3633 }
3634 }
3635
3636 return +it;
3637 };
3638
3639 if (!$Number(' 0o1') || !$Number('0b1') || $Number('+0x1')) {
3640 $Number = function Number(value) {
3641 var it = arguments.length < 1 ? 0 : value;
3642 var that = this;
3643 return that instanceof $Number // check on 1..constructor(foo) case
3644 && (BROKEN_COF ? _fails(function () {
3645 proto$1.valueOf.call(that);
3646 }) : _cof(that) != NUMBER) ? _inheritIfRequired(new Base(toNumber(it)), that, $Number) : toNumber(it);
3647 };
3648
3649 for (var keys$2 = _descriptors ? gOPN$2(Base) : ( // ES3:
3650 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' + // ES6 (in case, if modules with ES6 Number statics required before):
3651 'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' + 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger').split(','), j$1$1 = 0, key$1$1; keys$2.length > j$1$1; j$1$1++) {
3652 if (_has(Base, key$1$1 = keys$2[j$1$1]) && !_has($Number, key$1$1)) {
3653 dP$2($Number, key$1$1, gOPD$2(Base, key$1$1));
3654 }
3655 }
3656
3657 $Number.prototype = proto$1;
3658 proto$1.constructor = $Number;
3659
3660 _redefine(_global, NUMBER, $Number);
3661 }
3662
3663 var moment = createCommonjsModule$1(function (module, exports) {
3664 (function (global, factory) {
3665 module.exports = factory();
3666 })(commonjsGlobal$1, function () {
3667 var hookCallback;
3668
3669 function hooks() {
3670 return hookCallback.apply(null, arguments);
3671 } // This is done to register the method called with moment()
3672 // without creating circular dependencies.
3673
3674
3675 function setHookCallback(callback) {
3676 hookCallback = callback;
3677 }
3678
3679 function isArray(input) {
3680 return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
3681 }
3682
3683 function isObject(input) {
3684 // IE8 will treat undefined and null as object if it wasn't for
3685 // input != null
3686 return input != null && Object.prototype.toString.call(input) === '[object Object]';
3687 }
3688
3689 function isObjectEmpty(obj) {
3690 if (Object.getOwnPropertyNames) {
3691 return Object.getOwnPropertyNames(obj).length === 0;
3692 } else {
3693 var k;
3694
3695 for (k in obj) {
3696 if (obj.hasOwnProperty(k)) {
3697 return false;
3698 }
3699 }
3700
3701 return true;
3702 }
3703 }
3704
3705 function isUndefined(input) {
3706 return input === void 0;
3707 }
3708
3709 function isNumber(input) {
3710 return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
3711 }
3712
3713 function isDate(input) {
3714 return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
3715 }
3716
3717 function map(arr, fn) {
3718 var res = [],
3719 i;
3720
3721 for (i = 0; i < arr.length; ++i) {
3722 res.push(fn(arr[i], i));
3723 }
3724
3725 return res;
3726 }
3727
3728 function hasOwnProp(a, b) {
3729 return Object.prototype.hasOwnProperty.call(a, b);
3730 }
3731
3732 function extend(a, b) {
3733 for (var i in b) {
3734 if (hasOwnProp(b, i)) {
3735 a[i] = b[i];
3736 }
3737 }
3738
3739 if (hasOwnProp(b, 'toString')) {
3740 a.toString = b.toString;
3741 }
3742
3743 if (hasOwnProp(b, 'valueOf')) {
3744 a.valueOf = b.valueOf;
3745 }
3746
3747 return a;
3748 }
3749
3750 function createUTC(input, format, locale, strict) {
3751 return createLocalOrUTC(input, format, locale, strict, true).utc();
3752 }
3753
3754 function defaultParsingFlags() {
3755 // We need to deep clone this object.
3756 return {
3757 empty: false,
3758 unusedTokens: [],
3759 unusedInput: [],
3760 overflow: -2,
3761 charsLeftOver: 0,
3762 nullInput: false,
3763 invalidMonth: null,
3764 invalidFormat: false,
3765 userInvalidated: false,
3766 iso: false,
3767 parsedDateParts: [],
3768 meridiem: null,
3769 rfc2822: false,
3770 weekdayMismatch: false
3771 };
3772 }
3773
3774 function getParsingFlags(m) {
3775 if (m._pf == null) {
3776 m._pf = defaultParsingFlags();
3777 }
3778
3779 return m._pf;
3780 }
3781
3782 var some;
3783
3784 if (Array.prototype.some) {
3785 some = Array.prototype.some;
3786 } else {
3787 some = function (fun) {
3788 var t = Object(this);
3789 var len = t.length >>> 0;
3790
3791 for (var i = 0; i < len; i++) {
3792 if (i in t && fun.call(this, t[i], i, t)) {
3793 return true;
3794 }
3795 }
3796
3797 return false;
3798 };
3799 }
3800
3801 function isValid(m) {
3802 if (m._isValid == null) {
3803 var flags = getParsingFlags(m);
3804 var parsedParts = some.call(flags.parsedDateParts, function (i) {
3805 return i != null;
3806 });
3807 var isNowValid = !isNaN(m._d.getTime()) && flags.overflow < 0 && !flags.empty && !flags.invalidMonth && !flags.invalidWeekday && !flags.weekdayMismatch && !flags.nullInput && !flags.invalidFormat && !flags.userInvalidated && (!flags.meridiem || flags.meridiem && parsedParts);
3808
3809 if (m._strict) {
3810 isNowValid = isNowValid && flags.charsLeftOver === 0 && flags.unusedTokens.length === 0 && flags.bigHour === undefined;
3811 }
3812
3813 if (Object.isFrozen == null || !Object.isFrozen(m)) {
3814 m._isValid = isNowValid;
3815 } else {
3816 return isNowValid;
3817 }
3818 }
3819
3820 return m._isValid;
3821 }
3822
3823 function createInvalid(flags) {
3824 var m = createUTC(NaN);
3825
3826 if (flags != null) {
3827 extend(getParsingFlags(m), flags);
3828 } else {
3829 getParsingFlags(m).userInvalidated = true;
3830 }
3831
3832 return m;
3833 } // Plugins that add properties should also add the key here (null value),
3834 // so we can properly clone ourselves.
3835
3836
3837 var momentProperties = hooks.momentProperties = [];
3838
3839 function copyConfig(to, from) {
3840 var i, prop, val;
3841
3842 if (!isUndefined(from._isAMomentObject)) {
3843 to._isAMomentObject = from._isAMomentObject;
3844 }
3845
3846 if (!isUndefined(from._i)) {
3847 to._i = from._i;
3848 }
3849
3850 if (!isUndefined(from._f)) {
3851 to._f = from._f;
3852 }
3853
3854 if (!isUndefined(from._l)) {
3855 to._l = from._l;
3856 }
3857
3858 if (!isUndefined(from._strict)) {
3859 to._strict = from._strict;
3860 }
3861
3862 if (!isUndefined(from._tzm)) {
3863 to._tzm = from._tzm;
3864 }
3865
3866 if (!isUndefined(from._isUTC)) {
3867 to._isUTC = from._isUTC;
3868 }
3869
3870 if (!isUndefined(from._offset)) {
3871 to._offset = from._offset;
3872 }
3873
3874 if (!isUndefined(from._pf)) {
3875 to._pf = getParsingFlags(from);
3876 }
3877
3878 if (!isUndefined(from._locale)) {
3879 to._locale = from._locale;
3880 }
3881
3882 if (momentProperties.length > 0) {
3883 for (i = 0; i < momentProperties.length; i++) {
3884 prop = momentProperties[i];
3885 val = from[prop];
3886
3887 if (!isUndefined(val)) {
3888 to[prop] = val;
3889 }
3890 }
3891 }
3892
3893 return to;
3894 }
3895
3896 var updateInProgress = false; // Moment prototype object
3897
3898 function Moment(config) {
3899 copyConfig(this, config);
3900 this._d = new Date(config._d != null ? config._d.getTime() : NaN);
3901
3902 if (!this.isValid()) {
3903 this._d = new Date(NaN);
3904 } // Prevent infinite loop in case updateOffset creates new moment
3905 // objects.
3906
3907
3908 if (updateInProgress === false) {
3909 updateInProgress = true;
3910 hooks.updateOffset(this);
3911 updateInProgress = false;
3912 }
3913 }
3914
3915 function isMoment(obj) {
3916 return obj instanceof Moment || obj != null && obj._isAMomentObject != null;
3917 }
3918
3919 function absFloor(number) {
3920 if (number < 0) {
3921 // -0 -> 0
3922 return Math.ceil(number) || 0;
3923 } else {
3924 return Math.floor(number);
3925 }
3926 }
3927
3928 function toInt(argumentForCoercion) {
3929 var coercedNumber = +argumentForCoercion,
3930 value = 0;
3931
3932 if (coercedNumber !== 0 && isFinite(coercedNumber)) {
3933 value = absFloor(coercedNumber);
3934 }
3935
3936 return value;
3937 } // compare two arrays, return the number of differences
3938
3939
3940 function compareArrays(array1, array2, dontConvert) {
3941 var len = Math.min(array1.length, array2.length),
3942 lengthDiff = Math.abs(array1.length - array2.length),
3943 diffs = 0,
3944 i;
3945
3946 for (i = 0; i < len; i++) {
3947 if (dontConvert && array1[i] !== array2[i] || !dontConvert && toInt(array1[i]) !== toInt(array2[i])) {
3948 diffs++;
3949 }
3950 }
3951
3952 return diffs + lengthDiff;
3953 }
3954
3955 function warn(msg) {
3956 if (hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) {
3957 console.warn('Deprecation warning: ' + msg);
3958 }
3959 }
3960
3961 function deprecate(msg, fn) {
3962 var firstTime = true;
3963 return extend(function () {
3964 if (hooks.deprecationHandler != null) {
3965 hooks.deprecationHandler(null, msg);
3966 }
3967
3968 if (firstTime) {
3969 var args = [];
3970 var arg;
3971
3972 for (var i = 0; i < arguments.length; i++) {
3973 arg = '';
3974
3975 if (typeof arguments[i] === 'object') {
3976 arg += '\n[' + i + '] ';
3977
3978 for (var key in arguments[0]) {
3979 arg += key + ': ' + arguments[0][key] + ', ';
3980 }
3981
3982 arg = arg.slice(0, -2); // Remove trailing comma and space
3983 } else {
3984 arg = arguments[i];
3985 }
3986
3987 args.push(arg);
3988 }
3989
3990 warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + new Error().stack);
3991 firstTime = false;
3992 }
3993
3994 return fn.apply(this, arguments);
3995 }, fn);
3996 }
3997
3998 var deprecations = {};
3999
4000 function deprecateSimple(name, msg) {
4001 if (hooks.deprecationHandler != null) {
4002 hooks.deprecationHandler(name, msg);
4003 }
4004
4005 if (!deprecations[name]) {
4006 warn(msg);
4007 deprecations[name] = true;
4008 }
4009 }
4010
4011 hooks.suppressDeprecationWarnings = false;
4012 hooks.deprecationHandler = null;
4013
4014 function isFunction(input) {
4015 return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
4016 }
4017
4018 function set(config) {
4019 var prop, i;
4020
4021 for (i in config) {
4022 prop = config[i];
4023
4024 if (isFunction(prop)) {
4025 this[i] = prop;
4026 } else {
4027 this['_' + i] = prop;
4028 }
4029 }
4030
4031 this._config = config; // Lenient ordinal parsing accepts just a number in addition to
4032 // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
4033 // TODO: Remove "ordinalParse" fallback in next major release.
4034
4035 this._dayOfMonthOrdinalParseLenient = new RegExp((this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + '|' + /\d{1,2}/.source);
4036 }
4037
4038 function mergeConfigs(parentConfig, childConfig) {
4039 var res = extend({}, parentConfig),
4040 prop;
4041
4042 for (prop in childConfig) {
4043 if (hasOwnProp(childConfig, prop)) {
4044 if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
4045 res[prop] = {};
4046 extend(res[prop], parentConfig[prop]);
4047 extend(res[prop], childConfig[prop]);
4048 } else if (childConfig[prop] != null) {
4049 res[prop] = childConfig[prop];
4050 } else {
4051 delete res[prop];
4052 }
4053 }
4054 }
4055
4056 for (prop in parentConfig) {
4057 if (hasOwnProp(parentConfig, prop) && !hasOwnProp(childConfig, prop) && isObject(parentConfig[prop])) {
4058 // make sure changes to properties don't modify parent config
4059 res[prop] = extend({}, res[prop]);
4060 }
4061 }
4062
4063 return res;
4064 }
4065
4066 function Locale(config) {
4067 if (config != null) {
4068 this.set(config);
4069 }
4070 }
4071
4072 var keys;
4073
4074 if (Object.keys) {
4075 keys = Object.keys;
4076 } else {
4077 keys = function (obj) {
4078 var i,
4079 res = [];
4080
4081 for (i in obj) {
4082 if (hasOwnProp(obj, i)) {
4083 res.push(i);
4084 }
4085 }
4086
4087 return res;
4088 };
4089 }
4090
4091 var defaultCalendar = {
4092 sameDay: '[Today at] LT',
4093 nextDay: '[Tomorrow at] LT',
4094 nextWeek: 'dddd [at] LT',
4095 lastDay: '[Yesterday at] LT',
4096 lastWeek: '[Last] dddd [at] LT',
4097 sameElse: 'L'
4098 };
4099
4100 function calendar(key, mom, now) {
4101 var output = this._calendar[key] || this._calendar['sameElse'];
4102 return isFunction(output) ? output.call(mom, now) : output;
4103 }
4104
4105 var defaultLongDateFormat = {
4106 LTS: 'h:mm:ss A',
4107 LT: 'h:mm A',
4108 L: 'MM/DD/YYYY',
4109 LL: 'MMMM D, YYYY',
4110 LLL: 'MMMM D, YYYY h:mm A',
4111 LLLL: 'dddd, MMMM D, YYYY h:mm A'
4112 };
4113
4114 function longDateFormat(key) {
4115 var format = this._longDateFormat[key],
4116 formatUpper = this._longDateFormat[key.toUpperCase()];
4117
4118 if (format || !formatUpper) {
4119 return format;
4120 }
4121
4122 this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
4123 return val.slice(1);
4124 });
4125 return this._longDateFormat[key];
4126 }
4127
4128 var defaultInvalidDate = 'Invalid date';
4129
4130 function invalidDate() {
4131 return this._invalidDate;
4132 }
4133
4134 var defaultOrdinal = '%d';
4135 var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
4136
4137 function ordinal(number) {
4138 return this._ordinal.replace('%d', number);
4139 }
4140
4141 var defaultRelativeTime = {
4142 future: 'in %s',
4143 past: '%s ago',
4144 s: 'a few seconds',
4145 ss: '%d seconds',
4146 m: 'a minute',
4147 mm: '%d minutes',
4148 h: 'an hour',
4149 hh: '%d hours',
4150 d: 'a day',
4151 dd: '%d days',
4152 M: 'a month',
4153 MM: '%d months',
4154 y: 'a year',
4155 yy: '%d years'
4156 };
4157
4158 function relativeTime(number, withoutSuffix, string, isFuture) {
4159 var output = this._relativeTime[string];
4160 return isFunction(output) ? output(number, withoutSuffix, string, isFuture) : output.replace(/%d/i, number);
4161 }
4162
4163 function pastFuture(diff, output) {
4164 var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
4165 return isFunction(format) ? format(output) : format.replace(/%s/i, output);
4166 }
4167
4168 var aliases = {};
4169
4170 function addUnitAlias(unit, shorthand) {
4171 var lowerCase = unit.toLowerCase();
4172 aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
4173 }
4174
4175 function normalizeUnits(units) {
4176 return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
4177 }
4178
4179 function normalizeObjectUnits(inputObject) {
4180 var normalizedInput = {},
4181 normalizedProp,
4182 prop;
4183
4184 for (prop in inputObject) {
4185 if (hasOwnProp(inputObject, prop)) {
4186 normalizedProp = normalizeUnits(prop);
4187
4188 if (normalizedProp) {
4189 normalizedInput[normalizedProp] = inputObject[prop];
4190 }
4191 }
4192 }
4193
4194 return normalizedInput;
4195 }
4196
4197 var priorities = {};
4198
4199 function addUnitPriority(unit, priority) {
4200 priorities[unit] = priority;
4201 }
4202
4203 function getPrioritizedUnits(unitsObj) {
4204 var units = [];
4205
4206 for (var u in unitsObj) {
4207 units.push({
4208 unit: u,
4209 priority: priorities[u]
4210 });
4211 }
4212
4213 units.sort(function (a, b) {
4214 return a.priority - b.priority;
4215 });
4216 return units;
4217 }
4218
4219 function zeroFill(number, targetLength, forceSign) {
4220 var absNumber = '' + Math.abs(number),
4221 zerosToFill = targetLength - absNumber.length,
4222 sign = number >= 0;
4223 return (sign ? forceSign ? '+' : '' : '-') + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
4224 }
4225
4226 var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
4227 var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
4228 var formatFunctions = {};
4229 var formatTokenFunctions = {}; // token: 'M'
4230 // padded: ['MM', 2]
4231 // ordinal: 'Mo'
4232 // callback: function () { this.month() + 1 }
4233
4234 function addFormatToken(token, padded, ordinal, callback) {
4235 var func = callback;
4236
4237 if (typeof callback === 'string') {
4238 func = function () {
4239 return this[callback]();
4240 };
4241 }
4242
4243 if (token) {
4244 formatTokenFunctions[token] = func;
4245 }
4246
4247 if (padded) {
4248 formatTokenFunctions[padded[0]] = function () {
4249 return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
4250 };
4251 }
4252
4253 if (ordinal) {
4254 formatTokenFunctions[ordinal] = function () {
4255 return this.localeData().ordinal(func.apply(this, arguments), token);
4256 };
4257 }
4258 }
4259
4260 function removeFormattingTokens(input) {
4261 if (input.match(/\[[\s\S]/)) {
4262 return input.replace(/^\[|\]$/g, '');
4263 }
4264
4265 return input.replace(/\\/g, '');
4266 }
4267
4268 function makeFormatFunction(format) {
4269 var array = format.match(formattingTokens),
4270 i,
4271 length;
4272
4273 for (i = 0, length = array.length; i < length; i++) {
4274 if (formatTokenFunctions[array[i]]) {
4275 array[i] = formatTokenFunctions[array[i]];
4276 } else {
4277 array[i] = removeFormattingTokens(array[i]);
4278 }
4279 }
4280
4281 return function (mom) {
4282 var output = '',
4283 i;
4284
4285 for (i = 0; i < length; i++) {
4286 output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
4287 }
4288
4289 return output;
4290 };
4291 } // format date using native date object
4292
4293
4294 function formatMoment(m, format) {
4295 if (!m.isValid()) {
4296 return m.localeData().invalidDate();
4297 }
4298
4299 format = expandFormat(format, m.localeData());
4300 formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
4301 return formatFunctions[format](m);
4302 }
4303
4304 function expandFormat(format, locale) {
4305 var i = 5;
4306
4307 function replaceLongDateFormatTokens(input) {
4308 return locale.longDateFormat(input) || input;
4309 }
4310
4311 localFormattingTokens.lastIndex = 0;
4312
4313 while (i >= 0 && localFormattingTokens.test(format)) {
4314 format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
4315 localFormattingTokens.lastIndex = 0;
4316 i -= 1;
4317 }
4318
4319 return format;
4320 }
4321
4322 var match1 = /\d/; // 0 - 9
4323
4324 var match2 = /\d\d/; // 00 - 99
4325
4326 var match3 = /\d{3}/; // 000 - 999
4327
4328 var match4 = /\d{4}/; // 0000 - 9999
4329
4330 var match6 = /[+-]?\d{6}/; // -999999 - 999999
4331
4332 var match1to2 = /\d\d?/; // 0 - 99
4333
4334 var match3to4 = /\d\d\d\d?/; // 999 - 9999
4335
4336 var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
4337
4338 var match1to3 = /\d{1,3}/; // 0 - 999
4339
4340 var match1to4 = /\d{1,4}/; // 0 - 9999
4341
4342 var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
4343
4344 var matchUnsigned = /\d+/; // 0 - inf
4345
4346 var matchSigned = /[+-]?\d+/; // -inf - inf
4347
4348 var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
4349
4350 var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
4351
4352 var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
4353 // any word (or two) characters or numbers including two/three word month in arabic.
4354 // includes scottish gaelic two word and hyphenated months
4355
4356 var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;
4357 var regexes = {};
4358
4359 function addRegexToken(token, regex, strictRegex) {
4360 regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
4361 return isStrict && strictRegex ? strictRegex : regex;
4362 };
4363 }
4364
4365 function getParseRegexForToken(token, config) {
4366 if (!hasOwnProp(regexes, token)) {
4367 return new RegExp(unescapeFormat(token));
4368 }
4369
4370 return regexes[token](config._strict, config._locale);
4371 } // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
4372
4373
4374 function unescapeFormat(s) {
4375 return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
4376 return p1 || p2 || p3 || p4;
4377 }));
4378 }
4379
4380 function regexEscape(s) {
4381 return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
4382 }
4383
4384 var tokens = {};
4385
4386 function addParseToken(token, callback) {
4387 var i,
4388 func = callback;
4389
4390 if (typeof token === 'string') {
4391 token = [token];
4392 }
4393
4394 if (isNumber(callback)) {
4395 func = function (input, array) {
4396 array[callback] = toInt(input);
4397 };
4398 }
4399
4400 for (i = 0; i < token.length; i++) {
4401 tokens[token[i]] = func;
4402 }
4403 }
4404
4405 function addWeekParseToken(token, callback) {
4406 addParseToken(token, function (input, array, config, token) {
4407 config._w = config._w || {};
4408 callback(input, config._w, config, token);
4409 });
4410 }
4411
4412 function addTimeToArrayFromToken(token, input, config) {
4413 if (input != null && hasOwnProp(tokens, token)) {
4414 tokens[token](input, config._a, config, token);
4415 }
4416 }
4417
4418 var YEAR = 0;
4419 var MONTH = 1;
4420 var DATE = 2;
4421 var HOUR = 3;
4422 var MINUTE = 4;
4423 var SECOND = 5;
4424 var MILLISECOND = 6;
4425 var WEEK = 7;
4426 var WEEKDAY = 8; // FORMATTING
4427
4428 addFormatToken('Y', 0, 0, function () {
4429 var y = this.year();
4430 return y <= 9999 ? '' + y : '+' + y;
4431 });
4432 addFormatToken(0, ['YY', 2], 0, function () {
4433 return this.year() % 100;
4434 });
4435 addFormatToken(0, ['YYYY', 4], 0, 'year');
4436 addFormatToken(0, ['YYYYY', 5], 0, 'year');
4437 addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); // ALIASES
4438
4439 addUnitAlias('year', 'y'); // PRIORITIES
4440
4441 addUnitPriority('year', 1); // PARSING
4442
4443 addRegexToken('Y', matchSigned);
4444 addRegexToken('YY', match1to2, match2);
4445 addRegexToken('YYYY', match1to4, match4);
4446 addRegexToken('YYYYY', match1to6, match6);
4447 addRegexToken('YYYYYY', match1to6, match6);
4448 addParseToken(['YYYYY', 'YYYYYY'], YEAR);
4449 addParseToken('YYYY', function (input, array) {
4450 array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
4451 });
4452 addParseToken('YY', function (input, array) {
4453 array[YEAR] = hooks.parseTwoDigitYear(input);
4454 });
4455 addParseToken('Y', function (input, array) {
4456 array[YEAR] = parseInt(input, 10);
4457 }); // HELPERS
4458
4459 function daysInYear(year) {
4460 return isLeapYear(year) ? 366 : 365;
4461 }
4462
4463 function isLeapYear(year) {
4464 return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
4465 } // HOOKS
4466
4467
4468 hooks.parseTwoDigitYear = function (input) {
4469 return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
4470 }; // MOMENTS
4471
4472
4473 var getSetYear = makeGetSet('FullYear', true);
4474
4475 function getIsLeapYear() {
4476 return isLeapYear(this.year());
4477 }
4478
4479 function makeGetSet(unit, keepTime) {
4480 return function (value) {
4481 if (value != null) {
4482 set$1(this, unit, value);
4483 hooks.updateOffset(this, keepTime);
4484 return this;
4485 } else {
4486 return get(this, unit);
4487 }
4488 };
4489 }
4490
4491 function get(mom, unit) {
4492 return mom.isValid() ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
4493 }
4494
4495 function set$1(mom, unit, value) {
4496 if (mom.isValid() && !isNaN(value)) {
4497 if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
4498 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
4499 } else {
4500 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
4501 }
4502 }
4503 } // MOMENTS
4504
4505
4506 function stringGet(units) {
4507 units = normalizeUnits(units);
4508
4509 if (isFunction(this[units])) {
4510 return this[units]();
4511 }
4512
4513 return this;
4514 }
4515
4516 function stringSet(units, value) {
4517 if (typeof units === 'object') {
4518 units = normalizeObjectUnits(units);
4519 var prioritized = getPrioritizedUnits(units);
4520
4521 for (var i = 0; i < prioritized.length; i++) {
4522 this[prioritized[i].unit](units[prioritized[i].unit]);
4523 }
4524 } else {
4525 units = normalizeUnits(units);
4526
4527 if (isFunction(this[units])) {
4528 return this[units](value);
4529 }
4530 }
4531
4532 return this;
4533 }
4534
4535 function mod(n, x) {
4536 return (n % x + x) % x;
4537 }
4538
4539 var indexOf;
4540
4541 if (Array.prototype.indexOf) {
4542 indexOf = Array.prototype.indexOf;
4543 } else {
4544 indexOf = function (o) {
4545 // I know
4546 var i;
4547
4548 for (i = 0; i < this.length; ++i) {
4549 if (this[i] === o) {
4550 return i;
4551 }
4552 }
4553
4554 return -1;
4555 };
4556 }
4557
4558 function daysInMonth(year, month) {
4559 if (isNaN(year) || isNaN(month)) {
4560 return NaN;
4561 }
4562
4563 var modMonth = mod(month, 12);
4564 year += (month - modMonth) / 12;
4565 return modMonth === 1 ? isLeapYear(year) ? 29 : 28 : 31 - modMonth % 7 % 2;
4566 } // FORMATTING
4567
4568
4569 addFormatToken('M', ['MM', 2], 'Mo', function () {
4570 return this.month() + 1;
4571 });
4572 addFormatToken('MMM', 0, 0, function (format) {
4573 return this.localeData().monthsShort(this, format);
4574 });
4575 addFormatToken('MMMM', 0, 0, function (format) {
4576 return this.localeData().months(this, format);
4577 }); // ALIASES
4578
4579 addUnitAlias('month', 'M'); // PRIORITY
4580
4581 addUnitPriority('month', 8); // PARSING
4582
4583 addRegexToken('M', match1to2);
4584 addRegexToken('MM', match1to2, match2);
4585 addRegexToken('MMM', function (isStrict, locale) {
4586 return locale.monthsShortRegex(isStrict);
4587 });
4588 addRegexToken('MMMM', function (isStrict, locale) {
4589 return locale.monthsRegex(isStrict);
4590 });
4591 addParseToken(['M', 'MM'], function (input, array) {
4592 array[MONTH] = toInt(input) - 1;
4593 });
4594 addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
4595 var month = config._locale.monthsParse(input, token, config._strict); // if we didn't find a month name, mark the date as invalid.
4596
4597
4598 if (month != null) {
4599 array[MONTH] = month;
4600 } else {
4601 getParsingFlags(config).invalidMonth = input;
4602 }
4603 }); // LOCALES
4604
4605 var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
4606 var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
4607
4608 function localeMonths(m, format) {
4609 if (!m) {
4610 return isArray(this._months) ? this._months : this._months['standalone'];
4611 }
4612
4613 return isArray(this._months) ? this._months[m.month()] : this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
4614 }
4615
4616 var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
4617
4618 function localeMonthsShort(m, format) {
4619 if (!m) {
4620 return isArray(this._monthsShort) ? this._monthsShort : this._monthsShort['standalone'];
4621 }
4622
4623 return isArray(this._monthsShort) ? this._monthsShort[m.month()] : this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
4624 }
4625
4626 function handleStrictParse(monthName, format, strict) {
4627 var i,
4628 ii,
4629 mom,
4630 llc = monthName.toLocaleLowerCase();
4631
4632 if (!this._monthsParse) {
4633 // this is not used
4634 this._monthsParse = [];
4635 this._longMonthsParse = [];
4636 this._shortMonthsParse = [];
4637
4638 for (i = 0; i < 12; ++i) {
4639 mom = createUTC([2000, i]);
4640 this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
4641 this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
4642 }
4643 }
4644
4645 if (strict) {
4646 if (format === 'MMM') {
4647 ii = indexOf.call(this._shortMonthsParse, llc);
4648 return ii !== -1 ? ii : null;
4649 } else {
4650 ii = indexOf.call(this._longMonthsParse, llc);
4651 return ii !== -1 ? ii : null;
4652 }
4653 } else {
4654 if (format === 'MMM') {
4655 ii = indexOf.call(this._shortMonthsParse, llc);
4656
4657 if (ii !== -1) {
4658 return ii;
4659 }
4660
4661 ii = indexOf.call(this._longMonthsParse, llc);
4662 return ii !== -1 ? ii : null;
4663 } else {
4664 ii = indexOf.call(this._longMonthsParse, llc);
4665
4666 if (ii !== -1) {
4667 return ii;
4668 }
4669
4670 ii = indexOf.call(this._shortMonthsParse, llc);
4671 return ii !== -1 ? ii : null;
4672 }
4673 }
4674 }
4675
4676 function localeMonthsParse(monthName, format, strict) {
4677 var i, mom, regex;
4678
4679 if (this._monthsParseExact) {
4680 return handleStrictParse.call(this, monthName, format, strict);
4681 }
4682
4683 if (!this._monthsParse) {
4684 this._monthsParse = [];
4685 this._longMonthsParse = [];
4686 this._shortMonthsParse = [];
4687 } // TODO: add sorting
4688 // Sorting makes sure if one month (or abbr) is a prefix of another
4689 // see sorting in computeMonthsParse
4690
4691
4692 for (i = 0; i < 12; i++) {
4693 // make the regex if we don't have it already
4694 mom = createUTC([2000, i]);
4695
4696 if (strict && !this._longMonthsParse[i]) {
4697 this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
4698 this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
4699 }
4700
4701 if (!strict && !this._monthsParse[i]) {
4702 regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
4703 this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
4704 } // test the regex
4705
4706
4707 if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
4708 return i;
4709 } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
4710 return i;
4711 } else if (!strict && this._monthsParse[i].test(monthName)) {
4712 return i;
4713 }
4714 }
4715 } // MOMENTS
4716
4717
4718 function setMonth(mom, value) {
4719 var dayOfMonth;
4720
4721 if (!mom.isValid()) {
4722 // No op
4723 return mom;
4724 }
4725
4726 if (typeof value === 'string') {
4727 if (/^\d+$/.test(value)) {
4728 value = toInt(value);
4729 } else {
4730 value = mom.localeData().monthsParse(value); // TODO: Another silent failure?
4731
4732 if (!isNumber(value)) {
4733 return mom;
4734 }
4735 }
4736 }
4737
4738 dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
4739
4740 mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
4741
4742 return mom;
4743 }
4744
4745 function getSetMonth(value) {
4746 if (value != null) {
4747 setMonth(this, value);
4748 hooks.updateOffset(this, true);
4749 return this;
4750 } else {
4751 return get(this, 'Month');
4752 }
4753 }
4754
4755 function getDaysInMonth() {
4756 return daysInMonth(this.year(), this.month());
4757 }
4758
4759 var defaultMonthsShortRegex = matchWord;
4760
4761 function monthsShortRegex(isStrict) {
4762 if (this._monthsParseExact) {
4763 if (!hasOwnProp(this, '_monthsRegex')) {
4764 computeMonthsParse.call(this);
4765 }
4766
4767 if (isStrict) {
4768 return this._monthsShortStrictRegex;
4769 } else {
4770 return this._monthsShortRegex;
4771 }
4772 } else {
4773 if (!hasOwnProp(this, '_monthsShortRegex')) {
4774 this._monthsShortRegex = defaultMonthsShortRegex;
4775 }
4776
4777 return this._monthsShortStrictRegex && isStrict ? this._monthsShortStrictRegex : this._monthsShortRegex;
4778 }
4779 }
4780
4781 var defaultMonthsRegex = matchWord;
4782
4783 function monthsRegex(isStrict) {
4784 if (this._monthsParseExact) {
4785 if (!hasOwnProp(this, '_monthsRegex')) {
4786 computeMonthsParse.call(this);
4787 }
4788
4789 if (isStrict) {
4790 return this._monthsStrictRegex;
4791 } else {
4792 return this._monthsRegex;
4793 }
4794 } else {
4795 if (!hasOwnProp(this, '_monthsRegex')) {
4796 this._monthsRegex = defaultMonthsRegex;
4797 }
4798
4799 return this._monthsStrictRegex && isStrict ? this._monthsStrictRegex : this._monthsRegex;
4800 }
4801 }
4802
4803 function computeMonthsParse() {
4804 function cmpLenRev(a, b) {
4805 return b.length - a.length;
4806 }
4807
4808 var shortPieces = [],
4809 longPieces = [],
4810 mixedPieces = [],
4811 i,
4812 mom;
4813
4814 for (i = 0; i < 12; i++) {
4815 // make the regex if we don't have it already
4816 mom = createUTC([2000, i]);
4817 shortPieces.push(this.monthsShort(mom, ''));
4818 longPieces.push(this.months(mom, ''));
4819 mixedPieces.push(this.months(mom, ''));
4820 mixedPieces.push(this.monthsShort(mom, ''));
4821 } // Sorting makes sure if one month (or abbr) is a prefix of another it
4822 // will match the longer piece.
4823
4824
4825 shortPieces.sort(cmpLenRev);
4826 longPieces.sort(cmpLenRev);
4827 mixedPieces.sort(cmpLenRev);
4828
4829 for (i = 0; i < 12; i++) {
4830 shortPieces[i] = regexEscape(shortPieces[i]);
4831 longPieces[i] = regexEscape(longPieces[i]);
4832 }
4833
4834 for (i = 0; i < 24; i++) {
4835 mixedPieces[i] = regexEscape(mixedPieces[i]);
4836 }
4837
4838 this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
4839 this._monthsShortRegex = this._monthsRegex;
4840 this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
4841 this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
4842 }
4843
4844 function createDate(y, m, d, h, M, s, ms) {
4845 // can't just apply() to create a date:
4846 // https://stackoverflow.com/q/181348
4847 var date; // the date constructor remaps years 0-99 to 1900-1999
4848
4849 if (y < 100 && y >= 0) {
4850 // preserve leap years using a full 400 year cycle, then reset
4851 date = new Date(y + 400, m, d, h, M, s, ms);
4852
4853 if (isFinite(date.getFullYear())) {
4854 date.setFullYear(y);
4855 }
4856 } else {
4857 date = new Date(y, m, d, h, M, s, ms);
4858 }
4859
4860 return date;
4861 }
4862
4863 function createUTCDate(y) {
4864 var date; // the Date.UTC function remaps years 0-99 to 1900-1999
4865
4866 if (y < 100 && y >= 0) {
4867 var args = Array.prototype.slice.call(arguments); // preserve leap years using a full 400 year cycle, then reset
4868
4869 args[0] = y + 400;
4870 date = new Date(Date.UTC.apply(null, args));
4871
4872 if (isFinite(date.getUTCFullYear())) {
4873 date.setUTCFullYear(y);
4874 }
4875 } else {
4876 date = new Date(Date.UTC.apply(null, arguments));
4877 }
4878
4879 return date;
4880 } // start-of-first-week - start-of-year
4881
4882
4883 function firstWeekOffset(year, dow, doy) {
4884 var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
4885 fwd = 7 + dow - doy,
4886 // first-week day local weekday -- which local weekday is fwd
4887 fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
4888 return -fwdlw + fwd - 1;
4889 } // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
4890
4891
4892 function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
4893 var localWeekday = (7 + weekday - dow) % 7,
4894 weekOffset = firstWeekOffset(year, dow, doy),
4895 dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
4896 resYear,
4897 resDayOfYear;
4898
4899 if (dayOfYear <= 0) {
4900 resYear = year - 1;
4901 resDayOfYear = daysInYear(resYear) + dayOfYear;
4902 } else if (dayOfYear > daysInYear(year)) {
4903 resYear = year + 1;
4904 resDayOfYear = dayOfYear - daysInYear(year);
4905 } else {
4906 resYear = year;
4907 resDayOfYear = dayOfYear;
4908 }
4909
4910 return {
4911 year: resYear,
4912 dayOfYear: resDayOfYear
4913 };
4914 }
4915
4916 function weekOfYear(mom, dow, doy) {
4917 var weekOffset = firstWeekOffset(mom.year(), dow, doy),
4918 week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
4919 resWeek,
4920 resYear;
4921
4922 if (week < 1) {
4923 resYear = mom.year() - 1;
4924 resWeek = week + weeksInYear(resYear, dow, doy);
4925 } else if (week > weeksInYear(mom.year(), dow, doy)) {
4926 resWeek = week - weeksInYear(mom.year(), dow, doy);
4927 resYear = mom.year() + 1;
4928 } else {
4929 resYear = mom.year();
4930 resWeek = week;
4931 }
4932
4933 return {
4934 week: resWeek,
4935 year: resYear
4936 };
4937 }
4938
4939 function weeksInYear(year, dow, doy) {
4940 var weekOffset = firstWeekOffset(year, dow, doy),
4941 weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
4942 return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
4943 } // FORMATTING
4944
4945
4946 addFormatToken('w', ['ww', 2], 'wo', 'week');
4947 addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); // ALIASES
4948
4949 addUnitAlias('week', 'w');
4950 addUnitAlias('isoWeek', 'W'); // PRIORITIES
4951
4952 addUnitPriority('week', 5);
4953 addUnitPriority('isoWeek', 5); // PARSING
4954
4955 addRegexToken('w', match1to2);
4956 addRegexToken('ww', match1to2, match2);
4957 addRegexToken('W', match1to2);
4958 addRegexToken('WW', match1to2, match2);
4959 addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
4960 week[token.substr(0, 1)] = toInt(input);
4961 }); // HELPERS
4962 // LOCALES
4963
4964 function localeWeek(mom) {
4965 return weekOfYear(mom, this._week.dow, this._week.doy).week;
4966 }
4967
4968 var defaultLocaleWeek = {
4969 dow: 0,
4970 // Sunday is the first day of the week.
4971 doy: 6 // The week that contains Jan 6th is the first week of the year.
4972
4973 };
4974
4975 function localeFirstDayOfWeek() {
4976 return this._week.dow;
4977 }
4978
4979 function localeFirstDayOfYear() {
4980 return this._week.doy;
4981 } // MOMENTS
4982
4983
4984 function getSetWeek(input) {
4985 var week = this.localeData().week(this);
4986 return input == null ? week : this.add((input - week) * 7, 'd');
4987 }
4988
4989 function getSetISOWeek(input) {
4990 var week = weekOfYear(this, 1, 4).week;
4991 return input == null ? week : this.add((input - week) * 7, 'd');
4992 } // FORMATTING
4993
4994
4995 addFormatToken('d', 0, 'do', 'day');
4996 addFormatToken('dd', 0, 0, function (format) {
4997 return this.localeData().weekdaysMin(this, format);
4998 });
4999 addFormatToken('ddd', 0, 0, function (format) {
5000 return this.localeData().weekdaysShort(this, format);
5001 });
5002 addFormatToken('dddd', 0, 0, function (format) {
5003 return this.localeData().weekdays(this, format);
5004 });
5005 addFormatToken('e', 0, 0, 'weekday');
5006 addFormatToken('E', 0, 0, 'isoWeekday'); // ALIASES
5007
5008 addUnitAlias('day', 'd');
5009 addUnitAlias('weekday', 'e');
5010 addUnitAlias('isoWeekday', 'E'); // PRIORITY
5011
5012 addUnitPriority('day', 11);
5013 addUnitPriority('weekday', 11);
5014 addUnitPriority('isoWeekday', 11); // PARSING
5015
5016 addRegexToken('d', match1to2);
5017 addRegexToken('e', match1to2);
5018 addRegexToken('E', match1to2);
5019 addRegexToken('dd', function (isStrict, locale) {
5020 return locale.weekdaysMinRegex(isStrict);
5021 });
5022 addRegexToken('ddd', function (isStrict, locale) {
5023 return locale.weekdaysShortRegex(isStrict);
5024 });
5025 addRegexToken('dddd', function (isStrict, locale) {
5026 return locale.weekdaysRegex(isStrict);
5027 });
5028 addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
5029 var weekday = config._locale.weekdaysParse(input, token, config._strict); // if we didn't get a weekday name, mark the date as invalid
5030
5031
5032 if (weekday != null) {
5033 week.d = weekday;
5034 } else {
5035 getParsingFlags(config).invalidWeekday = input;
5036 }
5037 });
5038 addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
5039 week[token] = toInt(input);
5040 }); // HELPERS
5041
5042 function parseWeekday(input, locale) {
5043 if (typeof input !== 'string') {
5044 return input;
5045 }
5046
5047 if (!isNaN(input)) {
5048 return parseInt(input, 10);
5049 }
5050
5051 input = locale.weekdaysParse(input);
5052
5053 if (typeof input === 'number') {
5054 return input;
5055 }
5056
5057 return null;
5058 }
5059
5060 function parseIsoWeekday(input, locale) {
5061 if (typeof input === 'string') {
5062 return locale.weekdaysParse(input) % 7 || 7;
5063 }
5064
5065 return isNaN(input) ? null : input;
5066 } // LOCALES
5067
5068
5069 function shiftWeekdays(ws, n) {
5070 return ws.slice(n, 7).concat(ws.slice(0, n));
5071 }
5072
5073 var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
5074
5075 function localeWeekdays(m, format) {
5076 var weekdays = isArray(this._weekdays) ? this._weekdays : this._weekdays[m && m !== true && this._weekdays.isFormat.test(format) ? 'format' : 'standalone'];
5077 return m === true ? shiftWeekdays(weekdays, this._week.dow) : m ? weekdays[m.day()] : weekdays;
5078 }
5079
5080 var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
5081
5082 function localeWeekdaysShort(m) {
5083 return m === true ? shiftWeekdays(this._weekdaysShort, this._week.dow) : m ? this._weekdaysShort[m.day()] : this._weekdaysShort;
5084 }
5085
5086 var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
5087
5088 function localeWeekdaysMin(m) {
5089 return m === true ? shiftWeekdays(this._weekdaysMin, this._week.dow) : m ? this._weekdaysMin[m.day()] : this._weekdaysMin;
5090 }
5091
5092 function handleStrictParse$1(weekdayName, format, strict) {
5093 var i,
5094 ii,
5095 mom,
5096 llc = weekdayName.toLocaleLowerCase();
5097
5098 if (!this._weekdaysParse) {
5099 this._weekdaysParse = [];
5100 this._shortWeekdaysParse = [];
5101 this._minWeekdaysParse = [];
5102
5103 for (i = 0; i < 7; ++i) {
5104 mom = createUTC([2000, 1]).day(i);
5105 this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
5106 this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
5107 this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
5108 }
5109 }
5110
5111 if (strict) {
5112 if (format === 'dddd') {
5113 ii = indexOf.call(this._weekdaysParse, llc);
5114 return ii !== -1 ? ii : null;
5115 } else if (format === 'ddd') {
5116 ii = indexOf.call(this._shortWeekdaysParse, llc);
5117 return ii !== -1 ? ii : null;
5118 } else {
5119 ii = indexOf.call(this._minWeekdaysParse, llc);
5120 return ii !== -1 ? ii : null;
5121 }
5122 } else {
5123 if (format === 'dddd') {
5124 ii = indexOf.call(this._weekdaysParse, llc);
5125
5126 if (ii !== -1) {
5127 return ii;
5128 }
5129
5130 ii = indexOf.call(this._shortWeekdaysParse, llc);
5131
5132 if (ii !== -1) {
5133 return ii;
5134 }
5135
5136 ii = indexOf.call(this._minWeekdaysParse, llc);
5137 return ii !== -1 ? ii : null;
5138 } else if (format === 'ddd') {
5139 ii = indexOf.call(this._shortWeekdaysParse, llc);
5140
5141 if (ii !== -1) {
5142 return ii;
5143 }
5144
5145 ii = indexOf.call(this._weekdaysParse, llc);
5146
5147 if (ii !== -1) {
5148 return ii;
5149 }
5150
5151 ii = indexOf.call(this._minWeekdaysParse, llc);
5152 return ii !== -1 ? ii : null;
5153 } else {
5154 ii = indexOf.call(this._minWeekdaysParse, llc);
5155
5156 if (ii !== -1) {
5157 return ii;
5158 }
5159
5160 ii = indexOf.call(this._weekdaysParse, llc);
5161
5162 if (ii !== -1) {
5163 return ii;
5164 }
5165
5166 ii = indexOf.call(this._shortWeekdaysParse, llc);
5167 return ii !== -1 ? ii : null;
5168 }
5169 }
5170 }
5171
5172 function localeWeekdaysParse(weekdayName, format, strict) {
5173 var i, mom, regex;
5174
5175 if (this._weekdaysParseExact) {
5176 return handleStrictParse$1.call(this, weekdayName, format, strict);
5177 }
5178
5179 if (!this._weekdaysParse) {
5180 this._weekdaysParse = [];
5181 this._minWeekdaysParse = [];
5182 this._shortWeekdaysParse = [];
5183 this._fullWeekdaysParse = [];
5184 }
5185
5186 for (i = 0; i < 7; i++) {
5187 // make the regex if we don't have it already
5188 mom = createUTC([2000, 1]).day(i);
5189
5190 if (strict && !this._fullWeekdaysParse[i]) {
5191 this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', 'i');
5192 this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', 'i');
5193 this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', 'i');
5194 }
5195
5196 if (!this._weekdaysParse[i]) {
5197 regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
5198 this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
5199 } // test the regex
5200
5201
5202 if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
5203 return i;
5204 } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
5205 return i;
5206 } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
5207 return i;
5208 } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
5209 return i;
5210 }
5211 }
5212 } // MOMENTS
5213
5214
5215 function getSetDayOfWeek(input) {
5216 if (!this.isValid()) {
5217 return input != null ? this : NaN;
5218 }
5219
5220 var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
5221
5222 if (input != null) {
5223 input = parseWeekday(input, this.localeData());
5224 return this.add(input - day, 'd');
5225 } else {
5226 return day;
5227 }
5228 }
5229
5230 function getSetLocaleDayOfWeek(input) {
5231 if (!this.isValid()) {
5232 return input != null ? this : NaN;
5233 }
5234
5235 var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
5236 return input == null ? weekday : this.add(input - weekday, 'd');
5237 }
5238
5239 function getSetISODayOfWeek(input) {
5240 if (!this.isValid()) {
5241 return input != null ? this : NaN;
5242 } // behaves the same as moment#day except
5243 // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
5244 // as a setter, sunday should belong to the previous week.
5245
5246
5247 if (input != null) {
5248 var weekday = parseIsoWeekday(input, this.localeData());
5249 return this.day(this.day() % 7 ? weekday : weekday - 7);
5250 } else {
5251 return this.day() || 7;
5252 }
5253 }
5254
5255 var defaultWeekdaysRegex = matchWord;
5256
5257 function weekdaysRegex(isStrict) {
5258 if (this._weekdaysParseExact) {
5259 if (!hasOwnProp(this, '_weekdaysRegex')) {
5260 computeWeekdaysParse.call(this);
5261 }
5262
5263 if (isStrict) {
5264 return this._weekdaysStrictRegex;
5265 } else {
5266 return this._weekdaysRegex;
5267 }
5268 } else {
5269 if (!hasOwnProp(this, '_weekdaysRegex')) {
5270 this._weekdaysRegex = defaultWeekdaysRegex;
5271 }
5272
5273 return this._weekdaysStrictRegex && isStrict ? this._weekdaysStrictRegex : this._weekdaysRegex;
5274 }
5275 }
5276
5277 var defaultWeekdaysShortRegex = matchWord;
5278
5279 function weekdaysShortRegex(isStrict) {
5280 if (this._weekdaysParseExact) {
5281 if (!hasOwnProp(this, '_weekdaysRegex')) {
5282 computeWeekdaysParse.call(this);
5283 }
5284
5285 if (isStrict) {
5286 return this._weekdaysShortStrictRegex;
5287 } else {
5288 return this._weekdaysShortRegex;
5289 }
5290 } else {
5291 if (!hasOwnProp(this, '_weekdaysShortRegex')) {
5292 this._weekdaysShortRegex = defaultWeekdaysShortRegex;
5293 }
5294
5295 return this._weekdaysShortStrictRegex && isStrict ? this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
5296 }
5297 }
5298
5299 var defaultWeekdaysMinRegex = matchWord;
5300
5301 function weekdaysMinRegex(isStrict) {
5302 if (this._weekdaysParseExact) {
5303 if (!hasOwnProp(this, '_weekdaysRegex')) {
5304 computeWeekdaysParse.call(this);
5305 }
5306
5307 if (isStrict) {
5308 return this._weekdaysMinStrictRegex;
5309 } else {
5310 return this._weekdaysMinRegex;
5311 }
5312 } else {
5313 if (!hasOwnProp(this, '_weekdaysMinRegex')) {
5314 this._weekdaysMinRegex = defaultWeekdaysMinRegex;
5315 }
5316
5317 return this._weekdaysMinStrictRegex && isStrict ? this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
5318 }
5319 }
5320
5321 function computeWeekdaysParse() {
5322 function cmpLenRev(a, b) {
5323 return b.length - a.length;
5324 }
5325
5326 var minPieces = [],
5327 shortPieces = [],
5328 longPieces = [],
5329 mixedPieces = [],
5330 i,
5331 mom,
5332 minp,
5333 shortp,
5334 longp;
5335
5336 for (i = 0; i < 7; i++) {
5337 // make the regex if we don't have it already
5338 mom = createUTC([2000, 1]).day(i);
5339 minp = this.weekdaysMin(mom, '');
5340 shortp = this.weekdaysShort(mom, '');
5341 longp = this.weekdays(mom, '');
5342 minPieces.push(minp);
5343 shortPieces.push(shortp);
5344 longPieces.push(longp);
5345 mixedPieces.push(minp);
5346 mixedPieces.push(shortp);
5347 mixedPieces.push(longp);
5348 } // Sorting makes sure if one weekday (or abbr) is a prefix of another it
5349 // will match the longer piece.
5350
5351
5352 minPieces.sort(cmpLenRev);
5353 shortPieces.sort(cmpLenRev);
5354 longPieces.sort(cmpLenRev);
5355 mixedPieces.sort(cmpLenRev);
5356
5357 for (i = 0; i < 7; i++) {
5358 shortPieces[i] = regexEscape(shortPieces[i]);
5359 longPieces[i] = regexEscape(longPieces[i]);
5360 mixedPieces[i] = regexEscape(mixedPieces[i]);
5361 }
5362
5363 this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
5364 this._weekdaysShortRegex = this._weekdaysRegex;
5365 this._weekdaysMinRegex = this._weekdaysRegex;
5366 this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
5367 this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
5368 this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
5369 } // FORMATTING
5370
5371
5372 function hFormat() {
5373 return this.hours() % 12 || 12;
5374 }
5375
5376 function kFormat() {
5377 return this.hours() || 24;
5378 }
5379
5380 addFormatToken('H', ['HH', 2], 0, 'hour');
5381 addFormatToken('h', ['hh', 2], 0, hFormat);
5382 addFormatToken('k', ['kk', 2], 0, kFormat);
5383 addFormatToken('hmm', 0, 0, function () {
5384 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
5385 });
5386 addFormatToken('hmmss', 0, 0, function () {
5387 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
5388 });
5389 addFormatToken('Hmm', 0, 0, function () {
5390 return '' + this.hours() + zeroFill(this.minutes(), 2);
5391 });
5392 addFormatToken('Hmmss', 0, 0, function () {
5393 return '' + this.hours() + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
5394 });
5395
5396 function meridiem(token, lowercase) {
5397 addFormatToken(token, 0, 0, function () {
5398 return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
5399 });
5400 }
5401
5402 meridiem('a', true);
5403 meridiem('A', false); // ALIASES
5404
5405 addUnitAlias('hour', 'h'); // PRIORITY
5406
5407 addUnitPriority('hour', 13); // PARSING
5408
5409 function matchMeridiem(isStrict, locale) {
5410 return locale._meridiemParse;
5411 }
5412
5413 addRegexToken('a', matchMeridiem);
5414 addRegexToken('A', matchMeridiem);
5415 addRegexToken('H', match1to2);
5416 addRegexToken('h', match1to2);
5417 addRegexToken('k', match1to2);
5418 addRegexToken('HH', match1to2, match2);
5419 addRegexToken('hh', match1to2, match2);
5420 addRegexToken('kk', match1to2, match2);
5421 addRegexToken('hmm', match3to4);
5422 addRegexToken('hmmss', match5to6);
5423 addRegexToken('Hmm', match3to4);
5424 addRegexToken('Hmmss', match5to6);
5425 addParseToken(['H', 'HH'], HOUR);
5426 addParseToken(['k', 'kk'], function (input, array, config) {
5427 var kInput = toInt(input);
5428 array[HOUR] = kInput === 24 ? 0 : kInput;
5429 });
5430 addParseToken(['a', 'A'], function (input, array, config) {
5431 config._isPm = config._locale.isPM(input);
5432 config._meridiem = input;
5433 });
5434 addParseToken(['h', 'hh'], function (input, array, config) {
5435 array[HOUR] = toInt(input);
5436 getParsingFlags(config).bigHour = true;
5437 });
5438 addParseToken('hmm', function (input, array, config) {
5439 var pos = input.length - 2;
5440 array[HOUR] = toInt(input.substr(0, pos));
5441 array[MINUTE] = toInt(input.substr(pos));
5442 getParsingFlags(config).bigHour = true;
5443 });
5444 addParseToken('hmmss', function (input, array, config) {
5445 var pos1 = input.length - 4;
5446 var pos2 = input.length - 2;
5447 array[HOUR] = toInt(input.substr(0, pos1));
5448 array[MINUTE] = toInt(input.substr(pos1, 2));
5449 array[SECOND] = toInt(input.substr(pos2));
5450 getParsingFlags(config).bigHour = true;
5451 });
5452 addParseToken('Hmm', function (input, array, config) {
5453 var pos = input.length - 2;
5454 array[HOUR] = toInt(input.substr(0, pos));
5455 array[MINUTE] = toInt(input.substr(pos));
5456 });
5457 addParseToken('Hmmss', function (input, array, config) {
5458 var pos1 = input.length - 4;
5459 var pos2 = input.length - 2;
5460 array[HOUR] = toInt(input.substr(0, pos1));
5461 array[MINUTE] = toInt(input.substr(pos1, 2));
5462 array[SECOND] = toInt(input.substr(pos2));
5463 }); // LOCALES
5464
5465 function localeIsPM(input) {
5466 // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
5467 // Using charAt should be more compatible.
5468 return (input + '').toLowerCase().charAt(0) === 'p';
5469 }
5470
5471 var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
5472
5473 function localeMeridiem(hours, minutes, isLower) {
5474 if (hours > 11) {
5475 return isLower ? 'pm' : 'PM';
5476 } else {
5477 return isLower ? 'am' : 'AM';
5478 }
5479 } // MOMENTS
5480 // Setting the hour should keep the time, because the user explicitly
5481 // specified which hour they want. So trying to maintain the same hour (in
5482 // a new timezone) makes sense. Adding/subtracting hours does not follow
5483 // this rule.
5484
5485
5486 var getSetHour = makeGetSet('Hours', true);
5487 var baseConfig = {
5488 calendar: defaultCalendar,
5489 longDateFormat: defaultLongDateFormat,
5490 invalidDate: defaultInvalidDate,
5491 ordinal: defaultOrdinal,
5492 dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
5493 relativeTime: defaultRelativeTime,
5494 months: defaultLocaleMonths,
5495 monthsShort: defaultLocaleMonthsShort,
5496 week: defaultLocaleWeek,
5497 weekdays: defaultLocaleWeekdays,
5498 weekdaysMin: defaultLocaleWeekdaysMin,
5499 weekdaysShort: defaultLocaleWeekdaysShort,
5500 meridiemParse: defaultLocaleMeridiemParse
5501 }; // internal storage for locale config files
5502
5503 var locales = {};
5504 var localeFamilies = {};
5505 var globalLocale;
5506
5507 function normalizeLocale(key) {
5508 return key ? key.toLowerCase().replace('_', '-') : key;
5509 } // pick the locale from the array
5510 // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
5511 // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
5512
5513
5514 function chooseLocale(names) {
5515 var i = 0,
5516 j,
5517 next,
5518 locale,
5519 split;
5520
5521 while (i < names.length) {
5522 split = normalizeLocale(names[i]).split('-');
5523 j = split.length;
5524 next = normalizeLocale(names[i + 1]);
5525 next = next ? next.split('-') : null;
5526
5527 while (j > 0) {
5528 locale = loadLocale(split.slice(0, j).join('-'));
5529
5530 if (locale) {
5531 return locale;
5532 }
5533
5534 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
5535 //the next array item is better than a shallower substring of this one
5536 break;
5537 }
5538
5539 j--;
5540 }
5541
5542 i++;
5543 }
5544
5545 return globalLocale;
5546 }
5547
5548 function loadLocale(name) {
5549 var oldLocale = null; // TODO: Find a better way to register and load all the locales in Node
5550
5551 if (!locales[name] && 'object' !== 'undefined' && module && module.exports) {
5552 try {
5553 oldLocale = globalLocale._abbr;
5554 var aliasedRequire = commonjsRequire$1;
5555 aliasedRequire('./locale/' + name);
5556 getSetGlobalLocale(oldLocale);
5557 } catch (e) {}
5558 }
5559
5560 return locales[name];
5561 } // This function will load locale and then set the global locale. If
5562 // no arguments are passed in, it will simply return the current global
5563 // locale key.
5564
5565
5566 function getSetGlobalLocale(key, values) {
5567 var data;
5568
5569 if (key) {
5570 if (isUndefined(values)) {
5571 data = getLocale(key);
5572 } else {
5573 data = defineLocale(key, values);
5574 }
5575
5576 if (data) {
5577 // moment.duration._locale = moment._locale = data;
5578 globalLocale = data;
5579 } else {
5580 if (typeof console !== 'undefined' && console.warn) {
5581 //warn user if arguments are passed but the locale could not be set
5582 console.warn('Locale ' + key + ' not found. Did you forget to load it?');
5583 }
5584 }
5585 }
5586
5587 return globalLocale._abbr;
5588 }
5589
5590 function defineLocale(name, config) {
5591 if (config !== null) {
5592 var locale,
5593 parentConfig = baseConfig;
5594 config.abbr = name;
5595
5596 if (locales[name] != null) {
5597 deprecateSimple('defineLocaleOverride', 'use moment.updateLocale(localeName, config) to change ' + 'an existing locale. moment.defineLocale(localeName, ' + 'config) should only be used for creating a new locale ' + 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
5598 parentConfig = locales[name]._config;
5599 } else if (config.parentLocale != null) {
5600 if (locales[config.parentLocale] != null) {
5601 parentConfig = locales[config.parentLocale]._config;
5602 } else {
5603 locale = loadLocale(config.parentLocale);
5604
5605 if (locale != null) {
5606 parentConfig = locale._config;
5607 } else {
5608 if (!localeFamilies[config.parentLocale]) {
5609 localeFamilies[config.parentLocale] = [];
5610 }
5611
5612 localeFamilies[config.parentLocale].push({
5613 name: name,
5614 config: config
5615 });
5616 return null;
5617 }
5618 }
5619 }
5620
5621 locales[name] = new Locale(mergeConfigs(parentConfig, config));
5622
5623 if (localeFamilies[name]) {
5624 localeFamilies[name].forEach(function (x) {
5625 defineLocale(x.name, x.config);
5626 });
5627 } // backwards compat for now: also set the locale
5628 // make sure we set the locale AFTER all child locales have been
5629 // created, so we won't end up with the child locale set.
5630
5631
5632 getSetGlobalLocale(name);
5633 return locales[name];
5634 } else {
5635 // useful for testing
5636 delete locales[name];
5637 return null;
5638 }
5639 }
5640
5641 function updateLocale(name, config) {
5642 if (config != null) {
5643 var locale,
5644 tmpLocale,
5645 parentConfig = baseConfig; // MERGE
5646
5647 tmpLocale = loadLocale(name);
5648
5649 if (tmpLocale != null) {
5650 parentConfig = tmpLocale._config;
5651 }
5652
5653 config = mergeConfigs(parentConfig, config);
5654 locale = new Locale(config);
5655 locale.parentLocale = locales[name];
5656 locales[name] = locale; // backwards compat for now: also set the locale
5657
5658 getSetGlobalLocale(name);
5659 } else {
5660 // pass null for config to unupdate, useful for tests
5661 if (locales[name] != null) {
5662 if (locales[name].parentLocale != null) {
5663 locales[name] = locales[name].parentLocale;
5664 } else if (locales[name] != null) {
5665 delete locales[name];
5666 }
5667 }
5668 }
5669
5670 return locales[name];
5671 } // returns locale data
5672
5673
5674 function getLocale(key) {
5675 var locale;
5676
5677 if (key && key._locale && key._locale._abbr) {
5678 key = key._locale._abbr;
5679 }
5680
5681 if (!key) {
5682 return globalLocale;
5683 }
5684
5685 if (!isArray(key)) {
5686 //short-circuit everything else
5687 locale = loadLocale(key);
5688
5689 if (locale) {
5690 return locale;
5691 }
5692
5693 key = [key];
5694 }
5695
5696 return chooseLocale(key);
5697 }
5698
5699 function listLocales() {
5700 return keys(locales);
5701 }
5702
5703 function checkOverflow(m) {
5704 var overflow;
5705 var a = m._a;
5706
5707 if (a && getParsingFlags(m).overflow === -2) {
5708 overflow = a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE : a[HOUR] < 0 || a[HOUR] > 24 || a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0) ? HOUR : a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE : a[SECOND] < 0 || a[SECOND] > 59 ? SECOND : a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND : -1;
5709
5710 if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
5711 overflow = DATE;
5712 }
5713
5714 if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
5715 overflow = WEEK;
5716 }
5717
5718 if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
5719 overflow = WEEKDAY;
5720 }
5721
5722 getParsingFlags(m).overflow = overflow;
5723 }
5724
5725 return m;
5726 } // Pick the first defined of two or three arguments.
5727
5728
5729 function defaults(a, b, c) {
5730 if (a != null) {
5731 return a;
5732 }
5733
5734 if (b != null) {
5735 return b;
5736 }
5737
5738 return c;
5739 }
5740
5741 function currentDateArray(config) {
5742 // hooks is actually the exported moment object
5743 var nowValue = new Date(hooks.now());
5744
5745 if (config._useUTC) {
5746 return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
5747 }
5748
5749 return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
5750 } // convert an array to a date.
5751 // the array should mirror the parameters below
5752 // note: all values past the year are optional and will default to the lowest possible value.
5753 // [year, month, day , hour, minute, second, millisecond]
5754
5755
5756 function configFromArray(config) {
5757 var i,
5758 date,
5759 input = [],
5760 currentDate,
5761 expectedWeekday,
5762 yearToUse;
5763
5764 if (config._d) {
5765 return;
5766 }
5767
5768 currentDate = currentDateArray(config); //compute day of the year from weeks and weekdays
5769
5770 if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
5771 dayOfYearFromWeekInfo(config);
5772 } //if the day of the year is set, figure out what it is
5773
5774
5775 if (config._dayOfYear != null) {
5776 yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
5777
5778 if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
5779 getParsingFlags(config)._overflowDayOfYear = true;
5780 }
5781
5782 date = createUTCDate(yearToUse, 0, config._dayOfYear);
5783 config._a[MONTH] = date.getUTCMonth();
5784 config._a[DATE] = date.getUTCDate();
5785 } // Default to current date.
5786 // * if no year, month, day of month are given, default to today
5787 // * if day of month is given, default month and year
5788 // * if month is given, default only year
5789 // * if year is given, don't default anything
5790
5791
5792 for (i = 0; i < 3 && config._a[i] == null; ++i) {
5793 config._a[i] = input[i] = currentDate[i];
5794 } // Zero out whatever was not defaulted, including time
5795
5796
5797 for (; i < 7; i++) {
5798 config._a[i] = input[i] = config._a[i] == null ? i === 2 ? 1 : 0 : config._a[i];
5799 } // Check for 24:00:00.000
5800
5801
5802 if (config._a[HOUR] === 24 && config._a[MINUTE] === 0 && config._a[SECOND] === 0 && config._a[MILLISECOND] === 0) {
5803 config._nextDay = true;
5804 config._a[HOUR] = 0;
5805 }
5806
5807 config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
5808 expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay(); // Apply timezone offset from input. The actual utcOffset can be changed
5809 // with parseZone.
5810
5811 if (config._tzm != null) {
5812 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
5813 }
5814
5815 if (config._nextDay) {
5816 config._a[HOUR] = 24;
5817 } // check for mismatching day of week
5818
5819
5820 if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
5821 getParsingFlags(config).weekdayMismatch = true;
5822 }
5823 }
5824
5825 function dayOfYearFromWeekInfo(config) {
5826 var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
5827 w = config._w;
5828
5829 if (w.GG != null || w.W != null || w.E != null) {
5830 dow = 1;
5831 doy = 4; // TODO: We need to take the current isoWeekYear, but that depends on
5832 // how we interpret now (local, utc, fixed offset). So create
5833 // a now version of current config (take local/utc/offset flags, and
5834 // create now).
5835
5836 weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
5837 week = defaults(w.W, 1);
5838 weekday = defaults(w.E, 1);
5839
5840 if (weekday < 1 || weekday > 7) {
5841 weekdayOverflow = true;
5842 }
5843 } else {
5844 dow = config._locale._week.dow;
5845 doy = config._locale._week.doy;
5846 var curWeek = weekOfYear(createLocal(), dow, doy);
5847 weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); // Default to current week.
5848
5849 week = defaults(w.w, curWeek.week);
5850
5851 if (w.d != null) {
5852 // weekday -- low day numbers are considered next week
5853 weekday = w.d;
5854
5855 if (weekday < 0 || weekday > 6) {
5856 weekdayOverflow = true;
5857 }
5858 } else if (w.e != null) {
5859 // local weekday -- counting starts from beginning of week
5860 weekday = w.e + dow;
5861
5862 if (w.e < 0 || w.e > 6) {
5863 weekdayOverflow = true;
5864 }
5865 } else {
5866 // default to beginning of week
5867 weekday = dow;
5868 }
5869 }
5870
5871 if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
5872 getParsingFlags(config)._overflowWeeks = true;
5873 } else if (weekdayOverflow != null) {
5874 getParsingFlags(config)._overflowWeekday = true;
5875 } else {
5876 temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
5877 config._a[YEAR] = temp.year;
5878 config._dayOfYear = temp.dayOfYear;
5879 }
5880 } // iso 8601 regex
5881 // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
5882
5883
5884 var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
5885 var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
5886 var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
5887 var isoDates = [['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], ['GGGG-[W]WW', /\d{4}-W\d\d/, false], ['YYYY-DDD', /\d{4}-\d{3}/], ['YYYY-MM', /\d{4}-\d\d/, false], ['YYYYYYMMDD', /[+-]\d{10}/], ['YYYYMMDD', /\d{8}/], // YYYYMM is NOT allowed by the standard
5888 ['GGGG[W]WWE', /\d{4}W\d{3}/], ['GGGG[W]WW', /\d{4}W\d{2}/, false], ['YYYYDDD', /\d{7}/]]; // iso time formats and regexes
5889
5890 var isoTimes = [['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], ['HH:mm:ss', /\d\d:\d\d:\d\d/], ['HH:mm', /\d\d:\d\d/], ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], ['HHmmss', /\d\d\d\d\d\d/], ['HHmm', /\d\d\d\d/], ['HH', /\d\d/]];
5891 var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; // date from iso format
5892
5893 function configFromISO(config) {
5894 var i,
5895 l,
5896 string = config._i,
5897 match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
5898 allowTime,
5899 dateFormat,
5900 timeFormat,
5901 tzFormat;
5902
5903 if (match) {
5904 getParsingFlags(config).iso = true;
5905
5906 for (i = 0, l = isoDates.length; i < l; i++) {
5907 if (isoDates[i][1].exec(match[1])) {
5908 dateFormat = isoDates[i][0];
5909 allowTime = isoDates[i][2] !== false;
5910 break;
5911 }
5912 }
5913
5914 if (dateFormat == null) {
5915 config._isValid = false;
5916 return;
5917 }
5918
5919 if (match[3]) {
5920 for (i = 0, l = isoTimes.length; i < l; i++) {
5921 if (isoTimes[i][1].exec(match[3])) {
5922 // match[2] should be 'T' or space
5923 timeFormat = (match[2] || ' ') + isoTimes[i][0];
5924 break;
5925 }
5926 }
5927
5928 if (timeFormat == null) {
5929 config._isValid = false;
5930 return;
5931 }
5932 }
5933
5934 if (!allowTime && timeFormat != null) {
5935 config._isValid = false;
5936 return;
5937 }
5938
5939 if (match[4]) {
5940 if (tzRegex.exec(match[4])) {
5941 tzFormat = 'Z';
5942 } else {
5943 config._isValid = false;
5944 return;
5945 }
5946 }
5947
5948 config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
5949 configFromStringAndFormat(config);
5950 } else {
5951 config._isValid = false;
5952 }
5953 } // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
5954
5955
5956 var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
5957
5958 function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
5959 var result = [untruncateYear(yearStr), defaultLocaleMonthsShort.indexOf(monthStr), parseInt(dayStr, 10), parseInt(hourStr, 10), parseInt(minuteStr, 10)];
5960
5961 if (secondStr) {
5962 result.push(parseInt(secondStr, 10));
5963 }
5964
5965 return result;
5966 }
5967
5968 function untruncateYear(yearStr) {
5969 var year = parseInt(yearStr, 10);
5970
5971 if (year <= 49) {
5972 return 2000 + year;
5973 } else if (year <= 999) {
5974 return 1900 + year;
5975 }
5976
5977 return year;
5978 }
5979
5980 function preprocessRFC2822(s) {
5981 // Remove comments and folding whitespace and replace multiple-spaces with a single space
5982 return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
5983 }
5984
5985 function checkWeekday(weekdayStr, parsedInput, config) {
5986 if (weekdayStr) {
5987 // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
5988 var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
5989 weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
5990
5991 if (weekdayProvided !== weekdayActual) {
5992 getParsingFlags(config).weekdayMismatch = true;
5993 config._isValid = false;
5994 return false;
5995 }
5996 }
5997
5998 return true;
5999 }
6000
6001 var obsOffsets = {
6002 UT: 0,
6003 GMT: 0,
6004 EDT: -4 * 60,
6005 EST: -5 * 60,
6006 CDT: -5 * 60,
6007 CST: -6 * 60,
6008 MDT: -6 * 60,
6009 MST: -7 * 60,
6010 PDT: -7 * 60,
6011 PST: -8 * 60
6012 };
6013
6014 function calculateOffset(obsOffset, militaryOffset, numOffset) {
6015 if (obsOffset) {
6016 return obsOffsets[obsOffset];
6017 } else if (militaryOffset) {
6018 // the only allowed military tz is Z
6019 return 0;
6020 } else {
6021 var hm = parseInt(numOffset, 10);
6022 var m = hm % 100,
6023 h = (hm - m) / 100;
6024 return h * 60 + m;
6025 }
6026 } // date and time from ref 2822 format
6027
6028
6029 function configFromRFC2822(config) {
6030 var match = rfc2822.exec(preprocessRFC2822(config._i));
6031
6032 if (match) {
6033 var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
6034
6035 if (!checkWeekday(match[1], parsedArray, config)) {
6036 return;
6037 }
6038
6039 config._a = parsedArray;
6040 config._tzm = calculateOffset(match[8], match[9], match[10]);
6041 config._d = createUTCDate.apply(null, config._a);
6042
6043 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
6044
6045 getParsingFlags(config).rfc2822 = true;
6046 } else {
6047 config._isValid = false;
6048 }
6049 } // date from iso format or fallback
6050
6051
6052 function configFromString(config) {
6053 var matched = aspNetJsonRegex.exec(config._i);
6054
6055 if (matched !== null) {
6056 config._d = new Date(+matched[1]);
6057 return;
6058 }
6059
6060 configFromISO(config);
6061
6062 if (config._isValid === false) {
6063 delete config._isValid;
6064 } else {
6065 return;
6066 }
6067
6068 configFromRFC2822(config);
6069
6070 if (config._isValid === false) {
6071 delete config._isValid;
6072 } else {
6073 return;
6074 } // Final attempt, use Input Fallback
6075
6076
6077 hooks.createFromInputFallback(config);
6078 }
6079
6080 hooks.createFromInputFallback = deprecate('value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + 'discouraged and will be removed in an upcoming major release. Please refer to ' + 'http://momentjs.com/guides/#/warnings/js-date/ for more info.', function (config) {
6081 config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
6082 }); // constant that refers to the ISO standard
6083
6084 hooks.ISO_8601 = function () {}; // constant that refers to the RFC 2822 form
6085
6086
6087 hooks.RFC_2822 = function () {}; // date from string and format string
6088
6089
6090 function configFromStringAndFormat(config) {
6091 // TODO: Move this to another part of the creation flow to prevent circular deps
6092 if (config._f === hooks.ISO_8601) {
6093 configFromISO(config);
6094 return;
6095 }
6096
6097 if (config._f === hooks.RFC_2822) {
6098 configFromRFC2822(config);
6099 return;
6100 }
6101
6102 config._a = [];
6103 getParsingFlags(config).empty = true; // This array is used to make a Date, either with `new Date` or `Date.UTC`
6104
6105 var string = '' + config._i,
6106 i,
6107 parsedInput,
6108 tokens,
6109 token,
6110 skipped,
6111 stringLength = string.length,
6112 totalParsedInputLength = 0;
6113 tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
6114
6115 for (i = 0; i < tokens.length; i++) {
6116 token = tokens[i];
6117 parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; // console.log('token', token, 'parsedInput', parsedInput,
6118 // 'regex', getParseRegexForToken(token, config));
6119
6120 if (parsedInput) {
6121 skipped = string.substr(0, string.indexOf(parsedInput));
6122
6123 if (skipped.length > 0) {
6124 getParsingFlags(config).unusedInput.push(skipped);
6125 }
6126
6127 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
6128 totalParsedInputLength += parsedInput.length;
6129 } // don't parse if it's not a known token
6130
6131
6132 if (formatTokenFunctions[token]) {
6133 if (parsedInput) {
6134 getParsingFlags(config).empty = false;
6135 } else {
6136 getParsingFlags(config).unusedTokens.push(token);
6137 }
6138
6139 addTimeToArrayFromToken(token, parsedInput, config);
6140 } else if (config._strict && !parsedInput) {
6141 getParsingFlags(config).unusedTokens.push(token);
6142 }
6143 } // add remaining unparsed input length to the string
6144
6145
6146 getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
6147
6148 if (string.length > 0) {
6149 getParsingFlags(config).unusedInput.push(string);
6150 } // clear _12h flag if hour is <= 12
6151
6152
6153 if (config._a[HOUR] <= 12 && getParsingFlags(config).bigHour === true && config._a[HOUR] > 0) {
6154 getParsingFlags(config).bigHour = undefined;
6155 }
6156
6157 getParsingFlags(config).parsedDateParts = config._a.slice(0);
6158 getParsingFlags(config).meridiem = config._meridiem; // handle meridiem
6159
6160 config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
6161 configFromArray(config);
6162 checkOverflow(config);
6163 }
6164
6165 function meridiemFixWrap(locale, hour, meridiem) {
6166 var isPm;
6167
6168 if (meridiem == null) {
6169 // nothing to do
6170 return hour;
6171 }
6172
6173 if (locale.meridiemHour != null) {
6174 return locale.meridiemHour(hour, meridiem);
6175 } else if (locale.isPM != null) {
6176 // Fallback
6177 isPm = locale.isPM(meridiem);
6178
6179 if (isPm && hour < 12) {
6180 hour += 12;
6181 }
6182
6183 if (!isPm && hour === 12) {
6184 hour = 0;
6185 }
6186
6187 return hour;
6188 } else {
6189 // this is not supposed to happen
6190 return hour;
6191 }
6192 } // date from string and array of format strings
6193
6194
6195 function configFromStringAndArray(config) {
6196 var tempConfig, bestMoment, scoreToBeat, i, currentScore;
6197
6198 if (config._f.length === 0) {
6199 getParsingFlags(config).invalidFormat = true;
6200 config._d = new Date(NaN);
6201 return;
6202 }
6203
6204 for (i = 0; i < config._f.length; i++) {
6205 currentScore = 0;
6206 tempConfig = copyConfig({}, config);
6207
6208 if (config._useUTC != null) {
6209 tempConfig._useUTC = config._useUTC;
6210 }
6211
6212 tempConfig._f = config._f[i];
6213 configFromStringAndFormat(tempConfig);
6214
6215 if (!isValid(tempConfig)) {
6216 continue;
6217 } // if there is any input that was not parsed add a penalty for that format
6218
6219
6220 currentScore += getParsingFlags(tempConfig).charsLeftOver; //or tokens
6221
6222 currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
6223 getParsingFlags(tempConfig).score = currentScore;
6224
6225 if (scoreToBeat == null || currentScore < scoreToBeat) {
6226 scoreToBeat = currentScore;
6227 bestMoment = tempConfig;
6228 }
6229 }
6230
6231 extend(config, bestMoment || tempConfig);
6232 }
6233
6234 function configFromObject(config) {
6235 if (config._d) {
6236 return;
6237 }
6238
6239 var i = normalizeObjectUnits(config._i);
6240 config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
6241 return obj && parseInt(obj, 10);
6242 });
6243 configFromArray(config);
6244 }
6245
6246 function createFromConfig(config) {
6247 var res = new Moment(checkOverflow(prepareConfig(config)));
6248
6249 if (res._nextDay) {
6250 // Adding is smart enough around DST
6251 res.add(1, 'd');
6252 res._nextDay = undefined;
6253 }
6254
6255 return res;
6256 }
6257
6258 function prepareConfig(config) {
6259 var input = config._i,
6260 format = config._f;
6261 config._locale = config._locale || getLocale(config._l);
6262
6263 if (input === null || format === undefined && input === '') {
6264 return createInvalid({
6265 nullInput: true
6266 });
6267 }
6268
6269 if (typeof input === 'string') {
6270 config._i = input = config._locale.preparse(input);
6271 }
6272
6273 if (isMoment(input)) {
6274 return new Moment(checkOverflow(input));
6275 } else if (isDate(input)) {
6276 config._d = input;
6277 } else if (isArray(format)) {
6278 configFromStringAndArray(config);
6279 } else if (format) {
6280 configFromStringAndFormat(config);
6281 } else {
6282 configFromInput(config);
6283 }
6284
6285 if (!isValid(config)) {
6286 config._d = null;
6287 }
6288
6289 return config;
6290 }
6291
6292 function configFromInput(config) {
6293 var input = config._i;
6294
6295 if (isUndefined(input)) {
6296 config._d = new Date(hooks.now());
6297 } else if (isDate(input)) {
6298 config._d = new Date(input.valueOf());
6299 } else if (typeof input === 'string') {
6300 configFromString(config);
6301 } else if (isArray(input)) {
6302 config._a = map(input.slice(0), function (obj) {
6303 return parseInt(obj, 10);
6304 });
6305 configFromArray(config);
6306 } else if (isObject(input)) {
6307 configFromObject(config);
6308 } else if (isNumber(input)) {
6309 // from milliseconds
6310 config._d = new Date(input);
6311 } else {
6312 hooks.createFromInputFallback(config);
6313 }
6314 }
6315
6316 function createLocalOrUTC(input, format, locale, strict, isUTC) {
6317 var c = {};
6318
6319 if (locale === true || locale === false) {
6320 strict = locale;
6321 locale = undefined;
6322 }
6323
6324 if (isObject(input) && isObjectEmpty(input) || isArray(input) && input.length === 0) {
6325 input = undefined;
6326 } // object construction must be done this way.
6327 // https://github.com/moment/moment/issues/1423
6328
6329
6330 c._isAMomentObject = true;
6331 c._useUTC = c._isUTC = isUTC;
6332 c._l = locale;
6333 c._i = input;
6334 c._f = format;
6335 c._strict = strict;
6336 return createFromConfig(c);
6337 }
6338
6339 function createLocal(input, format, locale, strict) {
6340 return createLocalOrUTC(input, format, locale, strict, false);
6341 }
6342
6343 var prototypeMin = deprecate('moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
6344 var other = createLocal.apply(null, arguments);
6345
6346 if (this.isValid() && other.isValid()) {
6347 return other < this ? this : other;
6348 } else {
6349 return createInvalid();
6350 }
6351 });
6352 var prototypeMax = deprecate('moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
6353 var other = createLocal.apply(null, arguments);
6354
6355 if (this.isValid() && other.isValid()) {
6356 return other > this ? this : other;
6357 } else {
6358 return createInvalid();
6359 }
6360 }); // Pick a moment m from moments so that m[fn](other) is true for all
6361 // other. This relies on the function fn to be transitive.
6362 //
6363 // moments should either be an array of moment objects or an array, whose
6364 // first element is an array of moment objects.
6365
6366 function pickBy(fn, moments) {
6367 var res, i;
6368
6369 if (moments.length === 1 && isArray(moments[0])) {
6370 moments = moments[0];
6371 }
6372
6373 if (!moments.length) {
6374 return createLocal();
6375 }
6376
6377 res = moments[0];
6378
6379 for (i = 1; i < moments.length; ++i) {
6380 if (!moments[i].isValid() || moments[i][fn](res)) {
6381 res = moments[i];
6382 }
6383 }
6384
6385 return res;
6386 } // TODO: Use [].sort instead?
6387
6388
6389 function min() {
6390 var args = [].slice.call(arguments, 0);
6391 return pickBy('isBefore', args);
6392 }
6393
6394 function max() {
6395 var args = [].slice.call(arguments, 0);
6396 return pickBy('isAfter', args);
6397 }
6398
6399 var now = function () {
6400 return Date.now ? Date.now() : +new Date();
6401 };
6402
6403 var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
6404
6405 function isDurationValid(m) {
6406 for (var key in m) {
6407 if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
6408 return false;
6409 }
6410 }
6411
6412 var unitHasDecimal = false;
6413
6414 for (var i = 0; i < ordering.length; ++i) {
6415 if (m[ordering[i]]) {
6416 if (unitHasDecimal) {
6417 return false; // only allow non-integers for smallest unit
6418 }
6419
6420 if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
6421 unitHasDecimal = true;
6422 }
6423 }
6424 }
6425
6426 return true;
6427 }
6428
6429 function isValid$1() {
6430 return this._isValid;
6431 }
6432
6433 function createInvalid$1() {
6434 return createDuration(NaN);
6435 }
6436
6437 function Duration(duration) {
6438 var normalizedInput = normalizeObjectUnits(duration),
6439 years = normalizedInput.year || 0,
6440 quarters = normalizedInput.quarter || 0,
6441 months = normalizedInput.month || 0,
6442 weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
6443 days = normalizedInput.day || 0,
6444 hours = normalizedInput.hour || 0,
6445 minutes = normalizedInput.minute || 0,
6446 seconds = normalizedInput.second || 0,
6447 milliseconds = normalizedInput.millisecond || 0;
6448 this._isValid = isDurationValid(normalizedInput); // representation for dateAddRemove
6449
6450 this._milliseconds = +milliseconds + seconds * 1e3 + // 1000
6451 minutes * 6e4 + // 1000 * 60
6452 hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
6453 // Because of dateAddRemove treats 24 hours as different from a
6454 // day when working around DST, we need to store them separately
6455
6456 this._days = +days + weeks * 7; // It is impossible to translate months into days without knowing
6457 // which months you are are talking about, so we have to store
6458 // it separately.
6459
6460 this._months = +months + quarters * 3 + years * 12;
6461 this._data = {};
6462 this._locale = getLocale();
6463
6464 this._bubble();
6465 }
6466
6467 function isDuration(obj) {
6468 return obj instanceof Duration;
6469 }
6470
6471 function absRound(number) {
6472 if (number < 0) {
6473 return Math.round(-1 * number) * -1;
6474 } else {
6475 return Math.round(number);
6476 }
6477 } // FORMATTING
6478
6479
6480 function offset(token, separator) {
6481 addFormatToken(token, 0, 0, function () {
6482 var offset = this.utcOffset();
6483 var sign = '+';
6484
6485 if (offset < 0) {
6486 offset = -offset;
6487 sign = '-';
6488 }
6489
6490 return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~offset % 60, 2);
6491 });
6492 }
6493
6494 offset('Z', ':');
6495 offset('ZZ', ''); // PARSING
6496
6497 addRegexToken('Z', matchShortOffset);
6498 addRegexToken('ZZ', matchShortOffset);
6499 addParseToken(['Z', 'ZZ'], function (input, array, config) {
6500 config._useUTC = true;
6501 config._tzm = offsetFromString(matchShortOffset, input);
6502 }); // HELPERS
6503 // timezone chunker
6504 // '+10:00' > ['10', '00']
6505 // '-1530' > ['-15', '30']
6506
6507 var chunkOffset = /([\+\-]|\d\d)/gi;
6508
6509 function offsetFromString(matcher, string) {
6510 var matches = (string || '').match(matcher);
6511
6512 if (matches === null) {
6513 return null;
6514 }
6515
6516 var chunk = matches[matches.length - 1] || [];
6517 var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
6518 var minutes = +(parts[1] * 60) + toInt(parts[2]);
6519 return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
6520 } // Return a moment from input, that is local/utc/zone equivalent to model.
6521
6522
6523 function cloneWithOffset(input, model) {
6524 var res, diff;
6525
6526 if (model._isUTC) {
6527 res = model.clone();
6528 diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf(); // Use low-level api, because this fn is low-level api.
6529
6530 res._d.setTime(res._d.valueOf() + diff);
6531
6532 hooks.updateOffset(res, false);
6533 return res;
6534 } else {
6535 return createLocal(input).local();
6536 }
6537 }
6538
6539 function getDateOffset(m) {
6540 // On Firefox.24 Date#getTimezoneOffset returns a floating point.
6541 // https://github.com/moment/moment/pull/1871
6542 return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
6543 } // HOOKS
6544 // This function will be called whenever a moment is mutated.
6545 // It is intended to keep the offset in sync with the timezone.
6546
6547
6548 hooks.updateOffset = function () {}; // MOMENTS
6549 // keepLocalTime = true means only change the timezone, without
6550 // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
6551 // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
6552 // +0200, so we adjust the time as needed, to be valid.
6553 //
6554 // Keeping the time actually adds/subtracts (one hour)
6555 // from the actual represented time. That is why we call updateOffset
6556 // a second time. In case it wants us to change the offset again
6557 // _changeInProgress == true case, then we have to adjust, because
6558 // there is no such time in the given timezone.
6559
6560
6561 function getSetOffset(input, keepLocalTime, keepMinutes) {
6562 var offset = this._offset || 0,
6563 localAdjust;
6564
6565 if (!this.isValid()) {
6566 return input != null ? this : NaN;
6567 }
6568
6569 if (input != null) {
6570 if (typeof input === 'string') {
6571 input = offsetFromString(matchShortOffset, input);
6572
6573 if (input === null) {
6574 return this;
6575 }
6576 } else if (Math.abs(input) < 16 && !keepMinutes) {
6577 input = input * 60;
6578 }
6579
6580 if (!this._isUTC && keepLocalTime) {
6581 localAdjust = getDateOffset(this);
6582 }
6583
6584 this._offset = input;
6585 this._isUTC = true;
6586
6587 if (localAdjust != null) {
6588 this.add(localAdjust, 'm');
6589 }
6590
6591 if (offset !== input) {
6592 if (!keepLocalTime || this._changeInProgress) {
6593 addSubtract(this, createDuration(input - offset, 'm'), 1, false);
6594 } else if (!this._changeInProgress) {
6595 this._changeInProgress = true;
6596 hooks.updateOffset(this, true);
6597 this._changeInProgress = null;
6598 }
6599 }
6600
6601 return this;
6602 } else {
6603 return this._isUTC ? offset : getDateOffset(this);
6604 }
6605 }
6606
6607 function getSetZone(input, keepLocalTime) {
6608 if (input != null) {
6609 if (typeof input !== 'string') {
6610 input = -input;
6611 }
6612
6613 this.utcOffset(input, keepLocalTime);
6614 return this;
6615 } else {
6616 return -this.utcOffset();
6617 }
6618 }
6619
6620 function setOffsetToUTC(keepLocalTime) {
6621 return this.utcOffset(0, keepLocalTime);
6622 }
6623
6624 function setOffsetToLocal(keepLocalTime) {
6625 if (this._isUTC) {
6626 this.utcOffset(0, keepLocalTime);
6627 this._isUTC = false;
6628
6629 if (keepLocalTime) {
6630 this.subtract(getDateOffset(this), 'm');
6631 }
6632 }
6633
6634 return this;
6635 }
6636
6637 function setOffsetToParsedOffset() {
6638 if (this._tzm != null) {
6639 this.utcOffset(this._tzm, false, true);
6640 } else if (typeof this._i === 'string') {
6641 var tZone = offsetFromString(matchOffset, this._i);
6642
6643 if (tZone != null) {
6644 this.utcOffset(tZone);
6645 } else {
6646 this.utcOffset(0, true);
6647 }
6648 }
6649
6650 return this;
6651 }
6652
6653 function hasAlignedHourOffset(input) {
6654 if (!this.isValid()) {
6655 return false;
6656 }
6657
6658 input = input ? createLocal(input).utcOffset() : 0;
6659 return (this.utcOffset() - input) % 60 === 0;
6660 }
6661
6662 function isDaylightSavingTime() {
6663 return this.utcOffset() > this.clone().month(0).utcOffset() || this.utcOffset() > this.clone().month(5).utcOffset();
6664 }
6665
6666 function isDaylightSavingTimeShifted() {
6667 if (!isUndefined(this._isDSTShifted)) {
6668 return this._isDSTShifted;
6669 }
6670
6671 var c = {};
6672 copyConfig(c, this);
6673 c = prepareConfig(c);
6674
6675 if (c._a) {
6676 var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
6677 this._isDSTShifted = this.isValid() && compareArrays(c._a, other.toArray()) > 0;
6678 } else {
6679 this._isDSTShifted = false;
6680 }
6681
6682 return this._isDSTShifted;
6683 }
6684
6685 function isLocal() {
6686 return this.isValid() ? !this._isUTC : false;
6687 }
6688
6689 function isUtcOffset() {
6690 return this.isValid() ? this._isUTC : false;
6691 }
6692
6693 function isUtc() {
6694 return this.isValid() ? this._isUTC && this._offset === 0 : false;
6695 } // ASP.NET json date format regex
6696
6697
6698 var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/; // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
6699 // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
6700 // and further modified to allow for strings containing both week and day
6701
6702 var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
6703
6704 function createDuration(input, key) {
6705 var duration = input,
6706 // matching against regexp is expensive, do it on demand
6707 match = null,
6708 sign,
6709 ret,
6710 diffRes;
6711
6712 if (isDuration(input)) {
6713 duration = {
6714 ms: input._milliseconds,
6715 d: input._days,
6716 M: input._months
6717 };
6718 } else if (isNumber(input)) {
6719 duration = {};
6720
6721 if (key) {
6722 duration[key] = input;
6723 } else {
6724 duration.milliseconds = input;
6725 }
6726 } else if (!!(match = aspNetRegex.exec(input))) {
6727 sign = match[1] === '-' ? -1 : 1;
6728 duration = {
6729 y: 0,
6730 d: toInt(match[DATE]) * sign,
6731 h: toInt(match[HOUR]) * sign,
6732 m: toInt(match[MINUTE]) * sign,
6733 s: toInt(match[SECOND]) * sign,
6734 ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
6735
6736 };
6737 } else if (!!(match = isoRegex.exec(input))) {
6738 sign = match[1] === '-' ? -1 : 1;
6739 duration = {
6740 y: parseIso(match[2], sign),
6741 M: parseIso(match[3], sign),
6742 w: parseIso(match[4], sign),
6743 d: parseIso(match[5], sign),
6744 h: parseIso(match[6], sign),
6745 m: parseIso(match[7], sign),
6746 s: parseIso(match[8], sign)
6747 };
6748 } else if (duration == null) {
6749 // checks for null or undefined
6750 duration = {};
6751 } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
6752 diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
6753 duration = {};
6754 duration.ms = diffRes.milliseconds;
6755 duration.M = diffRes.months;
6756 }
6757
6758 ret = new Duration(duration);
6759
6760 if (isDuration(input) && hasOwnProp(input, '_locale')) {
6761 ret._locale = input._locale;
6762 }
6763
6764 return ret;
6765 }
6766
6767 createDuration.fn = Duration.prototype;
6768 createDuration.invalid = createInvalid$1;
6769
6770 function parseIso(inp, sign) {
6771 // We'd normally use ~~inp for this, but unfortunately it also
6772 // converts floats to ints.
6773 // inp may be undefined, so careful calling replace on it.
6774 var res = inp && parseFloat(inp.replace(',', '.')); // apply sign while we're at it
6775
6776 return (isNaN(res) ? 0 : res) * sign;
6777 }
6778
6779 function positiveMomentsDifference(base, other) {
6780 var res = {};
6781 res.months = other.month() - base.month() + (other.year() - base.year()) * 12;
6782
6783 if (base.clone().add(res.months, 'M').isAfter(other)) {
6784 --res.months;
6785 }
6786
6787 res.milliseconds = +other - +base.clone().add(res.months, 'M');
6788 return res;
6789 }
6790
6791 function momentsDifference(base, other) {
6792 var res;
6793
6794 if (!(base.isValid() && other.isValid())) {
6795 return {
6796 milliseconds: 0,
6797 months: 0
6798 };
6799 }
6800
6801 other = cloneWithOffset(other, base);
6802
6803 if (base.isBefore(other)) {
6804 res = positiveMomentsDifference(base, other);
6805 } else {
6806 res = positiveMomentsDifference(other, base);
6807 res.milliseconds = -res.milliseconds;
6808 res.months = -res.months;
6809 }
6810
6811 return res;
6812 } // TODO: remove 'name' arg after deprecation is removed
6813
6814
6815 function createAdder(direction, name) {
6816 return function (val, period) {
6817 var dur, tmp; //invert the arguments, but complain about it
6818
6819 if (period !== null && !isNaN(+period)) {
6820 deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' + 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
6821 tmp = val;
6822 val = period;
6823 period = tmp;
6824 }
6825
6826 val = typeof val === 'string' ? +val : val;
6827 dur = createDuration(val, period);
6828 addSubtract(this, dur, direction);
6829 return this;
6830 };
6831 }
6832
6833 function addSubtract(mom, duration, isAdding, updateOffset) {
6834 var milliseconds = duration._milliseconds,
6835 days = absRound(duration._days),
6836 months = absRound(duration._months);
6837
6838 if (!mom.isValid()) {
6839 // No op
6840 return;
6841 }
6842
6843 updateOffset = updateOffset == null ? true : updateOffset;
6844
6845 if (months) {
6846 setMonth(mom, get(mom, 'Month') + months * isAdding);
6847 }
6848
6849 if (days) {
6850 set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
6851 }
6852
6853 if (milliseconds) {
6854 mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
6855 }
6856
6857 if (updateOffset) {
6858 hooks.updateOffset(mom, days || months);
6859 }
6860 }
6861
6862 var add = createAdder(1, 'add');
6863 var subtract = createAdder(-1, 'subtract');
6864
6865 function getCalendarFormat(myMoment, now) {
6866 var diff = myMoment.diff(now, 'days', true);
6867 return diff < -6 ? 'sameElse' : diff < -1 ? 'lastWeek' : diff < 0 ? 'lastDay' : diff < 1 ? 'sameDay' : diff < 2 ? 'nextDay' : diff < 7 ? 'nextWeek' : 'sameElse';
6868 }
6869
6870 function calendar$1(time, formats) {
6871 // We want to compare the start of today, vs this.
6872 // Getting start-of-today depends on whether we're local/utc/offset or not.
6873 var now = time || createLocal(),
6874 sod = cloneWithOffset(now, this).startOf('day'),
6875 format = hooks.calendarFormat(this, sod) || 'sameElse';
6876 var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
6877 return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
6878 }
6879
6880 function clone() {
6881 return new Moment(this);
6882 }
6883
6884 function isAfter(input, units) {
6885 var localInput = isMoment(input) ? input : createLocal(input);
6886
6887 if (!(this.isValid() && localInput.isValid())) {
6888 return false;
6889 }
6890
6891 units = normalizeUnits(units) || 'millisecond';
6892
6893 if (units === 'millisecond') {
6894 return this.valueOf() > localInput.valueOf();
6895 } else {
6896 return localInput.valueOf() < this.clone().startOf(units).valueOf();
6897 }
6898 }
6899
6900 function isBefore(input, units) {
6901 var localInput = isMoment(input) ? input : createLocal(input);
6902
6903 if (!(this.isValid() && localInput.isValid())) {
6904 return false;
6905 }
6906
6907 units = normalizeUnits(units) || 'millisecond';
6908
6909 if (units === 'millisecond') {
6910 return this.valueOf() < localInput.valueOf();
6911 } else {
6912 return this.clone().endOf(units).valueOf() < localInput.valueOf();
6913 }
6914 }
6915
6916 function isBetween(from, to, units, inclusivity) {
6917 var localFrom = isMoment(from) ? from : createLocal(from),
6918 localTo = isMoment(to) ? to : createLocal(to);
6919
6920 if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
6921 return false;
6922 }
6923
6924 inclusivity = inclusivity || '()';
6925 return (inclusivity[0] === '(' ? this.isAfter(localFrom, units) : !this.isBefore(localFrom, units)) && (inclusivity[1] === ')' ? this.isBefore(localTo, units) : !this.isAfter(localTo, units));
6926 }
6927
6928 function isSame(input, units) {
6929 var localInput = isMoment(input) ? input : createLocal(input),
6930 inputMs;
6931
6932 if (!(this.isValid() && localInput.isValid())) {
6933 return false;
6934 }
6935
6936 units = normalizeUnits(units) || 'millisecond';
6937
6938 if (units === 'millisecond') {
6939 return this.valueOf() === localInput.valueOf();
6940 } else {
6941 inputMs = localInput.valueOf();
6942 return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
6943 }
6944 }
6945
6946 function isSameOrAfter(input, units) {
6947 return this.isSame(input, units) || this.isAfter(input, units);
6948 }
6949
6950 function isSameOrBefore(input, units) {
6951 return this.isSame(input, units) || this.isBefore(input, units);
6952 }
6953
6954 function diff(input, units, asFloat) {
6955 var that, zoneDelta, output;
6956
6957 if (!this.isValid()) {
6958 return NaN;
6959 }
6960
6961 that = cloneWithOffset(input, this);
6962
6963 if (!that.isValid()) {
6964 return NaN;
6965 }
6966
6967 zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
6968 units = normalizeUnits(units);
6969
6970 switch (units) {
6971 case 'year':
6972 output = monthDiff(this, that) / 12;
6973 break;
6974
6975 case 'month':
6976 output = monthDiff(this, that);
6977 break;
6978
6979 case 'quarter':
6980 output = monthDiff(this, that) / 3;
6981 break;
6982
6983 case 'second':
6984 output = (this - that) / 1e3;
6985 break;
6986 // 1000
6987
6988 case 'minute':
6989 output = (this - that) / 6e4;
6990 break;
6991 // 1000 * 60
6992
6993 case 'hour':
6994 output = (this - that) / 36e5;
6995 break;
6996 // 1000 * 60 * 60
6997
6998 case 'day':
6999 output = (this - that - zoneDelta) / 864e5;
7000 break;
7001 // 1000 * 60 * 60 * 24, negate dst
7002
7003 case 'week':
7004 output = (this - that - zoneDelta) / 6048e5;
7005 break;
7006 // 1000 * 60 * 60 * 24 * 7, negate dst
7007
7008 default:
7009 output = this - that;
7010 }
7011
7012 return asFloat ? output : absFloor(output);
7013 }
7014
7015 function monthDiff(a, b) {
7016 // difference in months
7017 var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()),
7018 // b is in (anchor - 1 month, anchor + 1 month)
7019 anchor = a.clone().add(wholeMonthDiff, 'months'),
7020 anchor2,
7021 adjust;
7022
7023 if (b - anchor < 0) {
7024 anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); // linear across the month
7025
7026 adjust = (b - anchor) / (anchor - anchor2);
7027 } else {
7028 anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); // linear across the month
7029
7030 adjust = (b - anchor) / (anchor2 - anchor);
7031 } //check for negative zero, return zero if negative zero
7032
7033
7034 return -(wholeMonthDiff + adjust) || 0;
7035 }
7036
7037 hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
7038 hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
7039
7040 function toString() {
7041 return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
7042 }
7043
7044 function toISOString(keepOffset) {
7045 if (!this.isValid()) {
7046 return null;
7047 }
7048
7049 var utc = keepOffset !== true;
7050 var m = utc ? this.clone().utc() : this;
7051
7052 if (m.year() < 0 || m.year() > 9999) {
7053 return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
7054 }
7055
7056 if (isFunction(Date.prototype.toISOString)) {
7057 // native implementation is ~50x faster, use it when we can
7058 if (utc) {
7059 return this.toDate().toISOString();
7060 } else {
7061 return new Date(this.valueOf() + this.utcOffset() * 60 * 1000).toISOString().replace('Z', formatMoment(m, 'Z'));
7062 }
7063 }
7064
7065 return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
7066 }
7067 /**
7068 * Return a human readable representation of a moment that can
7069 * also be evaluated to get a new moment which is the same
7070 *
7071 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
7072 */
7073
7074
7075 function inspect() {
7076 if (!this.isValid()) {
7077 return 'moment.invalid(/* ' + this._i + ' */)';
7078 }
7079
7080 var func = 'moment';
7081 var zone = '';
7082
7083 if (!this.isLocal()) {
7084 func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
7085 zone = 'Z';
7086 }
7087
7088 var prefix = '[' + func + '("]';
7089 var year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
7090 var datetime = '-MM-DD[T]HH:mm:ss.SSS';
7091 var suffix = zone + '[")]';
7092 return this.format(prefix + year + datetime + suffix);
7093 }
7094
7095 function format(inputString) {
7096 if (!inputString) {
7097 inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
7098 }
7099
7100 var output = formatMoment(this, inputString);
7101 return this.localeData().postformat(output);
7102 }
7103
7104 function from(time, withoutSuffix) {
7105 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
7106 return createDuration({
7107 to: this,
7108 from: time
7109 }).locale(this.locale()).humanize(!withoutSuffix);
7110 } else {
7111 return this.localeData().invalidDate();
7112 }
7113 }
7114
7115 function fromNow(withoutSuffix) {
7116 return this.from(createLocal(), withoutSuffix);
7117 }
7118
7119 function to(time, withoutSuffix) {
7120 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
7121 return createDuration({
7122 from: this,
7123 to: time
7124 }).locale(this.locale()).humanize(!withoutSuffix);
7125 } else {
7126 return this.localeData().invalidDate();
7127 }
7128 }
7129
7130 function toNow(withoutSuffix) {
7131 return this.to(createLocal(), withoutSuffix);
7132 } // If passed a locale key, it will set the locale for this
7133 // instance. Otherwise, it will return the locale configuration
7134 // variables for this instance.
7135
7136
7137 function locale(key) {
7138 var newLocaleData;
7139
7140 if (key === undefined) {
7141 return this._locale._abbr;
7142 } else {
7143 newLocaleData = getLocale(key);
7144
7145 if (newLocaleData != null) {
7146 this._locale = newLocaleData;
7147 }
7148
7149 return this;
7150 }
7151 }
7152
7153 var lang = deprecate('moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', function (key) {
7154 if (key === undefined) {
7155 return this.localeData();
7156 } else {
7157 return this.locale(key);
7158 }
7159 });
7160
7161 function localeData() {
7162 return this._locale;
7163 }
7164
7165 var MS_PER_SECOND = 1000;
7166 var MS_PER_MINUTE = 60 * MS_PER_SECOND;
7167 var MS_PER_HOUR = 60 * MS_PER_MINUTE;
7168 var MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; // actual modulo - handles negative numbers (for dates before 1970):
7169
7170 function mod$1(dividend, divisor) {
7171 return (dividend % divisor + divisor) % divisor;
7172 }
7173
7174 function localStartOfDate(y, m, d) {
7175 // the date constructor remaps years 0-99 to 1900-1999
7176 if (y < 100 && y >= 0) {
7177 // preserve leap years using a full 400 year cycle, then reset
7178 return new Date(y + 400, m, d) - MS_PER_400_YEARS;
7179 } else {
7180 return new Date(y, m, d).valueOf();
7181 }
7182 }
7183
7184 function utcStartOfDate(y, m, d) {
7185 // Date.UTC remaps years 0-99 to 1900-1999
7186 if (y < 100 && y >= 0) {
7187 // preserve leap years using a full 400 year cycle, then reset
7188 return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
7189 } else {
7190 return Date.UTC(y, m, d);
7191 }
7192 }
7193
7194 function startOf(units) {
7195 var time;
7196 units = normalizeUnits(units);
7197
7198 if (units === undefined || units === 'millisecond' || !this.isValid()) {
7199 return this;
7200 }
7201
7202 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
7203
7204 switch (units) {
7205 case 'year':
7206 time = startOfDate(this.year(), 0, 1);
7207 break;
7208
7209 case 'quarter':
7210 time = startOfDate(this.year(), this.month() - this.month() % 3, 1);
7211 break;
7212
7213 case 'month':
7214 time = startOfDate(this.year(), this.month(), 1);
7215 break;
7216
7217 case 'week':
7218 time = startOfDate(this.year(), this.month(), this.date() - this.weekday());
7219 break;
7220
7221 case 'isoWeek':
7222 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1));
7223 break;
7224
7225 case 'day':
7226 case 'date':
7227 time = startOfDate(this.year(), this.month(), this.date());
7228 break;
7229
7230 case 'hour':
7231 time = this._d.valueOf();
7232 time -= mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR);
7233 break;
7234
7235 case 'minute':
7236 time = this._d.valueOf();
7237 time -= mod$1(time, MS_PER_MINUTE);
7238 break;
7239
7240 case 'second':
7241 time = this._d.valueOf();
7242 time -= mod$1(time, MS_PER_SECOND);
7243 break;
7244 }
7245
7246 this._d.setTime(time);
7247
7248 hooks.updateOffset(this, true);
7249 return this;
7250 }
7251
7252 function endOf(units) {
7253 var time;
7254 units = normalizeUnits(units);
7255
7256 if (units === undefined || units === 'millisecond' || !this.isValid()) {
7257 return this;
7258 }
7259
7260 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
7261
7262 switch (units) {
7263 case 'year':
7264 time = startOfDate(this.year() + 1, 0, 1) - 1;
7265 break;
7266
7267 case 'quarter':
7268 time = startOfDate(this.year(), this.month() - this.month() % 3 + 3, 1) - 1;
7269 break;
7270
7271 case 'month':
7272 time = startOfDate(this.year(), this.month() + 1, 1) - 1;
7273 break;
7274
7275 case 'week':
7276 time = startOfDate(this.year(), this.month(), this.date() - this.weekday() + 7) - 1;
7277 break;
7278
7279 case 'isoWeek':
7280 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1) + 7) - 1;
7281 break;
7282
7283 case 'day':
7284 case 'date':
7285 time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
7286 break;
7287
7288 case 'hour':
7289 time = this._d.valueOf();
7290 time += MS_PER_HOUR - mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR) - 1;
7291 break;
7292
7293 case 'minute':
7294 time = this._d.valueOf();
7295 time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
7296 break;
7297
7298 case 'second':
7299 time = this._d.valueOf();
7300 time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
7301 break;
7302 }
7303
7304 this._d.setTime(time);
7305
7306 hooks.updateOffset(this, true);
7307 return this;
7308 }
7309
7310 function valueOf() {
7311 return this._d.valueOf() - (this._offset || 0) * 60000;
7312 }
7313
7314 function unix() {
7315 return Math.floor(this.valueOf() / 1000);
7316 }
7317
7318 function toDate() {
7319 return new Date(this.valueOf());
7320 }
7321
7322 function toArray() {
7323 var m = this;
7324 return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
7325 }
7326
7327 function toObject() {
7328 var m = this;
7329 return {
7330 years: m.year(),
7331 months: m.month(),
7332 date: m.date(),
7333 hours: m.hours(),
7334 minutes: m.minutes(),
7335 seconds: m.seconds(),
7336 milliseconds: m.milliseconds()
7337 };
7338 }
7339
7340 function toJSON() {
7341 // new Date(NaN).toJSON() === null
7342 return this.isValid() ? this.toISOString() : null;
7343 }
7344
7345 function isValid$2() {
7346 return isValid(this);
7347 }
7348
7349 function parsingFlags() {
7350 return extend({}, getParsingFlags(this));
7351 }
7352
7353 function invalidAt() {
7354 return getParsingFlags(this).overflow;
7355 }
7356
7357 function creationData() {
7358 return {
7359 input: this._i,
7360 format: this._f,
7361 locale: this._locale,
7362 isUTC: this._isUTC,
7363 strict: this._strict
7364 };
7365 } // FORMATTING
7366
7367
7368 addFormatToken(0, ['gg', 2], 0, function () {
7369 return this.weekYear() % 100;
7370 });
7371 addFormatToken(0, ['GG', 2], 0, function () {
7372 return this.isoWeekYear() % 100;
7373 });
7374
7375 function addWeekYearFormatToken(token, getter) {
7376 addFormatToken(0, [token, token.length], 0, getter);
7377 }
7378
7379 addWeekYearFormatToken('gggg', 'weekYear');
7380 addWeekYearFormatToken('ggggg', 'weekYear');
7381 addWeekYearFormatToken('GGGG', 'isoWeekYear');
7382 addWeekYearFormatToken('GGGGG', 'isoWeekYear'); // ALIASES
7383
7384 addUnitAlias('weekYear', 'gg');
7385 addUnitAlias('isoWeekYear', 'GG'); // PRIORITY
7386
7387 addUnitPriority('weekYear', 1);
7388 addUnitPriority('isoWeekYear', 1); // PARSING
7389
7390 addRegexToken('G', matchSigned);
7391 addRegexToken('g', matchSigned);
7392 addRegexToken('GG', match1to2, match2);
7393 addRegexToken('gg', match1to2, match2);
7394 addRegexToken('GGGG', match1to4, match4);
7395 addRegexToken('gggg', match1to4, match4);
7396 addRegexToken('GGGGG', match1to6, match6);
7397 addRegexToken('ggggg', match1to6, match6);
7398 addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
7399 week[token.substr(0, 2)] = toInt(input);
7400 });
7401 addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
7402 week[token] = hooks.parseTwoDigitYear(input);
7403 }); // MOMENTS
7404
7405 function getSetWeekYear(input) {
7406 return getSetWeekYearHelper.call(this, input, this.week(), this.weekday(), this.localeData()._week.dow, this.localeData()._week.doy);
7407 }
7408
7409 function getSetISOWeekYear(input) {
7410 return getSetWeekYearHelper.call(this, input, this.isoWeek(), this.isoWeekday(), 1, 4);
7411 }
7412
7413 function getISOWeeksInYear() {
7414 return weeksInYear(this.year(), 1, 4);
7415 }
7416
7417 function getWeeksInYear() {
7418 var weekInfo = this.localeData()._week;
7419
7420 return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
7421 }
7422
7423 function getSetWeekYearHelper(input, week, weekday, dow, doy) {
7424 var weeksTarget;
7425
7426 if (input == null) {
7427 return weekOfYear(this, dow, doy).year;
7428 } else {
7429 weeksTarget = weeksInYear(input, dow, doy);
7430
7431 if (week > weeksTarget) {
7432 week = weeksTarget;
7433 }
7434
7435 return setWeekAll.call(this, input, week, weekday, dow, doy);
7436 }
7437 }
7438
7439 function setWeekAll(weekYear, week, weekday, dow, doy) {
7440 var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
7441 date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
7442 this.year(date.getUTCFullYear());
7443 this.month(date.getUTCMonth());
7444 this.date(date.getUTCDate());
7445 return this;
7446 } // FORMATTING
7447
7448
7449 addFormatToken('Q', 0, 'Qo', 'quarter'); // ALIASES
7450
7451 addUnitAlias('quarter', 'Q'); // PRIORITY
7452
7453 addUnitPriority('quarter', 7); // PARSING
7454
7455 addRegexToken('Q', match1);
7456 addParseToken('Q', function (input, array) {
7457 array[MONTH] = (toInt(input) - 1) * 3;
7458 }); // MOMENTS
7459
7460 function getSetQuarter(input) {
7461 return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
7462 } // FORMATTING
7463
7464
7465 addFormatToken('D', ['DD', 2], 'Do', 'date'); // ALIASES
7466
7467 addUnitAlias('date', 'D'); // PRIORITY
7468
7469 addUnitPriority('date', 9); // PARSING
7470
7471 addRegexToken('D', match1to2);
7472 addRegexToken('DD', match1to2, match2);
7473 addRegexToken('Do', function (isStrict, locale) {
7474 // TODO: Remove "ordinalParse" fallback in next major release.
7475 return isStrict ? locale._dayOfMonthOrdinalParse || locale._ordinalParse : locale._dayOfMonthOrdinalParseLenient;
7476 });
7477 addParseToken(['D', 'DD'], DATE);
7478 addParseToken('Do', function (input, array) {
7479 array[DATE] = toInt(input.match(match1to2)[0]);
7480 }); // MOMENTS
7481
7482 var getSetDayOfMonth = makeGetSet('Date', true); // FORMATTING
7483
7484 addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); // ALIASES
7485
7486 addUnitAlias('dayOfYear', 'DDD'); // PRIORITY
7487
7488 addUnitPriority('dayOfYear', 4); // PARSING
7489
7490 addRegexToken('DDD', match1to3);
7491 addRegexToken('DDDD', match3);
7492 addParseToken(['DDD', 'DDDD'], function (input, array, config) {
7493 config._dayOfYear = toInt(input);
7494 }); // HELPERS
7495 // MOMENTS
7496
7497 function getSetDayOfYear(input) {
7498 var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
7499 return input == null ? dayOfYear : this.add(input - dayOfYear, 'd');
7500 } // FORMATTING
7501
7502
7503 addFormatToken('m', ['mm', 2], 0, 'minute'); // ALIASES
7504
7505 addUnitAlias('minute', 'm'); // PRIORITY
7506
7507 addUnitPriority('minute', 14); // PARSING
7508
7509 addRegexToken('m', match1to2);
7510 addRegexToken('mm', match1to2, match2);
7511 addParseToken(['m', 'mm'], MINUTE); // MOMENTS
7512
7513 var getSetMinute = makeGetSet('Minutes', false); // FORMATTING
7514
7515 addFormatToken('s', ['ss', 2], 0, 'second'); // ALIASES
7516
7517 addUnitAlias('second', 's'); // PRIORITY
7518
7519 addUnitPriority('second', 15); // PARSING
7520
7521 addRegexToken('s', match1to2);
7522 addRegexToken('ss', match1to2, match2);
7523 addParseToken(['s', 'ss'], SECOND); // MOMENTS
7524
7525 var getSetSecond = makeGetSet('Seconds', false); // FORMATTING
7526
7527 addFormatToken('S', 0, 0, function () {
7528 return ~~(this.millisecond() / 100);
7529 });
7530 addFormatToken(0, ['SS', 2], 0, function () {
7531 return ~~(this.millisecond() / 10);
7532 });
7533 addFormatToken(0, ['SSS', 3], 0, 'millisecond');
7534 addFormatToken(0, ['SSSS', 4], 0, function () {
7535 return this.millisecond() * 10;
7536 });
7537 addFormatToken(0, ['SSSSS', 5], 0, function () {
7538 return this.millisecond() * 100;
7539 });
7540 addFormatToken(0, ['SSSSSS', 6], 0, function () {
7541 return this.millisecond() * 1000;
7542 });
7543 addFormatToken(0, ['SSSSSSS', 7], 0, function () {
7544 return this.millisecond() * 10000;
7545 });
7546 addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
7547 return this.millisecond() * 100000;
7548 });
7549 addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
7550 return this.millisecond() * 1000000;
7551 }); // ALIASES
7552
7553 addUnitAlias('millisecond', 'ms'); // PRIORITY
7554
7555 addUnitPriority('millisecond', 16); // PARSING
7556
7557 addRegexToken('S', match1to3, match1);
7558 addRegexToken('SS', match1to3, match2);
7559 addRegexToken('SSS', match1to3, match3);
7560 var token;
7561
7562 for (token = 'SSSS'; token.length <= 9; token += 'S') {
7563 addRegexToken(token, matchUnsigned);
7564 }
7565
7566 function parseMs(input, array) {
7567 array[MILLISECOND] = toInt(('0.' + input) * 1000);
7568 }
7569
7570 for (token = 'S'; token.length <= 9; token += 'S') {
7571 addParseToken(token, parseMs);
7572 } // MOMENTS
7573
7574
7575 var getSetMillisecond = makeGetSet('Milliseconds', false); // FORMATTING
7576
7577 addFormatToken('z', 0, 0, 'zoneAbbr');
7578 addFormatToken('zz', 0, 0, 'zoneName'); // MOMENTS
7579
7580 function getZoneAbbr() {
7581 return this._isUTC ? 'UTC' : '';
7582 }
7583
7584 function getZoneName() {
7585 return this._isUTC ? 'Coordinated Universal Time' : '';
7586 }
7587
7588 var proto = Moment.prototype;
7589 proto.add = add;
7590 proto.calendar = calendar$1;
7591 proto.clone = clone;
7592 proto.diff = diff;
7593 proto.endOf = endOf;
7594 proto.format = format;
7595 proto.from = from;
7596 proto.fromNow = fromNow;
7597 proto.to = to;
7598 proto.toNow = toNow;
7599 proto.get = stringGet;
7600 proto.invalidAt = invalidAt;
7601 proto.isAfter = isAfter;
7602 proto.isBefore = isBefore;
7603 proto.isBetween = isBetween;
7604 proto.isSame = isSame;
7605 proto.isSameOrAfter = isSameOrAfter;
7606 proto.isSameOrBefore = isSameOrBefore;
7607 proto.isValid = isValid$2;
7608 proto.lang = lang;
7609 proto.locale = locale;
7610 proto.localeData = localeData;
7611 proto.max = prototypeMax;
7612 proto.min = prototypeMin;
7613 proto.parsingFlags = parsingFlags;
7614 proto.set = stringSet;
7615 proto.startOf = startOf;
7616 proto.subtract = subtract;
7617 proto.toArray = toArray;
7618 proto.toObject = toObject;
7619 proto.toDate = toDate;
7620 proto.toISOString = toISOString;
7621 proto.inspect = inspect;
7622 proto.toJSON = toJSON;
7623 proto.toString = toString;
7624 proto.unix = unix;
7625 proto.valueOf = valueOf;
7626 proto.creationData = creationData;
7627 proto.year = getSetYear;
7628 proto.isLeapYear = getIsLeapYear;
7629 proto.weekYear = getSetWeekYear;
7630 proto.isoWeekYear = getSetISOWeekYear;
7631 proto.quarter = proto.quarters = getSetQuarter;
7632 proto.month = getSetMonth;
7633 proto.daysInMonth = getDaysInMonth;
7634 proto.week = proto.weeks = getSetWeek;
7635 proto.isoWeek = proto.isoWeeks = getSetISOWeek;
7636 proto.weeksInYear = getWeeksInYear;
7637 proto.isoWeeksInYear = getISOWeeksInYear;
7638 proto.date = getSetDayOfMonth;
7639 proto.day = proto.days = getSetDayOfWeek;
7640 proto.weekday = getSetLocaleDayOfWeek;
7641 proto.isoWeekday = getSetISODayOfWeek;
7642 proto.dayOfYear = getSetDayOfYear;
7643 proto.hour = proto.hours = getSetHour;
7644 proto.minute = proto.minutes = getSetMinute;
7645 proto.second = proto.seconds = getSetSecond;
7646 proto.millisecond = proto.milliseconds = getSetMillisecond;
7647 proto.utcOffset = getSetOffset;
7648 proto.utc = setOffsetToUTC;
7649 proto.local = setOffsetToLocal;
7650 proto.parseZone = setOffsetToParsedOffset;
7651 proto.hasAlignedHourOffset = hasAlignedHourOffset;
7652 proto.isDST = isDaylightSavingTime;
7653 proto.isLocal = isLocal;
7654 proto.isUtcOffset = isUtcOffset;
7655 proto.isUtc = isUtc;
7656 proto.isUTC = isUtc;
7657 proto.zoneAbbr = getZoneAbbr;
7658 proto.zoneName = getZoneName;
7659 proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
7660 proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
7661 proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
7662 proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
7663 proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
7664
7665 function createUnix(input) {
7666 return createLocal(input * 1000);
7667 }
7668
7669 function createInZone() {
7670 return createLocal.apply(null, arguments).parseZone();
7671 }
7672
7673 function preParsePostFormat(string) {
7674 return string;
7675 }
7676
7677 var proto$1 = Locale.prototype;
7678 proto$1.calendar = calendar;
7679 proto$1.longDateFormat = longDateFormat;
7680 proto$1.invalidDate = invalidDate;
7681 proto$1.ordinal = ordinal;
7682 proto$1.preparse = preParsePostFormat;
7683 proto$1.postformat = preParsePostFormat;
7684 proto$1.relativeTime = relativeTime;
7685 proto$1.pastFuture = pastFuture;
7686 proto$1.set = set;
7687 proto$1.months = localeMonths;
7688 proto$1.monthsShort = localeMonthsShort;
7689 proto$1.monthsParse = localeMonthsParse;
7690 proto$1.monthsRegex = monthsRegex;
7691 proto$1.monthsShortRegex = monthsShortRegex;
7692 proto$1.week = localeWeek;
7693 proto$1.firstDayOfYear = localeFirstDayOfYear;
7694 proto$1.firstDayOfWeek = localeFirstDayOfWeek;
7695 proto$1.weekdays = localeWeekdays;
7696 proto$1.weekdaysMin = localeWeekdaysMin;
7697 proto$1.weekdaysShort = localeWeekdaysShort;
7698 proto$1.weekdaysParse = localeWeekdaysParse;
7699 proto$1.weekdaysRegex = weekdaysRegex;
7700 proto$1.weekdaysShortRegex = weekdaysShortRegex;
7701 proto$1.weekdaysMinRegex = weekdaysMinRegex;
7702 proto$1.isPM = localeIsPM;
7703 proto$1.meridiem = localeMeridiem;
7704
7705 function get$1(format, index, field, setter) {
7706 var locale = getLocale();
7707 var utc = createUTC().set(setter, index);
7708 return locale[field](utc, format);
7709 }
7710
7711 function listMonthsImpl(format, index, field) {
7712 if (isNumber(format)) {
7713 index = format;
7714 format = undefined;
7715 }
7716
7717 format = format || '';
7718
7719 if (index != null) {
7720 return get$1(format, index, field, 'month');
7721 }
7722
7723 var i;
7724 var out = [];
7725
7726 for (i = 0; i < 12; i++) {
7727 out[i] = get$1(format, i, field, 'month');
7728 }
7729
7730 return out;
7731 } // ()
7732 // (5)
7733 // (fmt, 5)
7734 // (fmt)
7735 // (true)
7736 // (true, 5)
7737 // (true, fmt, 5)
7738 // (true, fmt)
7739
7740
7741 function listWeekdaysImpl(localeSorted, format, index, field) {
7742 if (typeof localeSorted === 'boolean') {
7743 if (isNumber(format)) {
7744 index = format;
7745 format = undefined;
7746 }
7747
7748 format = format || '';
7749 } else {
7750 format = localeSorted;
7751 index = format;
7752 localeSorted = false;
7753
7754 if (isNumber(format)) {
7755 index = format;
7756 format = undefined;
7757 }
7758
7759 format = format || '';
7760 }
7761
7762 var locale = getLocale(),
7763 shift = localeSorted ? locale._week.dow : 0;
7764
7765 if (index != null) {
7766 return get$1(format, (index + shift) % 7, field, 'day');
7767 }
7768
7769 var i;
7770 var out = [];
7771
7772 for (i = 0; i < 7; i++) {
7773 out[i] = get$1(format, (i + shift) % 7, field, 'day');
7774 }
7775
7776 return out;
7777 }
7778
7779 function listMonths(format, index) {
7780 return listMonthsImpl(format, index, 'months');
7781 }
7782
7783 function listMonthsShort(format, index) {
7784 return listMonthsImpl(format, index, 'monthsShort');
7785 }
7786
7787 function listWeekdays(localeSorted, format, index) {
7788 return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
7789 }
7790
7791 function listWeekdaysShort(localeSorted, format, index) {
7792 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
7793 }
7794
7795 function listWeekdaysMin(localeSorted, format, index) {
7796 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
7797 }
7798
7799 getSetGlobalLocale('en', {
7800 dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
7801 ordinal: function (number) {
7802 var b = number % 10,
7803 output = toInt(number % 100 / 10) === 1 ? 'th' : b === 1 ? 'st' : b === 2 ? 'nd' : b === 3 ? 'rd' : 'th';
7804 return number + output;
7805 }
7806 }); // Side effect imports
7807
7808 hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
7809 hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
7810 var mathAbs = Math.abs;
7811
7812 function abs() {
7813 var data = this._data;
7814 this._milliseconds = mathAbs(this._milliseconds);
7815 this._days = mathAbs(this._days);
7816 this._months = mathAbs(this._months);
7817 data.milliseconds = mathAbs(data.milliseconds);
7818 data.seconds = mathAbs(data.seconds);
7819 data.minutes = mathAbs(data.minutes);
7820 data.hours = mathAbs(data.hours);
7821 data.months = mathAbs(data.months);
7822 data.years = mathAbs(data.years);
7823 return this;
7824 }
7825
7826 function addSubtract$1(duration, input, value, direction) {
7827 var other = createDuration(input, value);
7828 duration._milliseconds += direction * other._milliseconds;
7829 duration._days += direction * other._days;
7830 duration._months += direction * other._months;
7831 return duration._bubble();
7832 } // supports only 2.0-style add(1, 's') or add(duration)
7833
7834
7835 function add$1(input, value) {
7836 return addSubtract$1(this, input, value, 1);
7837 } // supports only 2.0-style subtract(1, 's') or subtract(duration)
7838
7839
7840 function subtract$1(input, value) {
7841 return addSubtract$1(this, input, value, -1);
7842 }
7843
7844 function absCeil(number) {
7845 if (number < 0) {
7846 return Math.floor(number);
7847 } else {
7848 return Math.ceil(number);
7849 }
7850 }
7851
7852 function bubble() {
7853 var milliseconds = this._milliseconds;
7854 var days = this._days;
7855 var months = this._months;
7856 var data = this._data;
7857 var seconds, minutes, hours, years, monthsFromDays; // if we have a mix of positive and negative values, bubble down first
7858 // check: https://github.com/moment/moment/issues/2166
7859
7860 if (!(milliseconds >= 0 && days >= 0 && months >= 0 || milliseconds <= 0 && days <= 0 && months <= 0)) {
7861 milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
7862 days = 0;
7863 months = 0;
7864 } // The following code bubbles up values, see the tests for
7865 // examples of what that means.
7866
7867
7868 data.milliseconds = milliseconds % 1000;
7869 seconds = absFloor(milliseconds / 1000);
7870 data.seconds = seconds % 60;
7871 minutes = absFloor(seconds / 60);
7872 data.minutes = minutes % 60;
7873 hours = absFloor(minutes / 60);
7874 data.hours = hours % 24;
7875 days += absFloor(hours / 24); // convert days to months
7876
7877 monthsFromDays = absFloor(daysToMonths(days));
7878 months += monthsFromDays;
7879 days -= absCeil(monthsToDays(monthsFromDays)); // 12 months -> 1 year
7880
7881 years = absFloor(months / 12);
7882 months %= 12;
7883 data.days = days;
7884 data.months = months;
7885 data.years = years;
7886 return this;
7887 }
7888
7889 function daysToMonths(days) {
7890 // 400 years have 146097 days (taking into account leap year rules)
7891 // 400 years have 12 months === 4800
7892 return days * 4800 / 146097;
7893 }
7894
7895 function monthsToDays(months) {
7896 // the reverse of daysToMonths
7897 return months * 146097 / 4800;
7898 }
7899
7900 function as(units) {
7901 if (!this.isValid()) {
7902 return NaN;
7903 }
7904
7905 var days;
7906 var months;
7907 var milliseconds = this._milliseconds;
7908 units = normalizeUnits(units);
7909
7910 if (units === 'month' || units === 'quarter' || units === 'year') {
7911 days = this._days + milliseconds / 864e5;
7912 months = this._months + daysToMonths(days);
7913
7914 switch (units) {
7915 case 'month':
7916 return months;
7917
7918 case 'quarter':
7919 return months / 3;
7920
7921 case 'year':
7922 return months / 12;
7923 }
7924 } else {
7925 // handle milliseconds separately because of floating point math errors (issue #1867)
7926 days = this._days + Math.round(monthsToDays(this._months));
7927
7928 switch (units) {
7929 case 'week':
7930 return days / 7 + milliseconds / 6048e5;
7931
7932 case 'day':
7933 return days + milliseconds / 864e5;
7934
7935 case 'hour':
7936 return days * 24 + milliseconds / 36e5;
7937
7938 case 'minute':
7939 return days * 1440 + milliseconds / 6e4;
7940
7941 case 'second':
7942 return days * 86400 + milliseconds / 1000;
7943 // Math.floor prevents floating point math errors here
7944
7945 case 'millisecond':
7946 return Math.floor(days * 864e5) + milliseconds;
7947
7948 default:
7949 throw new Error('Unknown unit ' + units);
7950 }
7951 }
7952 } // TODO: Use this.as('ms')?
7953
7954
7955 function valueOf$1() {
7956 if (!this.isValid()) {
7957 return NaN;
7958 }
7959
7960 return this._milliseconds + this._days * 864e5 + this._months % 12 * 2592e6 + toInt(this._months / 12) * 31536e6;
7961 }
7962
7963 function makeAs(alias) {
7964 return function () {
7965 return this.as(alias);
7966 };
7967 }
7968
7969 var asMilliseconds = makeAs('ms');
7970 var asSeconds = makeAs('s');
7971 var asMinutes = makeAs('m');
7972 var asHours = makeAs('h');
7973 var asDays = makeAs('d');
7974 var asWeeks = makeAs('w');
7975 var asMonths = makeAs('M');
7976 var asQuarters = makeAs('Q');
7977 var asYears = makeAs('y');
7978
7979 function clone$1() {
7980 return createDuration(this);
7981 }
7982
7983 function get$2(units) {
7984 units = normalizeUnits(units);
7985 return this.isValid() ? this[units + 's']() : NaN;
7986 }
7987
7988 function makeGetter(name) {
7989 return function () {
7990 return this.isValid() ? this._data[name] : NaN;
7991 };
7992 }
7993
7994 var milliseconds = makeGetter('milliseconds');
7995 var seconds = makeGetter('seconds');
7996 var minutes = makeGetter('minutes');
7997 var hours = makeGetter('hours');
7998 var days = makeGetter('days');
7999 var months = makeGetter('months');
8000 var years = makeGetter('years');
8001
8002 function weeks() {
8003 return absFloor(this.days() / 7);
8004 }
8005
8006 var round = Math.round;
8007 var thresholds = {
8008 ss: 44,
8009 // a few seconds to seconds
8010 s: 45,
8011 // seconds to minute
8012 m: 45,
8013 // minutes to hour
8014 h: 22,
8015 // hours to day
8016 d: 26,
8017 // days to month
8018 M: 11 // months to year
8019
8020 }; // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
8021
8022 function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
8023 return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
8024 }
8025
8026 function relativeTime$1(posNegDuration, withoutSuffix, locale) {
8027 var duration = createDuration(posNegDuration).abs();
8028 var seconds = round(duration.as('s'));
8029 var minutes = round(duration.as('m'));
8030 var hours = round(duration.as('h'));
8031 var days = round(duration.as('d'));
8032 var months = round(duration.as('M'));
8033 var years = round(duration.as('y'));
8034 var a = seconds <= thresholds.ss && ['s', seconds] || seconds < thresholds.s && ['ss', seconds] || minutes <= 1 && ['m'] || minutes < thresholds.m && ['mm', minutes] || hours <= 1 && ['h'] || hours < thresholds.h && ['hh', hours] || days <= 1 && ['d'] || days < thresholds.d && ['dd', days] || months <= 1 && ['M'] || months < thresholds.M && ['MM', months] || years <= 1 && ['y'] || ['yy', years];
8035 a[2] = withoutSuffix;
8036 a[3] = +posNegDuration > 0;
8037 a[4] = locale;
8038 return substituteTimeAgo.apply(null, a);
8039 } // This function allows you to set the rounding function for relative time strings
8040
8041
8042 function getSetRelativeTimeRounding(roundingFunction) {
8043 if (roundingFunction === undefined) {
8044 return round;
8045 }
8046
8047 if (typeof roundingFunction === 'function') {
8048 round = roundingFunction;
8049 return true;
8050 }
8051
8052 return false;
8053 } // This function allows you to set a threshold for relative time strings
8054
8055
8056 function getSetRelativeTimeThreshold(threshold, limit) {
8057 if (thresholds[threshold] === undefined) {
8058 return false;
8059 }
8060
8061 if (limit === undefined) {
8062 return thresholds[threshold];
8063 }
8064
8065 thresholds[threshold] = limit;
8066
8067 if (threshold === 's') {
8068 thresholds.ss = limit - 1;
8069 }
8070
8071 return true;
8072 }
8073
8074 function humanize(withSuffix) {
8075 if (!this.isValid()) {
8076 return this.localeData().invalidDate();
8077 }
8078
8079 var locale = this.localeData();
8080 var output = relativeTime$1(this, !withSuffix, locale);
8081
8082 if (withSuffix) {
8083 output = locale.pastFuture(+this, output);
8084 }
8085
8086 return locale.postformat(output);
8087 }
8088
8089 var abs$1 = Math.abs;
8090
8091 function sign(x) {
8092 return (x > 0) - (x < 0) || +x;
8093 }
8094
8095 function toISOString$1() {
8096 // for ISO strings we do not use the normal bubbling rules:
8097 // * milliseconds bubble up until they become hours
8098 // * days do not bubble at all
8099 // * months bubble up until they become years
8100 // This is because there is no context-free conversion between hours and days
8101 // (think of clock changes)
8102 // and also not between days and months (28-31 days per month)
8103 if (!this.isValid()) {
8104 return this.localeData().invalidDate();
8105 }
8106
8107 var seconds = abs$1(this._milliseconds) / 1000;
8108 var days = abs$1(this._days);
8109 var months = abs$1(this._months);
8110 var minutes, hours, years; // 3600 seconds -> 60 minutes -> 1 hour
8111
8112 minutes = absFloor(seconds / 60);
8113 hours = absFloor(minutes / 60);
8114 seconds %= 60;
8115 minutes %= 60; // 12 months -> 1 year
8116
8117 years = absFloor(months / 12);
8118 months %= 12; // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
8119
8120 var Y = years;
8121 var M = months;
8122 var D = days;
8123 var h = hours;
8124 var m = minutes;
8125 var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
8126 var total = this.asSeconds();
8127
8128 if (!total) {
8129 // this is the same as C#'s (Noda) and python (isodate)...
8130 // but not other JS (goog.date)
8131 return 'P0D';
8132 }
8133
8134 var totalSign = total < 0 ? '-' : '';
8135 var ymSign = sign(this._months) !== sign(total) ? '-' : '';
8136 var daysSign = sign(this._days) !== sign(total) ? '-' : '';
8137 var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
8138 return totalSign + 'P' + (Y ? ymSign + Y + 'Y' : '') + (M ? ymSign + M + 'M' : '') + (D ? daysSign + D + 'D' : '') + (h || m || s ? 'T' : '') + (h ? hmsSign + h + 'H' : '') + (m ? hmsSign + m + 'M' : '') + (s ? hmsSign + s + 'S' : '');
8139 }
8140
8141 var proto$2 = Duration.prototype;
8142 proto$2.isValid = isValid$1;
8143 proto$2.abs = abs;
8144 proto$2.add = add$1;
8145 proto$2.subtract = subtract$1;
8146 proto$2.as = as;
8147 proto$2.asMilliseconds = asMilliseconds;
8148 proto$2.asSeconds = asSeconds;
8149 proto$2.asMinutes = asMinutes;
8150 proto$2.asHours = asHours;
8151 proto$2.asDays = asDays;
8152 proto$2.asWeeks = asWeeks;
8153 proto$2.asMonths = asMonths;
8154 proto$2.asQuarters = asQuarters;
8155 proto$2.asYears = asYears;
8156 proto$2.valueOf = valueOf$1;
8157 proto$2._bubble = bubble;
8158 proto$2.clone = clone$1;
8159 proto$2.get = get$2;
8160 proto$2.milliseconds = milliseconds;
8161 proto$2.seconds = seconds;
8162 proto$2.minutes = minutes;
8163 proto$2.hours = hours;
8164 proto$2.days = days;
8165 proto$2.weeks = weeks;
8166 proto$2.months = months;
8167 proto$2.years = years;
8168 proto$2.humanize = humanize;
8169 proto$2.toISOString = toISOString$1;
8170 proto$2.toString = toISOString$1;
8171 proto$2.toJSON = toISOString$1;
8172 proto$2.locale = locale;
8173 proto$2.localeData = localeData;
8174 proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
8175 proto$2.lang = lang; // Side effect imports
8176 // FORMATTING
8177
8178 addFormatToken('X', 0, 0, 'unix');
8179 addFormatToken('x', 0, 0, 'valueOf'); // PARSING
8180
8181 addRegexToken('x', matchSigned);
8182 addRegexToken('X', matchTimestamp);
8183 addParseToken('X', function (input, array, config) {
8184 config._d = new Date(parseFloat(input, 10) * 1000);
8185 });
8186 addParseToken('x', function (input, array, config) {
8187 config._d = new Date(toInt(input));
8188 }); // Side effect imports
8189
8190 hooks.version = '2.24.0';
8191 setHookCallback(createLocal);
8192 hooks.fn = proto;
8193 hooks.min = min;
8194 hooks.max = max;
8195 hooks.now = now;
8196 hooks.utc = createUTC;
8197 hooks.unix = createUnix;
8198 hooks.months = listMonths;
8199 hooks.isDate = isDate;
8200 hooks.locale = getSetGlobalLocale;
8201 hooks.invalid = createInvalid;
8202 hooks.duration = createDuration;
8203 hooks.isMoment = isMoment;
8204 hooks.weekdays = listWeekdays;
8205 hooks.parseZone = createInZone;
8206 hooks.localeData = getLocale;
8207 hooks.isDuration = isDuration;
8208 hooks.monthsShort = listMonthsShort;
8209 hooks.weekdaysMin = listWeekdaysMin;
8210 hooks.defineLocale = defineLocale;
8211 hooks.updateLocale = updateLocale;
8212 hooks.locales = listLocales;
8213 hooks.weekdaysShort = listWeekdaysShort;
8214 hooks.normalizeUnits = normalizeUnits;
8215 hooks.relativeTimeRounding = getSetRelativeTimeRounding;
8216 hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
8217 hooks.calendarFormat = getCalendarFormat;
8218 hooks.prototype = proto; // currently HTML5 input type only supports 24-hour formats
8219
8220 hooks.HTML5_FMT = {
8221 DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',
8222 // <input type="datetime-local" />
8223 DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',
8224 // <input type="datetime-local" step="1" />
8225 DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',
8226 // <input type="datetime-local" step="0.001" />
8227 DATE: 'YYYY-MM-DD',
8228 // <input type="date" />
8229 TIME: 'HH:mm',
8230 // <input type="time" />
8231 TIME_SECONDS: 'HH:mm:ss',
8232 // <input type="time" step="1" />
8233 TIME_MS: 'HH:mm:ss.SSS',
8234 // <input type="time" step="0.001" />
8235 WEEK: 'GGGG-[W]WW',
8236 // <input type="week" />
8237 MONTH: 'YYYY-MM' // <input type="month" />
8238
8239 };
8240 return hooks;
8241 });
8242 }); // Maps for number <-> hex string conversion
8243
8244 var byteToHex = [];
8245
8246 for (var i$1 = 0; i$1 < 256; i$1++) {
8247 byteToHex[i$1] = (i$1 + 0x100).toString(16).substr(1);
8248 }
8249 /**
8250 * Represent binary UUID into it's string representation.
8251 *
8252 * @param buf - Buffer containing UUID bytes.
8253 * @param offset - Offset from the start of the buffer where the UUID is saved (not needed if the buffer starts with the UUID).
8254 *
8255 * @returns String representation of the UUID.
8256 */
8257
8258
8259 function stringifyUUID(buf, offset) {
8260 var i = offset || 0;
8261 var bth = byteToHex;
8262 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
8263 }
8264 /**
8265 * Generate 16 random bytes to be used as a base for UUID.
8266 *
8267 * @ignore
8268 */
8269
8270
8271 var random = function () {
8272 if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
8273 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
8274 // Moderately fast, high quality
8275 var _rnds8 = new Uint8Array(16);
8276
8277 return function whatwgRNG() {
8278 crypto.getRandomValues(_rnds8);
8279 return _rnds8;
8280 };
8281 } // Math.random()-based (RNG)
8282 //
8283 // If all else fails, use Math.random().
8284 // It's fast, but is of unspecified quality.
8285
8286
8287 var _rnds = new Array(16);
8288
8289 return function () {
8290 for (var i = 0, r; i < 16; i++) {
8291 if ((i & 0x03) === 0) {
8292 r = Math.random() * 0x100000000;
8293 }
8294
8295 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
8296 }
8297
8298 return _rnds;
8299 }; // uuid.js
8300 //
8301 // Copyright (c) 2010-2012 Robert Kieffer
8302 // MIT License - http://opensource.org/licenses/mit-license.php
8303 // Unique ID creation requires a high quality random # generator. We feature
8304 // detect to determine the best RNG source, normalizing to a function that
8305 // returns 128-bits of randomness, since that's what's usually required
8306 // return require('./rng');
8307 }();
8308
8309 var byteToHex$1 = [];
8310
8311 for (var i$1$1 = 0; i$1$1 < 256; i$1$1++) {
8312 byteToHex$1[i$1$1] = (i$1$1 + 0x100).toString(16).substr(1);
8313 } // **`v1()` - Generate time-based UUID**
8314 //
8315 // Inspired by https://github.com/LiosK/UUID.js
8316 // and http://docs.python.org/library/uuid.html
8317 // random #'s we need to init node and clockseq
8318
8319
8320 var seedBytes = random(); // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
8321
8322 var defaultNodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; // Per 4.2.2, randomize (14 bit) clockseq
8323
8324 var defaultClockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; // Previous uuid creation time
8325
8326 /**
8327 * UUIDv4 options.
8328 */
8329
8330 /**
8331 * Generate UUIDv4
8332 *
8333 * @param options - Options to be used instead of default generated values.
8334 * String 'binary' is a shorthand for uuid4({}, new Array(16)).
8335 * @param buf - If present the buffer will be filled with the generated UUID.
8336 * @param offset - Offset of the UUID from the start of the buffer.
8337 *
8338 * @returns UUIDv4
8339 */
8340
8341 function uuid4() {
8342 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
8343 var buf = arguments.length > 1 ? arguments[1] : undefined;
8344 var offset = arguments.length > 2 ? arguments[2] : undefined; // Deprecated - 'format' argument, as supported in v1.2
8345
8346 var i = buf && offset || 0;
8347
8348 if (typeof options === 'string') {
8349 buf = options === 'binary' ? new Array(16) : undefined;
8350 options = {};
8351 }
8352
8353 var rnds = options.random || (options.rng || random)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
8354
8355 rnds[6] = rnds[6] & 0x0f | 0x40;
8356 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
8357
8358 if (buf) {
8359 for (var ii = 0; ii < 16; ii++) {
8360 buf[i + ii] = rnds[ii];
8361 }
8362 }
8363
8364 return buf || stringifyUUID(rnds);
8365 } // Rollup will complain about mixing default and named exports in UMD build,
8366 // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/'
8367 // code from http://momentjs.com/
8368
8369
8370 var ASPDateRegex = /^\/?Date\((-?\d+)/i; // Color REs
8371
8372 var fullHexRE = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
8373 var shortHexRE = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
8374 var rgbRE = /^rgb\( *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *\)$/i;
8375 var rgbaRE = /^rgba\( *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *([01]|0?\.\d+) *\)$/i;
8376 /**
8377 * Hue, Saturation, Value.
8378 */
8379
8380 /**
8381 * Test whether given object is a number
8382 *
8383 * @param value - Input value of unknown type.
8384 *
8385 * @returns True if number, false otherwise.
8386 */
8387
8388 function isNumber(value) {
8389 return value instanceof Number || typeof value === "number";
8390 }
8391 /**
8392 * Remove everything in the DOM object
8393 *
8394 * @param DOMobject - Node whose child nodes will be recursively deleted.
8395 */
8396
8397
8398 function recursiveDOMDelete(DOMobject) {
8399 if (DOMobject) {
8400 while (DOMobject.hasChildNodes() === true) {
8401 var child = DOMobject.firstChild;
8402
8403 if (child) {
8404 recursiveDOMDelete(child);
8405 DOMobject.removeChild(child);
8406 }
8407 }
8408 }
8409 }
8410 /**
8411 * Test whether given object is a string
8412 *
8413 * @param value - Input value of unknown type.
8414 *
8415 * @returns True if string, false otherwise.
8416 */
8417
8418
8419 function isString(value) {
8420 return value instanceof String || typeof value === "string";
8421 }
8422 /**
8423 * Test whether given object is a object (not primitive or null).
8424 *
8425 * @param value - Input value of unknown type.
8426 *
8427 * @returns True if not null object, false otherwise.
8428 */
8429
8430
8431 function isObject$1(value) {
8432 return _typeof(value) === "object" && value !== null;
8433 }
8434 /**
8435 * Test whether given object is a Date, or a String containing a Date
8436 *
8437 * @param value - Input value of unknown type.
8438 *
8439 * @returns True if Date instance or string date representation, false otherwise.
8440 */
8441
8442
8443 function isDate(value) {
8444 if (value instanceof Date) {
8445 return true;
8446 } else if (isString(value)) {
8447 // test whether this string contains a date
8448 var match = ASPDateRegex.exec(value);
8449
8450 if (match) {
8451 return true;
8452 } else if (!isNaN(Date.parse(value))) {
8453 return true;
8454 }
8455 }
8456
8457 return false;
8458 }
8459 /**
8460 * Test whether given object is a Moment date.
8461 * @TODO: This is basically a workaround, if Moment was imported property it wouldn't necessary as moment.isMoment is a TS type guard.
8462 *
8463 * @param value - Input value of unknown type.
8464 *
8465 * @returns True if Moment instance, false otherwise.
8466 */
8467
8468
8469 function isMoment(value) {
8470 return moment.isMoment(value);
8471 }
8472 /**
8473 * Copy property from b to a if property present in a.
8474 * If property in b explicitly set to null, delete it if `allowDeletion` set.
8475 *
8476 * Internal helper routine, should not be exported. Not added to `exports` for that reason.
8477 *
8478 * @param a - Target object.
8479 * @param b - Source object.
8480 * @param prop - Name of property to copy from b to a.
8481 * @param allowDeletion if true, delete property in a if explicitly set to null in b
8482 */
8483
8484
8485 function copyOrDelete(a, b, prop, allowDeletion) {
8486 var doDeletion = false;
8487
8488 if (allowDeletion === true) {
8489 doDeletion = b[prop] === null && a[prop] !== undefined;
8490 }
8491
8492 if (doDeletion) {
8493 delete a[prop];
8494 } else {
8495 a[prop] = b[prop]; // Remember, this is a reference copy!
8496 }
8497 }
8498 /**
8499 * Fill an object with a possibly partially defined other object.
8500 *
8501 * Only copies values for the properties already present in a.
8502 * That means an object is not created on a property if only the b object has it.
8503 *
8504 * @param a - The object that will have it's properties updated.
8505 * @param b - The object with property updates.
8506 * @param allowDeletion - if true, delete properties in a that are explicitly set to null in b
8507 */
8508
8509
8510 function fillIfDefined(a, b) {
8511 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; // NOTE: iteration of properties of a
8512 // NOTE: prototype properties iterated over as well
8513
8514 for (var prop in a) {
8515 if (b[prop] !== undefined) {
8516 if (b[prop] === null || _typeof(b[prop]) !== "object") {
8517 // Note: typeof null === 'object'
8518 copyOrDelete(a, b, prop, allowDeletion);
8519 } else {
8520 var aProp = a[prop];
8521 var bProp = b[prop];
8522
8523 if (isObject$1(aProp) && isObject$1(bProp)) {
8524 fillIfDefined(aProp, bProp, allowDeletion);
8525 }
8526 }
8527 }
8528 }
8529 }
8530 /**
8531 * Copy the values of all of the enumerable own properties from one or more source objects to a
8532 * target object. Returns the target object.
8533 *
8534 * @param target - The target object to copy to.
8535 * @param source - The source object from which to copy properties.
8536 *
8537 * @return The target object.
8538 */
8539
8540
8541 var extend = Object.assign;
8542 /**
8543 * Extend object a with selected properties of object b or a series of objects
8544 * Only properties with defined values are copied
8545 *
8546 * @param props - Properties to be copied to a.
8547 * @param a - The target.
8548 * @param others - The sources.
8549 *
8550 * @returns Argument a.
8551 */
8552
8553 function selectiveExtend(props, a) {
8554 if (!Array.isArray(props)) {
8555 throw new Error("Array with property names expected as first argument");
8556 }
8557
8558 for (var _len = arguments.length, others = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
8559 others[_key - 2] = arguments[_key];
8560 }
8561
8562 for (var _i = 0, _others = others; _i < _others.length; _i++) {
8563 var other = _others[_i];
8564
8565 for (var p = 0; p < props.length; p++) {
8566 var prop = props[p];
8567
8568 if (other && Object.prototype.hasOwnProperty.call(other, prop)) {
8569 a[prop] = other[prop];
8570 }
8571 }
8572 }
8573
8574 return a;
8575 }
8576 /**
8577 * Extend object a with selected properties of object b.
8578 * Only properties with defined values are copied.
8579 *
8580 * **Note:** Previous version of this routine implied that multiple source objects
8581 * could be used; however, the implementation was **wrong**.
8582 * Since multiple (>1) sources weren't used anywhere in the `vis.js` code,
8583 * this has been removed
8584 *
8585 * @param props - Names of first-level properties to copy over.
8586 * @param a - Target object.
8587 * @param b - Source object.
8588 * @param allowDeletion - If true, delete property in a if explicitly set to null in b.
8589 *
8590 * @returns Argument a.
8591 */
8592
8593
8594 function selectiveDeepExtend(props, a, b) {
8595 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; // TODO: add support for Arrays to deepExtend
8596
8597 if (Array.isArray(b)) {
8598 throw new TypeError("Arrays are not supported by deepExtend");
8599 }
8600
8601 for (var p = 0; p < props.length; p++) {
8602 var prop = props[p];
8603
8604 if (Object.prototype.hasOwnProperty.call(b, prop)) {
8605 if (b[prop] && b[prop].constructor === Object) {
8606 if (a[prop] === undefined) {
8607 a[prop] = {};
8608 }
8609
8610 if (a[prop].constructor === Object) {
8611 deepExtend(a[prop], b[prop], false, allowDeletion);
8612 } else {
8613 copyOrDelete(a, b, prop, allowDeletion);
8614 }
8615 } else if (Array.isArray(b[prop])) {
8616 throw new TypeError("Arrays are not supported by deepExtend");
8617 } else {
8618 copyOrDelete(a, b, prop, allowDeletion);
8619 }
8620 }
8621 }
8622
8623 return a;
8624 }
8625 /**
8626 * Extend object `a` with properties of object `b`, ignoring properties which are explicitly
8627 * specified to be excluded.
8628 *
8629 * The properties of `b` are considered for copying.
8630 * Properties which are themselves objects are are also extended.
8631 * Only properties with defined values are copied
8632 *
8633 * @param propsToExclude - Names of properties which should *not* be copied.
8634 * @param a - Object to extend.
8635 * @param b - Object to take properties from for extension.
8636 * @param allowDeletion - If true, delete properties in a that are explicitly set to null in b.
8637 *
8638 * @returns Argument a.
8639 */
8640
8641
8642 function selectiveNotDeepExtend(propsToExclude, a, b) {
8643 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; // TODO: add support for Arrays to deepExtend
8644 // NOTE: array properties have an else-below; apparently, there is a problem here.
8645
8646 if (Array.isArray(b)) {
8647 throw new TypeError("Arrays are not supported by deepExtend");
8648 }
8649
8650 for (var prop in b) {
8651 if (!Object.prototype.hasOwnProperty.call(b, prop)) {
8652 continue;
8653 } // Handle local properties only
8654
8655
8656 if (propsToExclude.indexOf(prop) !== -1) {
8657 continue;
8658 } // In exclusion list, skip
8659
8660
8661 if (b[prop] && b[prop].constructor === Object) {
8662 if (a[prop] === undefined) {
8663 a[prop] = {};
8664 }
8665
8666 if (a[prop].constructor === Object) {
8667 deepExtend(a[prop], b[prop]); // NOTE: allowDeletion not propagated!
8668 } else {
8669 copyOrDelete(a, b, prop, allowDeletion);
8670 }
8671 } else if (Array.isArray(b[prop])) {
8672 a[prop] = [];
8673
8674 for (var i = 0; i < b[prop].length; i++) {
8675 a[prop].push(b[prop][i]);
8676 }
8677 } else {
8678 copyOrDelete(a, b, prop, allowDeletion);
8679 }
8680 }
8681
8682 return a;
8683 }
8684 /**
8685 * Deep extend an object a with the properties of object b
8686 *
8687 * @param a - Target object.
8688 * @param b - Source object.
8689 * @param protoExtend - If true, the prototype values will also be extended
8690 * (ie. the options objects that inherit from others will also get the inherited options).
8691 * @param allowDeletion - If true, the values of fields that are null will be deleted.
8692 *
8693 * @returns Argument a.
8694 */
8695
8696
8697 function deepExtend(a, b) {
8698 var protoExtend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
8699 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
8700
8701 for (var prop in b) {
8702 if (Object.prototype.hasOwnProperty.call(b, prop) || protoExtend === true) {
8703 if (_typeof(b[prop]) === "object" && b[prop] !== null && Object.getPrototypeOf(b[prop]) === Object.prototype) {
8704 if (a[prop] === undefined) {
8705 a[prop] = deepExtend({}, b[prop], protoExtend); // NOTE: allowDeletion not propagated!
8706 } else if (_typeof(a[prop]) === "object" && a[prop] !== null && Object.getPrototypeOf(a[prop]) === Object.prototype) {
8707 deepExtend(a[prop], b[prop], protoExtend); // NOTE: allowDeletion not propagated!
8708 } else {
8709 copyOrDelete(a, b, prop, allowDeletion);
8710 }
8711 } else if (Array.isArray(b[prop])) {
8712 a[prop] = b[prop].slice();
8713 } else {
8714 copyOrDelete(a, b, prop, allowDeletion);
8715 }
8716 }
8717 }
8718
8719 return a;
8720 }
8721 /**
8722 * Test whether all elements in two arrays are equal.
8723 *
8724 * @param a - First array.
8725 * @param b - Second array.
8726 *
8727 * @returns True if both arrays have the same length and same elements (1 = '1').
8728 */
8729
8730
8731 function equalArray(a, b) {
8732 if (a.length !== b.length) {
8733 return false;
8734 }
8735
8736 for (var i = 0, len = a.length; i < len; i++) {
8737 if (a[i] != b[i]) {
8738 return false;
8739 }
8740 }
8741
8742 return true;
8743 }
8744 /**
8745 * Convert an object into another type
8746 *
8747 * @param object - Value of unknown type.
8748 * @param type - Name of the desired type.
8749 *
8750 * @returns Object in the desired type.
8751 * @throws Error
8752 */
8753
8754
8755 function convert(object, type) {
8756 var match;
8757
8758 if (object === undefined) {
8759 return undefined;
8760 }
8761
8762 if (object === null) {
8763 return null;
8764 }
8765
8766 if (!type) {
8767 return object;
8768 }
8769
8770 if (!(typeof type === "string") && !(type instanceof String)) {
8771 throw new Error("Type must be a string");
8772 } //noinspection FallthroughInSwitchStatementJS
8773
8774
8775 switch (type) {
8776 case "boolean":
8777 case "Boolean":
8778 return Boolean(object);
8779
8780 case "number":
8781 case "Number":
8782 if (isString(object) && !isNaN(Date.parse(object))) {
8783 return moment(object).valueOf();
8784 } else {
8785 // @TODO: I don't think that Number and String constructors are a good idea.
8786 // This could also fail if the object doesn't have valueOf method or if it's redefined.
8787 // For example: Object.create(null) or { valueOf: 7 }.
8788 return Number(object.valueOf());
8789 }
8790
8791 case "string":
8792 case "String":
8793 return String(object);
8794
8795 case "Date":
8796 if (isNumber(object)) {
8797 return new Date(object);
8798 }
8799
8800 if (object instanceof Date) {
8801 return new Date(object.valueOf());
8802 } else if (isMoment(object)) {
8803 return new Date(object.valueOf());
8804 }
8805
8806 if (isString(object)) {
8807 match = ASPDateRegex.exec(object);
8808
8809 if (match) {
8810 // object is an ASP date
8811 return new Date(Number(match[1])); // parse number
8812 } else {
8813 return moment(new Date(object)).toDate(); // parse string
8814 }
8815 } else {
8816 throw new Error("Cannot convert object of type " + getType(object) + " to type Date");
8817 }
8818
8819 case "Moment":
8820 if (isNumber(object)) {
8821 return moment(object);
8822 }
8823
8824 if (object instanceof Date) {
8825 return moment(object.valueOf());
8826 } else if (isMoment(object)) {
8827 return moment(object);
8828 }
8829
8830 if (isString(object)) {
8831 match = ASPDateRegex.exec(object);
8832
8833 if (match) {
8834 // object is an ASP date
8835 return moment(Number(match[1])); // parse number
8836 } else {
8837 return moment(object); // parse string
8838 }
8839 } else {
8840 throw new Error("Cannot convert object of type " + getType(object) + " to type Date");
8841 }
8842
8843 case "ISODate":
8844 if (isNumber(object)) {
8845 return new Date(object);
8846 } else if (object instanceof Date) {
8847 return object.toISOString();
8848 } else if (isMoment(object)) {
8849 return object.toDate().toISOString();
8850 } else if (isString(object)) {
8851 match = ASPDateRegex.exec(object);
8852
8853 if (match) {
8854 // object is an ASP date
8855 return new Date(Number(match[1])).toISOString(); // parse number
8856 } else {
8857 return moment(object).format(); // ISO 8601
8858 }
8859 } else {
8860 throw new Error("Cannot convert object of type " + getType(object) + " to type ISODate");
8861 }
8862
8863 case "ASPDate":
8864 if (isNumber(object)) {
8865 return "/Date(" + object + ")/";
8866 } else if (object instanceof Date || isMoment(object)) {
8867 return "/Date(" + object.valueOf() + ")/";
8868 } else if (isString(object)) {
8869 match = ASPDateRegex.exec(object);
8870
8871 var _value;
8872
8873 if (match) {
8874 // object is an ASP date
8875 _value = new Date(Number(match[1])).valueOf(); // parse number
8876 } else {
8877 _value = new Date(object).valueOf(); // parse string
8878 }
8879
8880 return "/Date(" + _value + ")/";
8881 } else {
8882 throw new Error("Cannot convert object of type " + getType(object) + " to type ASPDate");
8883 }
8884
8885 default:
8886 var never = type;
8887 throw new Error("Unknown type ".concat(never));
8888 }
8889 }
8890 /**
8891 * Get the type of an object, for example exports.getType([]) returns 'Array'
8892 *
8893 * @param object - Input value of unknown type.
8894 *
8895 * @returns Detected type.
8896 */
8897
8898
8899 function getType(object) {
8900 var type = _typeof(object);
8901
8902 if (type === "object") {
8903 if (object === null) {
8904 return "null";
8905 }
8906
8907 if (object instanceof Boolean) {
8908 return "Boolean";
8909 }
8910
8911 if (object instanceof Number) {
8912 return "Number";
8913 }
8914
8915 if (object instanceof String) {
8916 return "String";
8917 }
8918
8919 if (Array.isArray(object)) {
8920 return "Array";
8921 }
8922
8923 if (object instanceof Date) {
8924 return "Date";
8925 }
8926
8927 return "Object";
8928 }
8929
8930 if (type === "number") {
8931 return "Number";
8932 }
8933
8934 if (type === "boolean") {
8935 return "Boolean";
8936 }
8937
8938 if (type === "string") {
8939 return "String";
8940 }
8941
8942 if (type === undefined) {
8943 return "undefined";
8944 }
8945
8946 return type;
8947 }
8948 /**
8949 * Used to extend an array and copy it. This is used to propagate paths recursively.
8950 *
8951 * @param arr - First part.
8952 * @param newValue - The value to be aadded into the array.
8953 *
8954 * @returns A new array with all items from arr and newValue (which is last).
8955 */
8956
8957
8958 function copyAndExtendArray(arr, newValue) {
8959 return [].concat(_toConsumableArray(arr), [newValue]);
8960 }
8961 /**
8962 * Used to extend an array and copy it. This is used to propagate paths recursively.
8963 *
8964 * @param arr - The array to be copied.
8965 *
8966 * @returns Shallow copy of arr.
8967 */
8968
8969
8970 function copyArray(arr) {
8971 return arr.slice();
8972 }
8973 /**
8974 * Retrieve the absolute left value of a DOM element
8975 *
8976 * @param elem - A dom element, for example a div.
8977 *
8978 * @returns The absolute left position of this element in the browser page.
8979 */
8980
8981
8982 function getAbsoluteLeft(elem) {
8983 return elem.getBoundingClientRect().left;
8984 }
8985 /**
8986 * Retrieve the absolute right value of a DOM element
8987 *
8988 * @param elem - A dom element, for example a div.
8989 *
8990 * @returns The absolute right position of this element in the browser page.
8991 */
8992
8993
8994 function getAbsoluteRight(elem) {
8995 return elem.getBoundingClientRect().right;
8996 }
8997 /**
8998 * Retrieve the absolute top value of a DOM element
8999 *
9000 * @param elem - A dom element, for example a div.
9001 *
9002 * @returns The absolute top position of this element in the browser page.
9003 */
9004
9005
9006 function getAbsoluteTop(elem) {
9007 return elem.getBoundingClientRect().top;
9008 }
9009 /**
9010 * Add a className to the given elements style.
9011 *
9012 * @param elem - The element to which the classes will be added.
9013 * @param classNames - Space separated list of classes.
9014 */
9015
9016
9017 function addClassName(elem, classNames) {
9018 var classes = elem.className.split(" ");
9019 var newClasses = classNames.split(" ");
9020 classes = classes.concat(newClasses.filter(function (className) {
9021 return classes.indexOf(className) < 0;
9022 }));
9023 elem.className = classes.join(" ");
9024 }
9025 /**
9026 * Remove a className from the given elements style.
9027 *
9028 * @param elem - The element from which the classes will be removed.
9029 * @param classNames - Space separated list of classes.
9030 */
9031
9032
9033 function removeClassName(elem, classNames) {
9034 var classes = elem.className.split(" ");
9035 var oldClasses = classNames.split(" ");
9036 classes = classes.filter(function (className) {
9037 return oldClasses.indexOf(className) < 0;
9038 });
9039 elem.className = classes.join(" ");
9040 }
9041 /**
9042 * For each method for both arrays and objects.
9043 * In case of an array, the built-in Array.forEach() is applied (**No, it's not!**).
9044 * In case of an Object, the method loops over all properties of the object.
9045 *
9046 * @param object - An Object or Array to be iterated over.
9047 * @param callback - Array.forEach-like callback.
9048 */
9049
9050
9051 function forEach(object, callback) {
9052 if (Array.isArray(object)) {
9053 // array
9054 var len = object.length;
9055
9056 for (var i = 0; i < len; i++) {
9057 callback(object[i], i, object);
9058 }
9059 } else {
9060 // object
9061 for (var _key2 in object) {
9062 if (Object.prototype.hasOwnProperty.call(object, _key2)) {
9063 callback(object[_key2], _key2, object);
9064 }
9065 }
9066 }
9067 }
9068 /**
9069 * Convert an object into an array: all objects properties are put into the array. The resulting array is unordered.
9070 *
9071 * @param o - Object that contains the properties and methods.
9072 *
9073 * @returns An array of unordered values.
9074 */
9075
9076
9077 var toArray = Object.values;
9078 /**
9079 * Update a property in an object
9080 *
9081 * @param object - The object whose property will be updated.
9082 * @param key - Name of the property to be updated.
9083 * @param value - The new value to be assigned.
9084 *
9085 * @returns Whether the value was updated (true) or already strictly the same in the original object (false).
9086 */
9087
9088 function updateProperty(object, key, value) {
9089 if (object[key] !== value) {
9090 object[key] = value;
9091 return true;
9092 } else {
9093 return false;
9094 }
9095 }
9096 /**
9097 * Throttle the given function to be only executed once per animation frame.
9098 *
9099 * @param fn - The original function.
9100 *
9101 * @returns The throttled function.
9102 */
9103
9104
9105 function throttle(fn) {
9106 var scheduled = false;
9107 return function () {
9108 if (!scheduled) {
9109 scheduled = true;
9110 requestAnimationFrame(function () {
9111 scheduled = false;
9112 fn();
9113 });
9114 }
9115 };
9116 }
9117 /**
9118 * Add and event listener. Works for all browsers.
9119 *
9120 * @param element - The element to bind the event listener to.
9121 * @param action - Same as Element.addEventListener(action, —, —).
9122 * @param listener - Same as Element.addEventListener(—, listener, —).
9123 * @param useCapture - Same as Element.addEventListener(—, —, useCapture).
9124 */
9125
9126
9127 function addEventListener(element, action, listener, useCapture) {
9128 if (element.addEventListener) {
9129 if (useCapture === undefined) {
9130 useCapture = false;
9131 }
9132
9133 if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
9134 action = "DOMMouseScroll"; // For Firefox
9135 }
9136
9137 element.addEventListener(action, listener, useCapture);
9138 } else {
9139 // @TODO: IE types? Does anyone care?
9140 element.attachEvent("on" + action, listener); // IE browsers
9141 }
9142 }
9143 /**
9144 * Remove an event listener from an element
9145 *
9146 * @param element - The element to bind the event listener to.
9147 * @param action - Same as Element.removeEventListener(action, —, —).
9148 * @param listener - Same as Element.removeEventListener(—, listener, —).
9149 * @param useCapture - Same as Element.removeEventListener(—, —, useCapture).
9150 */
9151
9152
9153 function removeEventListener(element, action, listener, useCapture) {
9154 if (element.removeEventListener) {
9155 // non-IE browsers
9156 if (useCapture === undefined) {
9157 useCapture = false;
9158 }
9159
9160 if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
9161 action = "DOMMouseScroll"; // For Firefox
9162 }
9163
9164 element.removeEventListener(action, listener, useCapture);
9165 } else {
9166 // @TODO: IE types? Does anyone care?
9167 element.detachEvent("on" + action, listener); // IE browsers
9168 }
9169 }
9170 /**
9171 * Cancels the event's default action if it is cancelable, without stopping further propagation of the event.
9172 *
9173 * @param event - The event whose default action should be prevented.
9174 */
9175
9176
9177 function preventDefault(event) {
9178 if (!event) {
9179 event = window.event;
9180 }
9181
9182 if (!event) ;else if (event.preventDefault) {
9183 event.preventDefault(); // non-IE browsers
9184 } else {
9185 // @TODO: IE types? Does anyone care?
9186 event.returnValue = false; // IE browsers
9187 }
9188 }
9189 /**
9190 * Get HTML element which is the target of the event.
9191 *
9192 * @param event - The event.
9193 *
9194 * @returns The element or null if not obtainable.
9195 */
9196
9197
9198 function getTarget() {
9199 var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.event; // code from http://www.quirksmode.org/js/events_properties.html
9200 // @TODO: EventTarget can be almost anything, is it okay to return only Elements?
9201
9202 var target = null;
9203 if (!event) ;else if (event.target) {
9204 target = event.target;
9205 } else if (event.srcElement) {
9206 target = event.srcElement;
9207 }
9208
9209 if (!(target instanceof Element)) {
9210 return null;
9211 }
9212
9213 if (target.nodeType != null && target.nodeType == 3) {
9214 // defeat Safari bug
9215 target = target.parentNode;
9216
9217 if (!(target instanceof Element)) {
9218 return null;
9219 }
9220 }
9221
9222 return target;
9223 }
9224 /**
9225 * Check if given element contains given parent somewhere in the DOM tree
9226 *
9227 * @param element - The element to be tested.
9228 * @param parent - The ancestor (not necessarily parent) of the element.
9229 *
9230 * @returns True if parent is an ancestor of the element, false otherwise.
9231 */
9232
9233
9234 function hasParent(element, parent) {
9235 var elem = element;
9236
9237 while (elem) {
9238 if (elem === parent) {
9239 return true;
9240 } else if (elem.parentNode) {
9241 elem = elem.parentNode;
9242 } else {
9243 return false;
9244 }
9245 }
9246
9247 return false;
9248 }
9249
9250 var option = {
9251 /**
9252 * Convert a value into a boolean.
9253 *
9254 * @param value - Value to be converted intoboolean, a function will be executed as (() => unknown).
9255 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
9256 *
9257 * @returns Corresponding boolean value, if none then the default value, if none then null.
9258 */
9259 asBoolean: function asBoolean(value, defaultValue) {
9260 if (typeof value == "function") {
9261 value = value();
9262 }
9263
9264 if (value != null) {
9265 return value != false;
9266 }
9267
9268 return defaultValue || null;
9269 },
9270
9271 /**
9272 * Convert a value into a number.
9273 *
9274 * @param value - Value to be converted intonumber, a function will be executed as (() => unknown).
9275 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
9276 *
9277 * @returns Corresponding **boxed** number value, if none then the default value, if none then null.
9278 */
9279 asNumber: function asNumber(value, defaultValue) {
9280 if (typeof value == "function") {
9281 value = value();
9282 }
9283
9284 if (value != null) {
9285 return Number(value) || defaultValue || null;
9286 }
9287
9288 return defaultValue || null;
9289 },
9290
9291 /**
9292 * Convert a value into a string.
9293 *
9294 * @param value - Value to be converted intostring, a function will be executed as (() => unknown).
9295 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
9296 *
9297 * @returns Corresponding **boxed** string value, if none then the default value, if none then null.
9298 */
9299 asString: function asString(value, defaultValue) {
9300 if (typeof value == "function") {
9301 value = value();
9302 }
9303
9304 if (value != null) {
9305 return String(value);
9306 }
9307
9308 return defaultValue || null;
9309 },
9310
9311 /**
9312 * Convert a value into a size.
9313 *
9314 * @param value - Value to be converted intosize, a function will be executed as (() => unknown).
9315 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
9316 *
9317 * @returns Corresponding string value (number + 'px'), if none then the default value, if none then null.
9318 */
9319 asSize: function asSize(value, defaultValue) {
9320 if (typeof value == "function") {
9321 value = value();
9322 }
9323
9324 if (isString(value)) {
9325 return value;
9326 } else if (isNumber(value)) {
9327 return value + "px";
9328 } else {
9329 return defaultValue || null;
9330 }
9331 },
9332
9333 /**
9334 * Convert a value into a DOM Element.
9335 *
9336 * @param value - Value to be converted into DOM Element, a function will be executed as (() => unknown).
9337 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
9338 *
9339 * @returns The DOM Element, if none then the default value, if none then null.
9340 */
9341 asElement: function asElement(value, defaultValue) {
9342 if (typeof value == "function") {
9343 value = value();
9344 }
9345
9346 return value || defaultValue || null;
9347 }
9348 };
9349 /**
9350 * Convert hex color string into RGB color object.
9351 * http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
9352 *
9353 * @param hex - Hex color string (3 or 6 digits, with or without #).
9354 *
9355 * @returns RGB color object.
9356 */
9357
9358 function hexToRGB(hex) {
9359 var result;
9360
9361 switch (hex.length) {
9362 case 3:
9363 case 4:
9364 result = shortHexRE.exec(hex);
9365 return result ? {
9366 r: parseInt(result[1] + result[1], 16),
9367 g: parseInt(result[2] + result[2], 16),
9368 b: parseInt(result[3] + result[3], 16)
9369 } : null;
9370
9371 case 6:
9372 case 7:
9373 result = fullHexRE.exec(hex);
9374 return result ? {
9375 r: parseInt(result[1], 16),
9376 g: parseInt(result[2], 16),
9377 b: parseInt(result[3], 16)
9378 } : null;
9379
9380 default:
9381 return null;
9382 }
9383 }
9384 /**
9385 * This function takes string color in hex or RGB format and adds the opacity, RGBA is passed through unchanged.
9386 *
9387 * @param color - The color string (hex, RGB, RGBA).
9388 * @param opacity - The new opacity.
9389 *
9390 * @returns RGBA string, for example 'rgba(255, 0, 127, 0.3)'.
9391 */
9392
9393
9394 function overrideOpacity(color, opacity) {
9395 if (color.indexOf("rgba") !== -1) {
9396 return color;
9397 } else if (color.indexOf("rgb") !== -1) {
9398 var rgb = color.substr(color.indexOf("(") + 1).replace(")", "").split(",");
9399 return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + opacity + ")";
9400 } else {
9401 var _rgb = hexToRGB(color);
9402
9403 if (_rgb == null) {
9404 return color;
9405 } else {
9406 return "rgba(" + _rgb.r + "," + _rgb.g + "," + _rgb.b + "," + opacity + ")";
9407 }
9408 }
9409 }
9410 /**
9411 * Convert RGB <0, 255> into hex color string.
9412 *
9413 * @param red - Red channel.
9414 * @param green - Green channel.
9415 * @param blue - Blue channel.
9416 *
9417 * @returns Hex color string (for example: '#0acdc0').
9418 */
9419
9420
9421 function RGBToHex(red, green, blue) {
9422 return "#" + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1);
9423 }
9424 /**
9425 * Parse a color property into an object with border, background, and highlight colors
9426 *
9427 * @param inputColor - Shorthand color string or input color object.
9428 * @param defaultColor - Full color object to fill in missing values in inputColor.
9429 *
9430 * @returns Color object.
9431 */
9432
9433
9434 function parseColor(inputColor, defaultColor) {
9435 if (isString(inputColor)) {
9436 var colorStr = inputColor;
9437
9438 if (isValidRGB(colorStr)) {
9439 var rgb = colorStr.substr(4).substr(0, colorStr.length - 5).split(",").map(function (value) {
9440 return parseInt(value);
9441 });
9442 colorStr = RGBToHex(rgb[0], rgb[1], rgb[2]);
9443 }
9444
9445 if (isValidHex(colorStr) === true) {
9446 var hsv = hexToHSV(colorStr);
9447 var lighterColorHSV = {
9448 h: hsv.h,
9449 s: hsv.s * 0.8,
9450 v: Math.min(1, hsv.v * 1.02)
9451 };
9452 var darkerColorHSV = {
9453 h: hsv.h,
9454 s: Math.min(1, hsv.s * 1.25),
9455 v: hsv.v * 0.8
9456 };
9457 var darkerColorHex = HSVToHex(darkerColorHSV.h, darkerColorHSV.s, darkerColorHSV.v);
9458 var lighterColorHex = HSVToHex(lighterColorHSV.h, lighterColorHSV.s, lighterColorHSV.v);
9459 return {
9460 background: colorStr,
9461 border: darkerColorHex,
9462 highlight: {
9463 background: lighterColorHex,
9464 border: darkerColorHex
9465 },
9466 hover: {
9467 background: lighterColorHex,
9468 border: darkerColorHex
9469 }
9470 };
9471 } else {
9472 return {
9473 background: colorStr,
9474 border: colorStr,
9475 highlight: {
9476 background: colorStr,
9477 border: colorStr
9478 },
9479 hover: {
9480 background: colorStr,
9481 border: colorStr
9482 }
9483 };
9484 }
9485 } else {
9486 if (defaultColor) {
9487 var color = {
9488 background: inputColor.background || defaultColor.background,
9489 border: inputColor.border || defaultColor.border,
9490 highlight: isString(inputColor.highlight) ? {
9491 border: inputColor.highlight,
9492 background: inputColor.highlight
9493 } : {
9494 background: inputColor.highlight && inputColor.highlight.background || defaultColor.highlight.background,
9495 border: inputColor.highlight && inputColor.highlight.border || defaultColor.highlight.border
9496 },
9497 hover: isString(inputColor.hover) ? {
9498 border: inputColor.hover,
9499 background: inputColor.hover
9500 } : {
9501 border: inputColor.hover && inputColor.hover.border || defaultColor.hover.border,
9502 background: inputColor.hover && inputColor.hover.background || defaultColor.hover.background
9503 }
9504 };
9505 return color;
9506 } else {
9507 var _color = {
9508 background: inputColor.background || undefined,
9509 border: inputColor.border || undefined,
9510 highlight: isString(inputColor.highlight) ? {
9511 border: inputColor.highlight,
9512 background: inputColor.highlight
9513 } : {
9514 background: inputColor.highlight && inputColor.highlight.background || undefined,
9515 border: inputColor.highlight && inputColor.highlight.border || undefined
9516 },
9517 hover: isString(inputColor.hover) ? {
9518 border: inputColor.hover,
9519 background: inputColor.hover
9520 } : {
9521 border: inputColor.hover && inputColor.hover.border || undefined,
9522 background: inputColor.hover && inputColor.hover.background || undefined
9523 }
9524 };
9525 return _color;
9526 }
9527 }
9528 }
9529 /**
9530 * Convert RGB <0, 255> into HSV object.
9531 * http://www.javascripter.net/faq/rgb2hsv.htm
9532 *
9533 * @param red - Red channel.
9534 * @param green - Green channel.
9535 * @param blue - Blue channel.
9536 *
9537 * @returns HSV color object.
9538 */
9539
9540
9541 function RGBToHSV(red, green, blue) {
9542 red = red / 255;
9543 green = green / 255;
9544 blue = blue / 255;
9545 var minRGB = Math.min(red, Math.min(green, blue));
9546 var maxRGB = Math.max(red, Math.max(green, blue)); // Black-gray-white
9547
9548 if (minRGB === maxRGB) {
9549 return {
9550 h: 0,
9551 s: 0,
9552 v: minRGB
9553 };
9554 } // Colors other than black-gray-white:
9555
9556
9557 var d = red === minRGB ? green - blue : blue === minRGB ? red - green : blue - red;
9558 var h = red === minRGB ? 3 : blue === minRGB ? 1 : 5;
9559 var hue = 60 * (h - d / (maxRGB - minRGB)) / 360;
9560 var saturation = (maxRGB - minRGB) / maxRGB;
9561 var value = maxRGB;
9562 return {
9563 h: hue,
9564 s: saturation,
9565 v: value
9566 };
9567 }
9568
9569 var cssUtil = {
9570 // split a string with css styles into an object with key/values
9571 split: function split(cssText) {
9572 var styles = {};
9573 cssText.split(";").forEach(function (style) {
9574 if (style.trim() != "") {
9575 var parts = style.split(":");
9576
9577 var _key3 = parts[0].trim();
9578
9579 var _value2 = parts[1].trim();
9580
9581 styles[_key3] = _value2;
9582 }
9583 });
9584 return styles;
9585 },
9586 // build a css text string from an object with key/values
9587 join: function join(styles) {
9588 return Object.keys(styles).map(function (key) {
9589 return key + ": " + styles[key];
9590 }).join("; ");
9591 }
9592 };
9593 /**
9594 * Append a string with css styles to an element
9595 *
9596 * @param element - The element that will receive new styles.
9597 * @param cssText - The styles to be appended.
9598 */
9599
9600 function addCssText(element, cssText) {
9601 var currentStyles = cssUtil.split(element.style.cssText);
9602 var newStyles = cssUtil.split(cssText);
9603
9604 var styles = _objectSpread2({}, currentStyles, {}, newStyles);
9605
9606 element.style.cssText = cssUtil.join(styles);
9607 }
9608 /**
9609 * Remove a string with css styles from an element
9610 *
9611 * @param element - The element from which styles should be removed.
9612 * @param cssText - The styles to be removed.
9613 */
9614
9615
9616 function removeCssText(element, cssText) {
9617 var styles = cssUtil.split(element.style.cssText);
9618 var removeStyles = cssUtil.split(cssText);
9619
9620 for (var _key4 in removeStyles) {
9621 if (Object.prototype.hasOwnProperty.call(removeStyles, _key4)) {
9622 delete styles[_key4];
9623 }
9624 }
9625
9626 element.style.cssText = cssUtil.join(styles);
9627 }
9628 /**
9629 * Convert HSV <0, 1> into RGB color object.
9630 * https://gist.github.com/mjijackson/5311256
9631 *
9632 * @param h - Hue
9633 * @param s - Saturation
9634 * @param v - Value
9635 *
9636 * @returns RGB color object.
9637 */
9638
9639
9640 function HSVToRGB(h, s, v) {
9641 var r;
9642 var g;
9643 var b;
9644 var i = Math.floor(h * 6);
9645 var f = h * 6 - i;
9646 var p = v * (1 - s);
9647 var q = v * (1 - f * s);
9648 var t = v * (1 - (1 - f) * s);
9649
9650 switch (i % 6) {
9651 case 0:
9652 r = v, g = t, b = p;
9653 break;
9654
9655 case 1:
9656 r = q, g = v, b = p;
9657 break;
9658
9659 case 2:
9660 r = p, g = v, b = t;
9661 break;
9662
9663 case 3:
9664 r = p, g = q, b = v;
9665 break;
9666
9667 case 4:
9668 r = t, g = p, b = v;
9669 break;
9670
9671 case 5:
9672 r = v, g = p, b = q;
9673 break;
9674 }
9675
9676 return {
9677 r: Math.floor(r * 255),
9678 g: Math.floor(g * 255),
9679 b: Math.floor(b * 255)
9680 };
9681 }
9682 /**
9683 * Convert HSV <0, 1> into hex color string.
9684 *
9685 * @param h - Hue
9686 * @param s - Saturation
9687 * @param v - Value
9688 *
9689 * @returns Hex color string.
9690 */
9691
9692
9693 function HSVToHex(h, s, v) {
9694 var rgb = HSVToRGB(h, s, v);
9695 return RGBToHex(rgb.r, rgb.g, rgb.b);
9696 }
9697 /**
9698 * Convert hex color string into HSV <0, 1>.
9699 *
9700 * @param hex - Hex color string.
9701 *
9702 * @returns HSV color object.
9703 */
9704
9705
9706 function hexToHSV(hex) {
9707 var rgb = hexToRGB(hex);
9708
9709 if (!rgb) {
9710 throw new TypeError("'".concat(hex, "' is not a valid color."));
9711 }
9712
9713 return RGBToHSV(rgb.r, rgb.g, rgb.b);
9714 }
9715 /**
9716 * Validate hex color string.
9717 *
9718 * @param hex - Unknown string that may contain a color.
9719 *
9720 * @returns True if the string is valid, false otherwise.
9721 */
9722
9723
9724 function isValidHex(hex) {
9725 var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex);
9726 return isOk;
9727 }
9728 /**
9729 * Validate RGB color string.
9730 *
9731 * @param rgb - Unknown string that may contain a color.
9732 *
9733 * @returns True if the string is valid, false otherwise.
9734 */
9735
9736
9737 function isValidRGB(rgb) {
9738 return rgbRE.test(rgb);
9739 }
9740 /**
9741 * Validate RGBA color string.
9742 *
9743 * @param rgba - Unknown string that may contain a color.
9744 *
9745 * @returns True if the string is valid, false otherwise.
9746 */
9747
9748
9749 function isValidRGBA(rgba) {
9750 return rgbaRE.test(rgba);
9751 }
9752 /**
9753 * This recursively redirects the prototype of JSON objects to the referenceObject.
9754 * This is used for default options.
9755 *
9756 * @param fields - Names of properties to be bridged.
9757 * @param referenceObject - The original object.
9758 *
9759 * @returns A new object inheriting from the referenceObject.
9760 */
9761
9762
9763 function selectiveBridgeObject(fields, referenceObject) {
9764 if (referenceObject !== null && _typeof(referenceObject) === "object") {
9765 // !!! typeof null === 'object'
9766 var objectTo = Object.create(referenceObject);
9767
9768 for (var i = 0; i < fields.length; i++) {
9769 if (Object.prototype.hasOwnProperty.call(referenceObject, fields[i])) {
9770 if (_typeof(referenceObject[fields[i]]) == "object") {
9771 objectTo[fields[i]] = bridgeObject(referenceObject[fields[i]]);
9772 }
9773 }
9774 }
9775
9776 return objectTo;
9777 } else {
9778 return null;
9779 }
9780 }
9781 /**
9782 * This recursively redirects the prototype of JSON objects to the referenceObject.
9783 * This is used for default options.
9784 *
9785 * @param referenceObject - The original object.
9786 *
9787 * @returns The Element if the referenceObject is an Element, or a new object inheriting from the referenceObject.
9788 */
9789
9790
9791 function bridgeObject(referenceObject) {
9792 if (referenceObject === null || _typeof(referenceObject) !== "object") {
9793 return null;
9794 }
9795
9796 if (referenceObject instanceof Element) {
9797 // Avoid bridging DOM objects
9798 return referenceObject;
9799 }
9800
9801 var objectTo = Object.create(referenceObject);
9802
9803 for (var i in referenceObject) {
9804 if (Object.prototype.hasOwnProperty.call(referenceObject, i)) {
9805 if (_typeof(referenceObject[i]) == "object") {
9806 objectTo[i] = bridgeObject(referenceObject[i]);
9807 }
9808 }
9809 }
9810
9811 return objectTo;
9812 }
9813 /**
9814 * This method provides a stable sort implementation, very fast for presorted data.
9815 *
9816 * @param a - The array to be sorted (in-place).
9817 * @param compare - An order comparator.
9818 *
9819 * @returns The argument a.
9820 */
9821
9822
9823 function insertSort(a, compare) {
9824 for (var i = 0; i < a.length; i++) {
9825 var k = a[i];
9826 var j = void 0;
9827
9828 for (j = i; j > 0 && compare(k, a[j - 1]) < 0; j--) {
9829 a[j] = a[j - 1];
9830 }
9831
9832 a[j] = k;
9833 }
9834
9835 return a;
9836 }
9837 /**
9838 * This is used to set the options of subobjects in the options object.
9839 *
9840 * A requirement of these subobjects is that they have an 'enabled' element
9841 * which is optional for the user but mandatory for the program.
9842 *
9843 * The added value here of the merge is that option 'enabled' is set as required.
9844 *
9845 * @param mergeTarget - Either this.options or the options used for the groups.
9846 * @param options - Options.
9847 * @param option - Option key in the options argument.
9848 * @param globalOptions - Global options, passed in to determine value of option 'enabled'.
9849 */
9850
9851
9852 function mergeOptions(mergeTarget, options, option) {
9853 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; // Local helpers
9854
9855 var isPresent = function isPresent(obj) {
9856 return obj !== null && obj !== undefined;
9857 };
9858
9859 var isObject = function isObject(obj) {
9860 return obj !== null && _typeof(obj) === "object";
9861 }; // https://stackoverflow.com/a/34491287/1223531
9862
9863
9864 var isEmpty = function isEmpty(obj) {
9865 for (var x in obj) {
9866 if (Object.prototype.hasOwnProperty.call(obj, x)) {
9867 return false;
9868 }
9869 }
9870
9871 return true;
9872 }; // Guards
9873
9874
9875 if (!isObject(mergeTarget)) {
9876 throw new Error("Parameter mergeTarget must be an object");
9877 }
9878
9879 if (!isObject(options)) {
9880 throw new Error("Parameter options must be an object");
9881 }
9882
9883 if (!isPresent(option)) {
9884 throw new Error("Parameter option must have a value");
9885 }
9886
9887 if (!isObject(globalOptions)) {
9888 throw new Error("Parameter globalOptions must be an object");
9889 } //
9890 // Actual merge routine, separated from main logic
9891 // Only a single level of options is merged. Deeper levels are ref'd. This may actually be an issue.
9892 //
9893
9894
9895 var doMerge = function doMerge(target, options, option) {
9896 if (!isObject(target[option])) {
9897 target[option] = {};
9898 }
9899
9900 var src = options[option];
9901 var dst = target[option];
9902
9903 for (var prop in src) {
9904 if (Object.prototype.hasOwnProperty.call(src, prop)) {
9905 dst[prop] = src[prop];
9906 }
9907 }
9908 }; // Local initialization
9909
9910
9911 var srcOption = options[option];
9912 var globalPassed = isObject(globalOptions) && !isEmpty(globalOptions);
9913 var globalOption = globalPassed ? globalOptions[option] : undefined;
9914 var globalEnabled = globalOption ? globalOption.enabled : undefined; /////////////////////////////////////////
9915 // Main routine
9916 /////////////////////////////////////////
9917
9918 if (srcOption === undefined) {
9919 return; // Nothing to do
9920 }
9921
9922 if (typeof srcOption === "boolean") {
9923 if (!isObject(mergeTarget[option])) {
9924 mergeTarget[option] = {};
9925 }
9926
9927 mergeTarget[option].enabled = srcOption;
9928 return;
9929 }
9930
9931 if (srcOption === null && !isObject(mergeTarget[option])) {
9932 // If possible, explicit copy from globals
9933 if (isPresent(globalOption)) {
9934 mergeTarget[option] = Object.create(globalOption);
9935 } else {
9936 return; // Nothing to do
9937 }
9938 }
9939
9940 if (!isObject(srcOption)) {
9941 return;
9942 } //
9943 // Ensure that 'enabled' is properly set. It is required internally
9944 // Note that the value from options will always overwrite the existing value
9945 //
9946
9947
9948 var enabled = true; // default value
9949
9950 if (srcOption.enabled !== undefined) {
9951 enabled = srcOption.enabled;
9952 } else {
9953 // Take from globals, if present
9954 if (globalEnabled !== undefined) {
9955 enabled = globalOption.enabled;
9956 }
9957 }
9958
9959 doMerge(mergeTarget, options, option);
9960 mergeTarget[option].enabled = enabled;
9961 }
9962 /**
9963 * This function does a binary search for a visible item in a sorted list. If we find a visible item, the code that uses
9964 * this function will then iterate in both directions over this sorted list to find all visible items.
9965 *
9966 * @param orderedItems - Items ordered by start
9967 * @param comparator - -1 is lower, 0 is equal, 1 is higher
9968 * @param field - Property name on an item (i.e. item[field]).
9969 * @param field2 - Second property name on an item (i.e. item[field][field2]).
9970 *
9971 * @returns Index of the found item or -1 if nothing was found.
9972 */
9973
9974
9975 function binarySearchCustom(orderedItems, comparator, field, field2) {
9976 var maxIterations = 10000;
9977 var iteration = 0;
9978 var low = 0;
9979 var high = orderedItems.length - 1;
9980
9981 while (low <= high && iteration < maxIterations) {
9982 var middle = Math.floor((low + high) / 2);
9983 var item = orderedItems[middle];
9984
9985 var _value3 = field2 === undefined ? item[field] : item[field][field2];
9986
9987 var searchResult = comparator(_value3);
9988
9989 if (searchResult == 0) {
9990 // jihaa, found a visible item!
9991 return middle;
9992 } else if (searchResult == -1) {
9993 // it is too small --> increase low
9994 low = middle + 1;
9995 } else {
9996 // it is too big --> decrease high
9997 high = middle - 1;
9998 }
9999
10000 iteration++;
10001 }
10002
10003 return -1;
10004 }
10005 /**
10006 * This function does a binary search for a specific value in a sorted array. If it does not exist but is in between of
10007 * two values, we return either the one before or the one after, depending on user input
10008 * If it is found, we return the index, else -1.
10009 *
10010 * @param orderedItems - Sorted array.
10011 * @param target - The searched value.
10012 * @param field - Name of the property in items to be searched.
10013 * @param sidePreference - If the target is between two values, should the index of the before or the after be returned?
10014 * @param comparator - An optional comparator, returning -1, 0, 1 for <, ===, >.
10015 *
10016 * @returns The index of found value or -1 if nothing was found.
10017 */
10018
10019
10020 function binarySearchValue(orderedItems, target, field, sidePreference, comparator) {
10021 var maxIterations = 10000;
10022 var iteration = 0;
10023 var low = 0;
10024 var high = orderedItems.length - 1;
10025 var prevValue;
10026 var value;
10027 var nextValue;
10028 var middle;
10029 comparator = comparator != undefined ? comparator : function (a, b) {
10030 return a == b ? 0 : a < b ? -1 : 1;
10031 };
10032
10033 while (low <= high && iteration < maxIterations) {
10034 // get a new guess
10035 middle = Math.floor(0.5 * (high + low));
10036 prevValue = orderedItems[Math.max(0, middle - 1)][field];
10037 value = orderedItems[middle][field];
10038 nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field];
10039
10040 if (comparator(value, target) == 0) {
10041 // we found the target
10042 return middle;
10043 } else if (comparator(prevValue, target) < 0 && comparator(value, target) > 0) {
10044 // target is in between of the previous and the current
10045 return sidePreference == "before" ? Math.max(0, middle - 1) : middle;
10046 } else if (comparator(value, target) < 0 && comparator(nextValue, target) > 0) {
10047 // target is in between of the current and the next
10048 return sidePreference == "before" ? middle : Math.min(orderedItems.length - 1, middle + 1);
10049 } else {
10050 // didnt find the target, we need to change our boundaries.
10051 if (comparator(value, target) < 0) {
10052 // it is too small --> increase low
10053 low = middle + 1;
10054 } else {
10055 // it is too big --> decrease high
10056 high = middle - 1;
10057 }
10058 }
10059
10060 iteration++;
10061 } // didnt find anything. Return -1.
10062
10063
10064 return -1;
10065 }
10066 /*
10067 * Easing Functions.
10068 * Only considering the t value for the range [0, 1] => [0, 1].
10069 *
10070 * Inspiration: from http://gizma.com/easing/
10071 * https://gist.github.com/gre/1650294
10072 */
10073
10074
10075 var easingFunctions = {
10076 /**
10077 * no easing, no acceleration
10078 *
10079 * @param t - Time.
10080 *
10081 * @returns Value at time t.
10082 */
10083 linear: function linear(t) {
10084 return t;
10085 },
10086
10087 /**
10088 * accelerating from zero velocity
10089 *
10090 * @param t - Time.
10091 *
10092 * @returns Value at time t.
10093 */
10094 easeInQuad: function easeInQuad(t) {
10095 return t * t;
10096 },
10097
10098 /**
10099 * decelerating to zero velocity
10100 *
10101 * @param t - Time.
10102 *
10103 * @returns Value at time t.
10104 */
10105 easeOutQuad: function easeOutQuad(t) {
10106 return t * (2 - t);
10107 },
10108
10109 /**
10110 * acceleration until halfway, then deceleration
10111 *
10112 * @param t - Time.
10113 *
10114 * @returns Value at time t.
10115 */
10116 easeInOutQuad: function easeInOutQuad(t) {
10117 return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
10118 },
10119
10120 /**
10121 * accelerating from zero velocity
10122 *
10123 * @param t - Time.
10124 *
10125 * @returns Value at time t.
10126 */
10127 easeInCubic: function easeInCubic(t) {
10128 return t * t * t;
10129 },
10130
10131 /**
10132 * decelerating to zero velocity
10133 *
10134 * @param t - Time.
10135 *
10136 * @returns Value at time t.
10137 */
10138 easeOutCubic: function easeOutCubic(t) {
10139 return --t * t * t + 1;
10140 },
10141
10142 /**
10143 * acceleration until halfway, then deceleration
10144 *
10145 * @param t - Time.
10146 *
10147 * @returns Value at time t.
10148 */
10149 easeInOutCubic: function easeInOutCubic(t) {
10150 return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
10151 },
10152
10153 /**
10154 * accelerating from zero velocity
10155 *
10156 * @param t - Time.
10157 *
10158 * @returns Value at time t.
10159 */
10160 easeInQuart: function easeInQuart(t) {
10161 return t * t * t * t;
10162 },
10163
10164 /**
10165 * decelerating to zero velocity
10166 *
10167 * @param t - Time.
10168 *
10169 * @returns Value at time t.
10170 */
10171 easeOutQuart: function easeOutQuart(t) {
10172 return 1 - --t * t * t * t;
10173 },
10174
10175 /**
10176 * acceleration until halfway, then deceleration
10177 *
10178 * @param t - Time.
10179 *
10180 * @returns Value at time t.
10181 */
10182 easeInOutQuart: function easeInOutQuart(t) {
10183 return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
10184 },
10185
10186 /**
10187 * accelerating from zero velocity
10188 *
10189 * @param t - Time.
10190 *
10191 * @returns Value at time t.
10192 */
10193 easeInQuint: function easeInQuint(t) {
10194 return t * t * t * t * t;
10195 },
10196
10197 /**
10198 * decelerating to zero velocity
10199 *
10200 * @param t - Time.
10201 *
10202 * @returns Value at time t.
10203 */
10204 easeOutQuint: function easeOutQuint(t) {
10205 return 1 + --t * t * t * t * t;
10206 },
10207
10208 /**
10209 * acceleration until halfway, then deceleration
10210 *
10211 * @param t - Time.
10212 *
10213 * @returns Value at time t.
10214 */
10215 easeInOutQuint: function easeInOutQuint(t) {
10216 return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
10217 }
10218 };
10219 /**
10220 * Experimentaly compute the width of the scrollbar for this browser.
10221 *
10222 * @returns The width in pixels.
10223 */
10224
10225 function getScrollBarWidth() {
10226 var inner = document.createElement("p");
10227 inner.style.width = "100%";
10228 inner.style.height = "200px";
10229 var outer = document.createElement("div");
10230 outer.style.position = "absolute";
10231 outer.style.top = "0px";
10232 outer.style.left = "0px";
10233 outer.style.visibility = "hidden";
10234 outer.style.width = "200px";
10235 outer.style.height = "150px";
10236 outer.style.overflow = "hidden";
10237 outer.appendChild(inner);
10238 document.body.appendChild(outer);
10239 var w1 = inner.offsetWidth;
10240 outer.style.overflow = "scroll";
10241 var w2 = inner.offsetWidth;
10242
10243 if (w1 == w2) {
10244 w2 = outer.clientWidth;
10245 }
10246
10247 document.body.removeChild(outer);
10248 return w1 - w2;
10249 } // @TODO: This doesn't work properly.
10250 // It works only for single property objects,
10251 // otherwise it combines all of the types in a union.
10252 // export function topMost<K1 extends string, V1> (
10253 // pile: Record<K1, undefined | V1>[],
10254 // accessors: K1 | [K1]
10255 // ): undefined | V1
10256 // export function topMost<K1 extends string, K2 extends string, V1, V2> (
10257 // pile: Record<K1, undefined | V1 | Record<K2, undefined | V2>>[],
10258 // accessors: [K1, K2]
10259 // ): undefined | V1 | V2
10260 // export function topMost<K1 extends string, K2 extends string, K3 extends string, V1, V2, V3> (
10261 // pile: Record<K1, undefined | V1 | Record<K2, undefined | V2 | Record<K3, undefined | V3>>>[],
10262 // accessors: [K1, K2, K3]
10263 // ): undefined | V1 | V2 | V3
10264
10265 /**
10266 * Get the top most property value from a pile of objects.
10267 *
10268 * @param pile - Array of objects, no required format.
10269 * @param accessors - Array of property names (e.g. object['foo']['bar'] → ['foo', 'bar']).
10270 *
10271 * @returns Value of the property with given accessors path from the first pile item where it's not undefined.
10272 */
10273
10274
10275 function topMost(pile, accessors) {
10276 var candidate;
10277
10278 if (!Array.isArray(accessors)) {
10279 accessors = [accessors];
10280 }
10281
10282 var _iteratorNormalCompletion = true;
10283 var _didIteratorError = false;
10284 var _iteratorError = undefined;
10285
10286 try {
10287 for (var _iterator = pile[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
10288 var member = _step.value;
10289
10290 if (member) {
10291 candidate = member[accessors[0]];
10292
10293 for (var i = 1; i < accessors.length; i++) {
10294 if (candidate) {
10295 candidate = candidate[accessors[i]];
10296 }
10297 }
10298
10299 if (typeof candidate !== "undefined") {
10300 break;
10301 }
10302 }
10303 }
10304 } catch (err) {
10305 _didIteratorError = true;
10306 _iteratorError = err;
10307 } finally {
10308 try {
10309 if (!_iteratorNormalCompletion && _iterator.return != null) {
10310 _iterator.return();
10311 }
10312 } finally {
10313 if (_didIteratorError) {
10314 throw _iteratorError;
10315 }
10316 }
10317 }
10318
10319 return candidate;
10320 }
10321
10322 var util =
10323 /*#__PURE__*/
10324 Object.freeze({
10325 isNumber: isNumber,
10326 recursiveDOMDelete: recursiveDOMDelete,
10327 isString: isString,
10328 isObject: isObject$1,
10329 isDate: isDate,
10330 isMoment: isMoment,
10331 fillIfDefined: fillIfDefined,
10332 extend: extend,
10333 selectiveExtend: selectiveExtend,
10334 selectiveDeepExtend: selectiveDeepExtend,
10335 selectiveNotDeepExtend: selectiveNotDeepExtend,
10336 deepExtend: deepExtend,
10337 equalArray: equalArray,
10338 convert: convert,
10339 getType: getType,
10340 copyAndExtendArray: copyAndExtendArray,
10341 copyArray: copyArray,
10342 getAbsoluteLeft: getAbsoluteLeft,
10343 getAbsoluteRight: getAbsoluteRight,
10344 getAbsoluteTop: getAbsoluteTop,
10345 addClassName: addClassName,
10346 removeClassName: removeClassName,
10347 forEach: forEach,
10348 toArray: toArray,
10349 updateProperty: updateProperty,
10350 throttle: throttle,
10351 addEventListener: addEventListener,
10352 removeEventListener: removeEventListener,
10353 preventDefault: preventDefault,
10354 getTarget: getTarget,
10355 hasParent: hasParent,
10356 option: option,
10357 hexToRGB: hexToRGB,
10358 overrideOpacity: overrideOpacity,
10359 RGBToHex: RGBToHex,
10360 parseColor: parseColor,
10361 RGBToHSV: RGBToHSV,
10362 addCssText: addCssText,
10363 removeCssText: removeCssText,
10364 HSVToRGB: HSVToRGB,
10365 HSVToHex: HSVToHex,
10366 hexToHSV: hexToHSV,
10367 isValidHex: isValidHex,
10368 isValidRGB: isValidRGB,
10369 isValidRGBA: isValidRGBA,
10370 selectiveBridgeObject: selectiveBridgeObject,
10371 bridgeObject: bridgeObject,
10372 insertSort: insertSort,
10373 mergeOptions: mergeOptions,
10374 binarySearchCustom: binarySearchCustom,
10375 binarySearchValue: binarySearchValue,
10376 easingFunctions: easingFunctions,
10377 getScrollBarWidth: getScrollBarWidth,
10378 topMost: topMost,
10379 randomUUID: uuid4
10380 }); // New API (tree shakeable).
10381
10382 var esm = /*#__PURE__*/Object.freeze({
10383 __proto__: null,
10384 'default': util,
10385 HSVToHex: HSVToHex,
10386 HSVToRGB: HSVToRGB,
10387 RGBToHSV: RGBToHSV,
10388 RGBToHex: RGBToHex,
10389 addClassName: addClassName,
10390 addCssText: addCssText,
10391 addEventListener: addEventListener,
10392 binarySearchCustom: binarySearchCustom,
10393 binarySearchValue: binarySearchValue,
10394 bridgeObject: bridgeObject,
10395 convert: convert,
10396 copyAndExtendArray: copyAndExtendArray,
10397 copyArray: copyArray,
10398 deepExtend: deepExtend,
10399 easingFunctions: easingFunctions,
10400 equalArray: equalArray,
10401 extend: extend,
10402 fillIfDefined: fillIfDefined,
10403 forEach: forEach,
10404 getAbsoluteLeft: getAbsoluteLeft,
10405 getAbsoluteRight: getAbsoluteRight,
10406 getAbsoluteTop: getAbsoluteTop,
10407 getScrollBarWidth: getScrollBarWidth,
10408 getTarget: getTarget,
10409 getType: getType,
10410 hasParent: hasParent,
10411 hexToHSV: hexToHSV,
10412 hexToRGB: hexToRGB,
10413 insertSort: insertSort,
10414 isDate: isDate,
10415 isMoment: isMoment,
10416 isNumber: isNumber,
10417 isObject: isObject$1,
10418 isString: isString,
10419 isValidHex: isValidHex,
10420 isValidRGB: isValidRGB,
10421 isValidRGBA: isValidRGBA,
10422 mergeOptions: mergeOptions,
10423 option: option,
10424 overrideOpacity: overrideOpacity,
10425 parseColor: parseColor,
10426 preventDefault: preventDefault,
10427 randomUUID: uuid4,
10428 recursiveDOMDelete: recursiveDOMDelete,
10429 removeClassName: removeClassName,
10430 removeCssText: removeCssText,
10431 removeEventListener: removeEventListener,
10432 selectiveBridgeObject: selectiveBridgeObject,
10433 selectiveDeepExtend: selectiveDeepExtend,
10434 selectiveExtend: selectiveExtend,
10435 selectiveNotDeepExtend: selectiveNotDeepExtend,
10436 throttle: throttle,
10437 toArray: toArray,
10438 topMost: topMost,
10439 updateProperty: updateProperty
10440 });
10441
10442 var bindContext = function (fn, that, length) {
10443 aFunction$1(fn);
10444 if (that === undefined) return fn;
10445
10446 switch (length) {
10447 case 0:
10448 return function () {
10449 return fn.call(that);
10450 };
10451
10452 case 1:
10453 return function (a) {
10454 return fn.call(that, a);
10455 };
10456
10457 case 2:
10458 return function (a, b) {
10459 return fn.call(that, a, b);
10460 };
10461
10462 case 3:
10463 return function (a, b, c) {
10464 return fn.call(that, a, b, c);
10465 };
10466 }
10467
10468 return function ()
10469 /* ...args */
10470 {
10471 return fn.apply(that, arguments);
10472 };
10473 };
10474
10475 // https://tc39.github.io/ecma262/#sec-isarray
10476
10477 var isArray = Array.isArray || function isArray(arg) {
10478 return classofRaw(arg) == 'Array';
10479 };
10480
10481 var SPECIES$2 = wellKnownSymbol('species'); // `ArraySpeciesCreate` abstract operation
10482 // https://tc39.github.io/ecma262/#sec-arrayspeciescreate
10483
10484 var arraySpeciesCreate = function (originalArray, length) {
10485 var C;
10486
10487 if (isArray(originalArray)) {
10488 C = originalArray.constructor; // cross-realm fallback
10489
10490 if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;else if (isObject(C)) {
10491 C = C[SPECIES$2];
10492 if (C === null) C = undefined;
10493 }
10494 }
10495
10496 return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
10497 };
10498
10499 var push = [].push; // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex }` methods implementation
10500
10501 var createMethod$1 = function (TYPE) {
10502 var IS_MAP = TYPE == 1;
10503 var IS_FILTER = TYPE == 2;
10504 var IS_SOME = TYPE == 3;
10505 var IS_EVERY = TYPE == 4;
10506 var IS_FIND_INDEX = TYPE == 6;
10507 var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
10508 return function ($this, callbackfn, that, specificCreate) {
10509 var O = toObject($this);
10510 var self = indexedObject(O);
10511 var boundFunction = bindContext(callbackfn, that, 3);
10512 var length = toLength(self.length);
10513 var index = 0;
10514 var create = specificCreate || arraySpeciesCreate;
10515 var target = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined;
10516 var value, result;
10517
10518 for (; length > index; index++) if (NO_HOLES || index in self) {
10519 value = self[index];
10520 result = boundFunction(value, index, O);
10521
10522 if (TYPE) {
10523 if (IS_MAP) target[index] = result; // map
10524 else if (result) switch (TYPE) {
10525 case 3:
10526 return true;
10527 // some
10528
10529 case 5:
10530 return value;
10531 // find
10532
10533 case 6:
10534 return index;
10535 // findIndex
10536
10537 case 2:
10538 push.call(target, value);
10539 // filter
10540 } else if (IS_EVERY) return false; // every
10541 }
10542 }
10543
10544 return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
10545 };
10546 };
10547
10548 var arrayIteration = {
10549 // `Array.prototype.forEach` method
10550 // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
10551 forEach: createMethod$1(0),
10552 // `Array.prototype.map` method
10553 // https://tc39.github.io/ecma262/#sec-array.prototype.map
10554 map: createMethod$1(1),
10555 // `Array.prototype.filter` method
10556 // https://tc39.github.io/ecma262/#sec-array.prototype.filter
10557 filter: createMethod$1(2),
10558 // `Array.prototype.some` method
10559 // https://tc39.github.io/ecma262/#sec-array.prototype.some
10560 some: createMethod$1(3),
10561 // `Array.prototype.every` method
10562 // https://tc39.github.io/ecma262/#sec-array.prototype.every
10563 every: createMethod$1(4),
10564 // `Array.prototype.find` method
10565 // https://tc39.github.io/ecma262/#sec-array.prototype.find
10566 find: createMethod$1(5),
10567 // `Array.prototype.findIndex` method
10568 // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
10569 findIndex: createMethod$1(6)
10570 };
10571
10572 var sloppyArrayMethod = function (METHOD_NAME, argument) {
10573 var method = [][METHOD_NAME];
10574 return !method || !fails(function () {
10575 // eslint-disable-next-line no-useless-call,no-throw-literal
10576 method.call(null, argument || function () {
10577 throw 1;
10578 }, 1);
10579 });
10580 };
10581
10582 var $forEach = arrayIteration.forEach; // `Array.prototype.forEach` method implementation
10583 // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
10584
10585 var arrayForEach = sloppyArrayMethod('forEach') ? function forEach(callbackfn
10586 /* , thisArg */
10587 ) {
10588 return $forEach(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
10589 } : [].forEach;
10590
10591 // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
10592
10593
10594 _export({
10595 target: 'Array',
10596 proto: true,
10597 forced: [].forEach != arrayForEach
10598 }, {
10599 forEach: arrayForEach
10600 });
10601
10602 // https://tc39.github.io/ecma262/#sec-object.keys
10603
10604 var objectKeys = Object.keys || function keys(O) {
10605 return objectKeysInternal(O, enumBugKeys);
10606 };
10607
10608 // https://tc39.github.io/ecma262/#sec-object.defineproperties
10609
10610 var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
10611 anObject(O);
10612 var keys = objectKeys(Properties);
10613 var length = keys.length;
10614 var index = 0;
10615 var key;
10616
10617 while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);
10618
10619 return O;
10620 };
10621
10622 var html = getBuiltIn('document', 'documentElement');
10623
10624 var IE_PROTO$3 = sharedKey('IE_PROTO');
10625 var PROTOTYPE$3 = 'prototype';
10626
10627 var Empty$1 = function () {
10628 /* empty */
10629 }; // Create object with fake `null` prototype: use iframe Object with cleared prototype
10630
10631
10632 var createDict$1 = function () {
10633 // Thrash, waste and sodomy: IE GC bug
10634 var iframe = documentCreateElement('iframe');
10635 var length = enumBugKeys.length;
10636 var lt = '<';
10637 var script = 'script';
10638 var gt = '>';
10639 var js = 'java' + script + ':';
10640 var iframeDocument;
10641 iframe.style.display = 'none';
10642 html.appendChild(iframe);
10643 iframe.src = String(js);
10644 iframeDocument = iframe.contentWindow.document;
10645 iframeDocument.open();
10646 iframeDocument.write(lt + script + gt + 'document.F=Object' + lt + '/' + script + gt);
10647 iframeDocument.close();
10648 createDict$1 = iframeDocument.F;
10649
10650 while (length--) delete createDict$1[PROTOTYPE$3][enumBugKeys[length]];
10651
10652 return createDict$1();
10653 }; // `Object.create` method
10654 // https://tc39.github.io/ecma262/#sec-object.create
10655
10656
10657 var objectCreate = Object.create || function create(O, Properties) {
10658 var result;
10659
10660 if (O !== null) {
10661 Empty$1[PROTOTYPE$3] = anObject(O);
10662 result = new Empty$1();
10663 Empty$1[PROTOTYPE$3] = null; // add "__proto__" for Object.getPrototypeOf polyfill
10664
10665 result[IE_PROTO$3] = O;
10666 } else result = createDict$1();
10667
10668 return Properties === undefined ? result : objectDefineProperties(result, Properties);
10669 };
10670
10671 hiddenKeys[IE_PROTO$3] = true;
10672
10673 var UNSCOPABLES$1 = wellKnownSymbol('unscopables');
10674 var ArrayPrototype = Array.prototype; // Array.prototype[@@unscopables]
10675 // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
10676
10677 if (ArrayPrototype[UNSCOPABLES$1] == undefined) {
10678 createNonEnumerableProperty(ArrayPrototype, UNSCOPABLES$1, objectCreate(null));
10679 } // add a key to Array.prototype[@@unscopables]
10680
10681
10682 var addToUnscopables = function (key) {
10683 ArrayPrototype[UNSCOPABLES$1][key] = true;
10684 };
10685
10686 var $includes = arrayIncludes.includes; // `Array.prototype.includes` method
10687 // https://tc39.github.io/ecma262/#sec-array.prototype.includes
10688
10689 _export({
10690 target: 'Array',
10691 proto: true
10692 }, {
10693 includes: function includes(el
10694 /* , fromIndex = 0 */
10695 ) {
10696 return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
10697 }
10698 }); // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
10699
10700 addToUnscopables('includes');
10701
10702 var $indexOf = arrayIncludes.indexOf;
10703 var nativeIndexOf = [].indexOf;
10704 var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
10705 var SLOPPY_METHOD = sloppyArrayMethod('indexOf'); // `Array.prototype.indexOf` method
10706 // https://tc39.github.io/ecma262/#sec-array.prototype.indexof
10707
10708 _export({
10709 target: 'Array',
10710 proto: true,
10711 forced: NEGATIVE_ZERO || SLOPPY_METHOD
10712 }, {
10713 indexOf: function indexOf(searchElement
10714 /* , fromIndex = 0 */
10715 ) {
10716 return NEGATIVE_ZERO // convert -0 to +0
10717 ? nativeIndexOf.apply(this, arguments) || 0 : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
10718 }
10719 });
10720
10721 var createProperty = function (object, key, value) {
10722 var propertyKey = toPrimitive(key);
10723 if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));else object[propertyKey] = value;
10724 };
10725
10726 var userAgent = getBuiltIn('navigator', 'userAgent') || '';
10727
10728 var process = global_1.process;
10729 var versions = process && process.versions;
10730 var v8 = versions && versions.v8;
10731 var match, version;
10732
10733 if (v8) {
10734 match = v8.split('.');
10735 version = match[0] + match[1];
10736 } else if (userAgent) {
10737 match = userAgent.match(/Chrome\/(\d+)/);
10738 if (match) version = match[1];
10739 }
10740
10741 var v8Version = version && +version;
10742
10743 var SPECIES$3 = wellKnownSymbol('species');
10744
10745 var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
10746 // We can't use this feature detection in V8 since it causes
10747 // deoptimization and serious performance degradation
10748 // https://github.com/zloirock/core-js/issues/677
10749 return v8Version >= 51 || !fails(function () {
10750 var array = [];
10751 var constructor = array.constructor = {};
10752
10753 constructor[SPECIES$3] = function () {
10754 return {
10755 foo: 1
10756 };
10757 };
10758
10759 return array[METHOD_NAME](Boolean).foo !== 1;
10760 });
10761 };
10762
10763 var max$2 = Math.max;
10764 var min$3 = Math.min;
10765 var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
10766 var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded'; // `Array.prototype.splice` method
10767 // https://tc39.github.io/ecma262/#sec-array.prototype.splice
10768 // with adding support of @@species
10769
10770 _export({
10771 target: 'Array',
10772 proto: true,
10773 forced: !arrayMethodHasSpeciesSupport('splice')
10774 }, {
10775 splice: function splice(start, deleteCount
10776 /* , ...items */
10777 ) {
10778 var O = toObject(this);
10779 var len = toLength(O.length);
10780 var actualStart = toAbsoluteIndex(start, len);
10781 var argumentsLength = arguments.length;
10782 var insertCount, actualDeleteCount, A, k, from, to;
10783
10784 if (argumentsLength === 0) {
10785 insertCount = actualDeleteCount = 0;
10786 } else if (argumentsLength === 1) {
10787 insertCount = 0;
10788 actualDeleteCount = len - actualStart;
10789 } else {
10790 insertCount = argumentsLength - 2;
10791 actualDeleteCount = min$3(max$2(toInteger(deleteCount), 0), len - actualStart);
10792 }
10793
10794 if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER) {
10795 throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
10796 }
10797
10798 A = arraySpeciesCreate(O, actualDeleteCount);
10799
10800 for (k = 0; k < actualDeleteCount; k++) {
10801 from = actualStart + k;
10802 if (from in O) createProperty(A, k, O[from]);
10803 }
10804
10805 A.length = actualDeleteCount;
10806
10807 if (insertCount < actualDeleteCount) {
10808 for (k = actualStart; k < len - actualDeleteCount; k++) {
10809 from = k + actualDeleteCount;
10810 to = k + insertCount;
10811 if (from in O) O[to] = O[from];else delete O[to];
10812 }
10813
10814 for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
10815 } else if (insertCount > actualDeleteCount) {
10816 for (k = len - actualDeleteCount; k > actualStart; k--) {
10817 from = k + actualDeleteCount - 1;
10818 to = k + insertCount - 1;
10819 if (from in O) O[to] = O[from];else delete O[to];
10820 }
10821 }
10822
10823 for (k = 0; k < insertCount; k++) {
10824 O[k + actualStart] = arguments[k + 2];
10825 }
10826
10827 O.length = len - actualDeleteCount + insertCount;
10828 return A;
10829 }
10830 });
10831
10832 var defineProperty$4 = objectDefineProperty.f;
10833 var FunctionPrototype = Function.prototype;
10834 var FunctionPrototypeToString = FunctionPrototype.toString;
10835 var nameRE = /^\s*function ([^ (]*)/;
10836 var NAME$2 = 'name'; // Function instances `.name` property
10837 // https://tc39.github.io/ecma262/#sec-function-instances-name
10838
10839 if (descriptors && !(NAME$2 in FunctionPrototype)) {
10840 defineProperty$4(FunctionPrototype, NAME$2, {
10841 configurable: true,
10842 get: function () {
10843 try {
10844 return FunctionPrototypeToString.call(this).match(nameRE)[1];
10845 } catch (error) {
10846 return '';
10847 }
10848 }
10849 });
10850 }
10851
10852 var inheritIfRequired = function ($this, dummy, Wrapper) {
10853 var NewTarget, NewTargetPrototype;
10854 if ( // it can work only with native `setPrototypeOf`
10855 objectSetPrototypeOf && // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
10856 typeof (NewTarget = dummy.constructor) == 'function' && NewTarget !== Wrapper && isObject(NewTargetPrototype = NewTarget.prototype) && NewTargetPrototype !== Wrapper.prototype) objectSetPrototypeOf($this, NewTargetPrototype);
10857 return $this;
10858 };
10859
10860 // a string of all valid unicode whitespaces
10861 // eslint-disable-next-line max-len
10862 var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
10863
10864 var whitespace = '[' + whitespaces + ']';
10865 var ltrim$1 = RegExp('^' + whitespace + whitespace + '*');
10866 var rtrim$1 = RegExp(whitespace + whitespace + '*$'); // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
10867
10868 var createMethod$2 = function (TYPE) {
10869 return function ($this) {
10870 var string = String(requireObjectCoercible($this));
10871 if (TYPE & 1) string = string.replace(ltrim$1, '');
10872 if (TYPE & 2) string = string.replace(rtrim$1, '');
10873 return string;
10874 };
10875 };
10876
10877 var stringTrim = {
10878 // `String.prototype.{ trimLeft, trimStart }` methods
10879 // https://tc39.github.io/ecma262/#sec-string.prototype.trimstart
10880 start: createMethod$2(1),
10881 // `String.prototype.{ trimRight, trimEnd }` methods
10882 // https://tc39.github.io/ecma262/#sec-string.prototype.trimend
10883 end: createMethod$2(2),
10884 // `String.prototype.trim` method
10885 // https://tc39.github.io/ecma262/#sec-string.prototype.trim
10886 trim: createMethod$2(3)
10887 };
10888
10889 var getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
10890 var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
10891 var defineProperty$5 = objectDefineProperty.f;
10892 var trim$1 = stringTrim.trim;
10893 var NUMBER$1 = 'Number';
10894 var NativeNumber = global_1[NUMBER$1];
10895 var NumberPrototype = NativeNumber.prototype; // Opera ~12 has broken Object#toString
10896
10897 var BROKEN_CLASSOF = classofRaw(objectCreate(NumberPrototype)) == NUMBER$1; // `ToNumber` abstract operation
10898 // https://tc39.github.io/ecma262/#sec-tonumber
10899
10900 var toNumber$1 = function (argument) {
10901 var it = toPrimitive(argument, false);
10902 var first, third, radix, maxCode, digits, length, index, code;
10903
10904 if (typeof it == 'string' && it.length > 2) {
10905 it = trim$1(it);
10906 first = it.charCodeAt(0);
10907
10908 if (first === 43 || first === 45) {
10909 third = it.charCodeAt(2);
10910 if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
10911 } else if (first === 48) {
10912 switch (it.charCodeAt(1)) {
10913 case 66:
10914 case 98:
10915 radix = 2;
10916 maxCode = 49;
10917 break;
10918 // fast equal of /^0b[01]+$/i
10919
10920 case 79:
10921 case 111:
10922 radix = 8;
10923 maxCode = 55;
10924 break;
10925 // fast equal of /^0o[0-7]+$/i
10926
10927 default:
10928 return +it;
10929 }
10930
10931 digits = it.slice(2);
10932 length = digits.length;
10933
10934 for (index = 0; index < length; index++) {
10935 code = digits.charCodeAt(index); // parseInt parses a string to a first unavailable symbol
10936 // but ToNumber should return NaN if a string contains unavailable symbols
10937
10938 if (code < 48 || code > maxCode) return NaN;
10939 }
10940
10941 return parseInt(digits, radix);
10942 }
10943 }
10944
10945 return +it;
10946 }; // `Number` constructor
10947 // https://tc39.github.io/ecma262/#sec-number-constructor
10948
10949
10950 if (isForced_1(NUMBER$1, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
10951 var NumberWrapper = function Number(value) {
10952 var it = arguments.length < 1 ? 0 : value;
10953 var dummy = this;
10954 return dummy instanceof NumberWrapper // check on 1..constructor(foo) case
10955 && (BROKEN_CLASSOF ? fails(function () {
10956 NumberPrototype.valueOf.call(dummy);
10957 }) : classofRaw(dummy) != NUMBER$1) ? inheritIfRequired(new NativeNumber(toNumber$1(it)), dummy, NumberWrapper) : toNumber$1(it);
10958 };
10959
10960 for (var keys$3 = descriptors ? getOwnPropertyNames$1(NativeNumber) : ( // ES3:
10961 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' + // ES2015 (in case, if modules with ES2015 Number statics required before):
10962 'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' + 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger').split(','), j$2 = 0, key$2; keys$3.length > j$2; j$2++) {
10963 if (has(NativeNumber, key$2 = keys$3[j$2]) && !has(NumberWrapper, key$2)) {
10964 defineProperty$5(NumberWrapper, key$2, getOwnPropertyDescriptor$2(NativeNumber, key$2));
10965 }
10966 }
10967
10968 NumberWrapper.prototype = NumberPrototype;
10969 NumberPrototype.constructor = NumberWrapper;
10970 redefine(global_1, NUMBER$1, NumberWrapper);
10971 }
10972
10973 // https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags
10974
10975
10976 var regexpFlags = function () {
10977 var that = anObject(this);
10978 var result = '';
10979 if (that.global) result += 'g';
10980 if (that.ignoreCase) result += 'i';
10981 if (that.multiline) result += 'm';
10982 if (that.dotAll) result += 's';
10983 if (that.unicode) result += 'u';
10984 if (that.sticky) result += 'y';
10985 return result;
10986 };
10987
10988 var nativeExec$1 = RegExp.prototype.exec; // This always refers to the native implementation, because the
10989 // String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js,
10990 // which loads this file before patching the method.
10991
10992 var nativeReplace$1 = String.prototype.replace;
10993 var patchedExec$1 = nativeExec$1;
10994
10995 var UPDATES_LAST_INDEX_WRONG$1 = function () {
10996 var re1 = /a/;
10997 var re2 = /b*/g;
10998 nativeExec$1.call(re1, 'a');
10999 nativeExec$1.call(re2, 'a');
11000 return re1.lastIndex !== 0 || re2.lastIndex !== 0;
11001 }(); // nonparticipating capturing group, copied from es5-shim's String#split patch.
11002
11003
11004 var NPCG_INCLUDED$1 = /()??/.exec('')[1] !== undefined;
11005 var PATCH$1 = UPDATES_LAST_INDEX_WRONG$1 || NPCG_INCLUDED$1;
11006
11007 if (PATCH$1) {
11008 patchedExec$1 = function exec(str) {
11009 var re = this;
11010 var lastIndex, reCopy, match, i;
11011
11012 if (NPCG_INCLUDED$1) {
11013 reCopy = new RegExp('^' + re.source + '$(?!\\s)', regexpFlags.call(re));
11014 }
11015
11016 if (UPDATES_LAST_INDEX_WRONG$1) lastIndex = re.lastIndex;
11017 match = nativeExec$1.call(re, str);
11018
11019 if (UPDATES_LAST_INDEX_WRONG$1 && match) {
11020 re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
11021 }
11022
11023 if (NPCG_INCLUDED$1 && match && match.length > 1) {
11024 // Fix browsers whose `exec` methods don't consistently return `undefined`
11025 // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
11026 nativeReplace$1.call(match[0], reCopy, function () {
11027 for (i = 1; i < arguments.length - 2; i++) {
11028 if (arguments[i] === undefined) match[i] = undefined;
11029 }
11030 });
11031 }
11032
11033 return match;
11034 };
11035 }
11036
11037 var regexpExec = patchedExec$1;
11038
11039 _export({
11040 target: 'RegExp',
11041 proto: true,
11042 forced: /./.exec !== regexpExec
11043 }, {
11044 exec: regexpExec
11045 });
11046
11047 var MATCH$1 = wellKnownSymbol('match'); // `IsRegExp` abstract operation
11048 // https://tc39.github.io/ecma262/#sec-isregexp
11049
11050 var isRegexp = function (it) {
11051 var isRegExp;
11052 return isObject(it) && ((isRegExp = it[MATCH$1]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
11053 };
11054
11055 var notARegexp = function (it) {
11056 if (isRegexp(it)) {
11057 throw TypeError("The method doesn't accept regular expressions");
11058 }
11059
11060 return it;
11061 };
11062
11063 var MATCH$2 = wellKnownSymbol('match');
11064
11065 var correctIsRegexpLogic = function (METHOD_NAME) {
11066 var regexp = /./;
11067
11068 try {
11069 '/./'[METHOD_NAME](regexp);
11070 } catch (e) {
11071 try {
11072 regexp[MATCH$2] = false;
11073 return '/./'[METHOD_NAME](regexp);
11074 } catch (f) {
11075 /* empty */
11076 }
11077 }
11078
11079 return false;
11080 };
11081
11082 // https://tc39.github.io/ecma262/#sec-string.prototype.includes
11083
11084
11085 _export({
11086 target: 'String',
11087 proto: true,
11088 forced: !correctIsRegexpLogic('includes')
11089 }, {
11090 includes: function includes(searchString
11091 /* , position = 0 */
11092 ) {
11093 return !!~String(requireObjectCoercible(this)).indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined);
11094 }
11095 });
11096
11097 var SPECIES$4 = wellKnownSymbol('species');
11098 var REPLACE_SUPPORTS_NAMED_GROUPS$1 = !fails(function () {
11099 // #replace needs built-in support for named groups.
11100 // #match works fine because it just return the exec results, even if it has
11101 // a "grops" property.
11102 var re = /./;
11103
11104 re.exec = function () {
11105 var result = [];
11106 result.groups = {
11107 a: '7'
11108 };
11109 return result;
11110 };
11111
11112 return ''.replace(re, '$<a>') !== '7';
11113 }); // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
11114 // Weex JS has frozen built-in prototypes, so use try / catch wrapper
11115
11116 var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC$1 = !fails(function () {
11117 var re = /(?:)/;
11118 var originalExec = re.exec;
11119
11120 re.exec = function () {
11121 return originalExec.apply(this, arguments);
11122 };
11123
11124 var result = 'ab'.split(re);
11125 return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
11126 });
11127
11128 var fixRegexpWellKnownSymbolLogic = function (KEY, length, exec, sham) {
11129 var SYMBOL = wellKnownSymbol(KEY);
11130 var DELEGATES_TO_SYMBOL = !fails(function () {
11131 // String methods call symbol-named RegEp methods
11132 var O = {};
11133
11134 O[SYMBOL] = function () {
11135 return 7;
11136 };
11137
11138 return ''[KEY](O) != 7;
11139 });
11140 var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
11141 // Symbol-named RegExp methods call .exec
11142 var execCalled = false;
11143 var re = /a/;
11144
11145 if (KEY === 'split') {
11146 // We can't use real regex here since it causes deoptimization
11147 // and serious performance degradation in V8
11148 // https://github.com/zloirock/core-js/issues/306
11149 re = {}; // RegExp[@@split] doesn't call the regex's exec method, but first creates
11150 // a new one. We need to return the patched regex when creating the new one.
11151
11152 re.constructor = {};
11153
11154 re.constructor[SPECIES$4] = function () {
11155 return re;
11156 };
11157
11158 re.flags = '';
11159 re[SYMBOL] = /./[SYMBOL];
11160 }
11161
11162 re.exec = function () {
11163 execCalled = true;
11164 return null;
11165 };
11166
11167 re[SYMBOL]('');
11168 return !execCalled;
11169 });
11170
11171 if (!DELEGATES_TO_SYMBOL || !DELEGATES_TO_EXEC || KEY === 'replace' && !REPLACE_SUPPORTS_NAMED_GROUPS$1 || KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC$1) {
11172 var nativeRegExpMethod = /./[SYMBOL];
11173 var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
11174 if (regexp.exec === regexpExec) {
11175 if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
11176 // The native String method already delegates to @@method (this
11177 // polyfilled function), leasing to infinite recursion.
11178 // We avoid it by directly calling the native @@method method.
11179 return {
11180 done: true,
11181 value: nativeRegExpMethod.call(regexp, str, arg2)
11182 };
11183 }
11184
11185 return {
11186 done: true,
11187 value: nativeMethod.call(str, regexp, arg2)
11188 };
11189 }
11190
11191 return {
11192 done: false
11193 };
11194 });
11195 var stringMethod = methods[0];
11196 var regexMethod = methods[1];
11197 redefine(String.prototype, KEY, stringMethod);
11198 redefine(RegExp.prototype, SYMBOL, length == 2 // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
11199 // 21.2.5.11 RegExp.prototype[@@split](string, limit)
11200 ? function (string, arg) {
11201 return regexMethod.call(string, this, arg);
11202 } // 21.2.5.6 RegExp.prototype[@@match](string)
11203 // 21.2.5.9 RegExp.prototype[@@search](string)
11204 : function (string) {
11205 return regexMethod.call(string, this);
11206 });
11207 if (sham) createNonEnumerableProperty(RegExp.prototype[SYMBOL], 'sham', true);
11208 }
11209 };
11210
11211 var createMethod$3 = function (CONVERT_TO_STRING) {
11212 return function ($this, pos) {
11213 var S = String(requireObjectCoercible($this));
11214 var position = toInteger(pos);
11215 var size = S.length;
11216 var first, second;
11217 if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
11218 first = S.charCodeAt(position);
11219 return first < 0xD800 || first > 0xDBFF || position + 1 === size || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF ? CONVERT_TO_STRING ? S.charAt(position) : first : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
11220 };
11221 };
11222
11223 var stringMultibyte = {
11224 // `String.prototype.codePointAt` method
11225 // https://tc39.github.io/ecma262/#sec-string.prototype.codepointat
11226 codeAt: createMethod$3(false),
11227 // `String.prototype.at` method
11228 // https://github.com/mathiasbynens/String.prototype.at
11229 charAt: createMethod$3(true)
11230 };
11231
11232 var charAt = stringMultibyte.charAt; // `AdvanceStringIndex` abstract operation
11233 // https://tc39.github.io/ecma262/#sec-advancestringindex
11234
11235 var advanceStringIndex = function (S, index, unicode) {
11236 return index + (unicode ? charAt(S, index).length : 1);
11237 };
11238
11239 // https://tc39.github.io/ecma262/#sec-regexpexec
11240
11241 var regexpExecAbstract = function (R, S) {
11242 var exec = R.exec;
11243
11244 if (typeof exec === 'function') {
11245 var result = exec.call(R, S);
11246
11247 if (typeof result !== 'object') {
11248 throw TypeError('RegExp exec method returned something other than an Object or null');
11249 }
11250
11251 return result;
11252 }
11253
11254 if (classofRaw(R) !== 'RegExp') {
11255 throw TypeError('RegExp#exec called on incompatible receiver');
11256 }
11257
11258 return regexpExec.call(R, S);
11259 };
11260
11261 var arrayPush = [].push;
11262 var min$4 = Math.min;
11263 var MAX_UINT32$1 = 0xFFFFFFFF; // babel-minify transpiles RegExp('x', 'y') -> /x/y and it causes SyntaxError
11264
11265 var SUPPORTS_Y$1 = !fails(function () {
11266 return !RegExp(MAX_UINT32$1, 'y');
11267 }); // @@split logic
11268
11269 fixRegexpWellKnownSymbolLogic('split', 2, function (SPLIT, nativeSplit, maybeCallNative) {
11270 var internalSplit;
11271
11272 if ('abbc'.split(/(b)*/)[1] == 'c' || 'test'.split(/(?:)/, -1).length != 4 || 'ab'.split(/(?:ab)*/).length != 2 || '.'.split(/(.?)(.?)/).length != 4 || '.'.split(/()()/).length > 1 || ''.split(/.?/).length) {
11273 // based on es5-shim implementation, need to rework it
11274 internalSplit = function (separator, limit) {
11275 var string = String(requireObjectCoercible(this));
11276 var lim = limit === undefined ? MAX_UINT32$1 : limit >>> 0;
11277 if (lim === 0) return [];
11278 if (separator === undefined) return [string]; // If `separator` is not a regex, use native split
11279
11280 if (!isRegexp(separator)) {
11281 return nativeSplit.call(string, separator, lim);
11282 }
11283
11284 var output = [];
11285 var flags = (separator.ignoreCase ? 'i' : '') + (separator.multiline ? 'm' : '') + (separator.unicode ? 'u' : '') + (separator.sticky ? 'y' : '');
11286 var lastLastIndex = 0; // Make `global` and avoid `lastIndex` issues by working with a copy
11287
11288 var separatorCopy = new RegExp(separator.source, flags + 'g');
11289 var match, lastIndex, lastLength;
11290
11291 while (match = regexpExec.call(separatorCopy, string)) {
11292 lastIndex = separatorCopy.lastIndex;
11293
11294 if (lastIndex > lastLastIndex) {
11295 output.push(string.slice(lastLastIndex, match.index));
11296 if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
11297 lastLength = match[0].length;
11298 lastLastIndex = lastIndex;
11299 if (output.length >= lim) break;
11300 }
11301
11302 if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
11303 }
11304
11305 if (lastLastIndex === string.length) {
11306 if (lastLength || !separatorCopy.test('')) output.push('');
11307 } else output.push(string.slice(lastLastIndex));
11308
11309 return output.length > lim ? output.slice(0, lim) : output;
11310 }; // Chakra, V8
11311
11312 } else if ('0'.split(undefined, 0).length) {
11313 internalSplit = function (separator, limit) {
11314 return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
11315 };
11316 } else internalSplit = nativeSplit;
11317
11318 return [// `String.prototype.split` method
11319 // https://tc39.github.io/ecma262/#sec-string.prototype.split
11320 function split(separator, limit) {
11321 var O = requireObjectCoercible(this);
11322 var splitter = separator == undefined ? undefined : separator[SPLIT];
11323 return splitter !== undefined ? splitter.call(separator, O, limit) : internalSplit.call(String(O), separator, limit);
11324 }, // `RegExp.prototype[@@split]` method
11325 // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@split
11326 //
11327 // NOTE: This cannot be properly polyfilled in engines that don't support
11328 // the 'y' flag.
11329 function (regexp, limit) {
11330 var res = maybeCallNative(internalSplit, regexp, this, limit, internalSplit !== nativeSplit);
11331 if (res.done) return res.value;
11332 var rx = anObject(regexp);
11333 var S = String(this);
11334 var C = speciesConstructor(rx, RegExp);
11335 var unicodeMatching = rx.unicode;
11336 var flags = (rx.ignoreCase ? 'i' : '') + (rx.multiline ? 'm' : '') + (rx.unicode ? 'u' : '') + (SUPPORTS_Y$1 ? 'y' : 'g'); // ^(? + rx + ) is needed, in combination with some S slicing, to
11337 // simulate the 'y' flag.
11338
11339 var splitter = new C(SUPPORTS_Y$1 ? rx : '^(?:' + rx.source + ')', flags);
11340 var lim = limit === undefined ? MAX_UINT32$1 : limit >>> 0;
11341 if (lim === 0) return [];
11342 if (S.length === 0) return regexpExecAbstract(splitter, S) === null ? [S] : [];
11343 var p = 0;
11344 var q = 0;
11345 var A = [];
11346
11347 while (q < S.length) {
11348 splitter.lastIndex = SUPPORTS_Y$1 ? q : 0;
11349 var z = regexpExecAbstract(splitter, SUPPORTS_Y$1 ? S : S.slice(q));
11350 var e;
11351
11352 if (z === null || (e = min$4(toLength(splitter.lastIndex + (SUPPORTS_Y$1 ? 0 : q)), S.length)) === p) {
11353 q = advanceStringIndex(S, q, unicodeMatching);
11354 } else {
11355 A.push(S.slice(p, q));
11356 if (A.length === lim) return A;
11357
11358 for (var i = 1; i <= z.length - 1; i++) {
11359 A.push(z[i]);
11360 if (A.length === lim) return A;
11361 }
11362
11363 q = p = e;
11364 }
11365 }
11366
11367 A.push(S.slice(p));
11368 return A;
11369 }];
11370 }, !SUPPORTS_Y$1);
11371
11372 // iterable DOM collections
11373 // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
11374 var domIterables = {
11375 CSSRuleList: 0,
11376 CSSStyleDeclaration: 0,
11377 CSSValueList: 0,
11378 ClientRectList: 0,
11379 DOMRectList: 0,
11380 DOMStringList: 0,
11381 DOMTokenList: 1,
11382 DataTransferItemList: 0,
11383 FileList: 0,
11384 HTMLAllCollection: 0,
11385 HTMLCollection: 0,
11386 HTMLFormElement: 0,
11387 HTMLSelectElement: 0,
11388 MediaList: 0,
11389 MimeTypeArray: 0,
11390 NamedNodeMap: 0,
11391 NodeList: 1,
11392 PaintRequestList: 0,
11393 Plugin: 0,
11394 PluginArray: 0,
11395 SVGLengthList: 0,
11396 SVGNumberList: 0,
11397 SVGPathSegList: 0,
11398 SVGPointList: 0,
11399 SVGStringList: 0,
11400 SVGTransformList: 0,
11401 SourceBufferList: 0,
11402 StyleSheetList: 0,
11403 TextTrackCueList: 0,
11404 TextTrackList: 0,
11405 TouchList: 0
11406 };
11407
11408 for (var COLLECTION_NAME in domIterables) {
11409 var Collection$1 = global_1[COLLECTION_NAME];
11410 var CollectionPrototype = Collection$1 && Collection$1.prototype; // some Chrome versions have non-configurable methods on DOMTokenList
11411
11412 if (CollectionPrototype && CollectionPrototype.forEach !== arrayForEach) try {
11413 createNonEnumerableProperty(CollectionPrototype, 'forEach', arrayForEach);
11414 } catch (error) {
11415 CollectionPrototype.forEach = arrayForEach;
11416 }
11417 }
11418
11419 /**
11420 * Parse a text source containing data in DOT language into a JSON object.
11421 * The object contains two lists: one with nodes and one with edges.
11422 *
11423 * DOT language reference: http://www.graphviz.org/doc/info/lang.html
11424 *
11425 * DOT language attributes: http://graphviz.org/content/attrs
11426 *
11427 * @param {string} data Text containing a graph in DOT-notation
11428 * @return {Object} graph An object containing two parameters:
11429 * {Object[]} nodes
11430 * {Object[]} edges
11431 *
11432 * -------------------------------------------
11433 * TODO
11434 * ====
11435 *
11436 * For label handling, this is an incomplete implementation. From docs (quote #3015):
11437 *
11438 * > the escape sequences "\n", "\l" and "\r" divide the label into lines, centered,
11439 * > left-justified, and right-justified, respectively.
11440 *
11441 * Source: http://www.graphviz.org/content/attrs#kescString
11442 *
11443 * > As another aid for readability, dot allows double-quoted strings to span multiple physical
11444 * > lines using the standard C convention of a backslash immediately preceding a newline
11445 * > character
11446 * > In addition, double-quoted strings can be concatenated using a '+' operator.
11447 * > As HTML strings can contain newline characters, which are used solely for formatting,
11448 * > the language does not allow escaped newlines or concatenation operators to be used
11449 * > within them.
11450 *
11451 * - Currently, only '\\n' is handled
11452 * - Note that text explicitly says 'labels'; the dot parser currently handles escape
11453 * sequences in **all** strings.
11454 */
11455 function parseDOT(data) {
11456 dot = data;
11457 return parseGraph();
11458 } // mapping of attributes from DOT (the keys) to vis.js (the values)
11459
11460
11461 var NODE_ATTR_MAPPING = {
11462 'fontsize': 'font.size',
11463 'fontcolor': 'font.color',
11464 'labelfontcolor': 'font.color',
11465 'fontname': 'font.face',
11466 'color': ['color.border', 'color.background'],
11467 'fillcolor': 'color.background',
11468 'tooltip': 'title',
11469 'labeltooltip': 'title'
11470 };
11471 var EDGE_ATTR_MAPPING = Object.create(NODE_ATTR_MAPPING);
11472 EDGE_ATTR_MAPPING.color = 'color.color';
11473 EDGE_ATTR_MAPPING.style = 'dashes'; // token types enumeration
11474
11475 var TOKENTYPE = {
11476 NULL: 0,
11477 DELIMITER: 1,
11478 IDENTIFIER: 2,
11479 UNKNOWN: 3
11480 }; // map with all delimiters
11481
11482 var DELIMITERS = {
11483 '{': true,
11484 '}': true,
11485 '[': true,
11486 ']': true,
11487 ';': true,
11488 '=': true,
11489 ',': true,
11490 '->': true,
11491 '--': true
11492 };
11493 var dot = ''; // current dot file
11494
11495 var index = 0; // current index in dot file
11496
11497 var c = ''; // current token character in expr
11498
11499 var token = ''; // current token
11500
11501 var tokenType = TOKENTYPE.NULL; // type of the token
11502
11503 /**
11504 * Get the first character from the dot file.
11505 * The character is stored into the char c. If the end of the dot file is
11506 * reached, the function puts an empty string in c.
11507 */
11508
11509 function first() {
11510 index = 0;
11511 c = dot.charAt(0);
11512 }
11513 /**
11514 * Get the next character from the dot file.
11515 * The character is stored into the char c. If the end of the dot file is
11516 * reached, the function puts an empty string in c.
11517 */
11518
11519
11520 function next() {
11521 index++;
11522 c = dot.charAt(index);
11523 }
11524 /**
11525 * Preview the next character from the dot file.
11526 * @return {string} cNext
11527 */
11528
11529
11530 function nextPreview() {
11531 return dot.charAt(index + 1);
11532 }
11533
11534 var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/;
11535 /**
11536 * Test whether given character is alphabetic or numeric
11537 * @param {string} c
11538 * @return {Boolean} isAlphaNumeric
11539 */
11540
11541 function isAlphaNumeric(c) {
11542 return regexAlphaNumeric.test(c);
11543 }
11544 /**
11545 * Merge all options of object b into object b
11546 * @param {Object} a
11547 * @param {Object} b
11548 * @return {Object} a
11549 */
11550
11551
11552 function merge(a, b) {
11553 if (!a) {
11554 a = {};
11555 }
11556
11557 if (b) {
11558 for (var name in b) {
11559 if (b.hasOwnProperty(name)) {
11560 a[name] = b[name];
11561 }
11562 }
11563 }
11564
11565 return a;
11566 }
11567 /**
11568 * Set a value in an object, where the provided parameter name can be a
11569 * path with nested parameters. For example:
11570 *
11571 * var obj = {a: 2};
11572 * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}}
11573 *
11574 * @param {Object} obj
11575 * @param {string} path A parameter name or dot-separated parameter path,
11576 * like "color.highlight.border".
11577 * @param {*} value
11578 */
11579
11580
11581 function setValue(obj, path, value) {
11582 var keys = path.split('.');
11583 var o = obj;
11584
11585 while (keys.length) {
11586 var key = keys.shift();
11587
11588 if (keys.length) {
11589 // this isn't the end point
11590 if (!o[key]) {
11591 o[key] = {};
11592 }
11593
11594 o = o[key];
11595 } else {
11596 // this is the end point
11597 o[key] = value;
11598 }
11599 }
11600 }
11601 /**
11602 * Add a node to a graph object. If there is already a node with
11603 * the same id, their attributes will be merged.
11604 * @param {Object} graph
11605 * @param {Object} node
11606 */
11607
11608
11609 function addNode(graph, node) {
11610 var i, len;
11611 var current = null; // find root graph (in case of subgraph)
11612
11613 var graphs = [graph]; // list with all graphs from current graph to root graph
11614
11615 var root = graph;
11616
11617 while (root.parent) {
11618 graphs.push(root.parent);
11619 root = root.parent;
11620 } // find existing node (at root level) by its id
11621
11622
11623 if (root.nodes) {
11624 for (i = 0, len = root.nodes.length; i < len; i++) {
11625 if (node.id === root.nodes[i].id) {
11626 current = root.nodes[i];
11627 break;
11628 }
11629 }
11630 }
11631
11632 if (!current) {
11633 // this is a new node
11634 current = {
11635 id: node.id
11636 };
11637
11638 if (graph.node) {
11639 // clone default attributes
11640 current.attr = merge(current.attr, graph.node);
11641 }
11642 } // add node to this (sub)graph and all its parent graphs
11643
11644
11645 for (i = graphs.length - 1; i >= 0; i--) {
11646 var g = graphs[i];
11647
11648 if (!g.nodes) {
11649 g.nodes = [];
11650 }
11651
11652 if (g.nodes.indexOf(current) === -1) {
11653 g.nodes.push(current);
11654 }
11655 } // merge attributes
11656
11657
11658 if (node.attr) {
11659 current.attr = merge(current.attr, node.attr);
11660 }
11661 }
11662 /**
11663 * Add an edge to a graph object
11664 * @param {Object} graph
11665 * @param {Object} edge
11666 */
11667
11668
11669 function addEdge(graph, edge) {
11670 if (!graph.edges) {
11671 graph.edges = [];
11672 }
11673
11674 graph.edges.push(edge);
11675
11676 if (graph.edge) {
11677 var attr = merge({}, graph.edge); // clone default attributes
11678
11679 edge.attr = merge(attr, edge.attr); // merge attributes
11680 }
11681 }
11682 /**
11683 * Create an edge to a graph object
11684 * @param {Object} graph
11685 * @param {string | number | Object} from
11686 * @param {string | number | Object} to
11687 * @param {string} type
11688 * @param {Object | null} attr
11689 * @return {Object} edge
11690 */
11691
11692
11693 function createEdge(graph, from, to, type, attr) {
11694 var edge = {
11695 from: from,
11696 to: to,
11697 type: type
11698 };
11699
11700 if (graph.edge) {
11701 edge.attr = merge({}, graph.edge); // clone default attributes
11702 }
11703
11704 edge.attr = merge(edge.attr || {}, attr); // merge attributes
11705 // Move arrows attribute from attr to edge temporally created in
11706 // parseAttributeList().
11707
11708 if (attr != null) {
11709 if (attr.hasOwnProperty('arrows') && attr['arrows'] != null) {
11710 edge['arrows'] = {
11711 to: {
11712 enabled: true,
11713 type: attr.arrows.type
11714 }
11715 };
11716 attr['arrows'] = null;
11717 }
11718 }
11719
11720 return edge;
11721 }
11722 /**
11723 * Get next token in the current dot file.
11724 * The token and token type are available as token and tokenType
11725 */
11726
11727
11728 function getToken() {
11729 tokenType = TOKENTYPE.NULL;
11730 token = ''; // skip over whitespaces
11731
11732 while (c === ' ' || c === '\t' || c === '\n' || c === '\r') {
11733 // space, tab, enter
11734 next();
11735 }
11736
11737 do {
11738 var isComment = false; // skip comment
11739
11740 if (c === '#') {
11741 // find the previous non-space character
11742 var i = index - 1;
11743
11744 while (dot.charAt(i) === ' ' || dot.charAt(i) === '\t') {
11745 i--;
11746 }
11747
11748 if (dot.charAt(i) === '\n' || dot.charAt(i) === '') {
11749 // the # is at the start of a line, this is indeed a line comment
11750 while (c != '' && c != '\n') {
11751 next();
11752 }
11753
11754 isComment = true;
11755 }
11756 }
11757
11758 if (c === '/' && nextPreview() === '/') {
11759 // skip line comment
11760 while (c != '' && c != '\n') {
11761 next();
11762 }
11763
11764 isComment = true;
11765 }
11766
11767 if (c === '/' && nextPreview() === '*') {
11768 // skip block comment
11769 while (c != '') {
11770 if (c === '*' && nextPreview() === '/') {
11771 // end of block comment found. skip these last two characters
11772 next();
11773 next();
11774 break;
11775 } else {
11776 next();
11777 }
11778 }
11779
11780 isComment = true;
11781 } // skip over whitespaces
11782
11783
11784 while (c === ' ' || c === '\t' || c === '\n' || c === '\r') {
11785 // space, tab, enter
11786 next();
11787 }
11788 } while (isComment); // check for end of dot file
11789
11790
11791 if (c === '') {
11792 // token is still empty
11793 tokenType = TOKENTYPE.DELIMITER;
11794 return;
11795 } // check for delimiters consisting of 2 characters
11796
11797
11798 var c2 = c + nextPreview();
11799
11800 if (DELIMITERS[c2]) {
11801 tokenType = TOKENTYPE.DELIMITER;
11802 token = c2;
11803 next();
11804 next();
11805 return;
11806 } // check for delimiters consisting of 1 character
11807
11808
11809 if (DELIMITERS[c]) {
11810 tokenType = TOKENTYPE.DELIMITER;
11811 token = c;
11812 next();
11813 return;
11814 } // check for an identifier (number or string)
11815 // TODO: more precise parsing of numbers/strings (and the port separator ':')
11816
11817
11818 if (isAlphaNumeric(c) || c === '-') {
11819 token += c;
11820 next();
11821
11822 while (isAlphaNumeric(c)) {
11823 token += c;
11824 next();
11825 }
11826
11827 if (token === 'false') {
11828 token = false; // convert to boolean
11829 } else if (token === 'true') {
11830 token = true; // convert to boolean
11831 } else if (!isNaN(Number(token))) {
11832 token = Number(token); // convert to number
11833 }
11834
11835 tokenType = TOKENTYPE.IDENTIFIER;
11836 return;
11837 } // check for a string enclosed by double quotes
11838
11839
11840 if (c === '"') {
11841 next();
11842
11843 while (c != '' && (c != '"' || c === '"' && nextPreview() === '"')) {
11844 if (c === '"') {
11845 // skip the escape character
11846 token += c;
11847 next();
11848 } else if (c === '\\' && nextPreview() === 'n') {
11849 // Honor a newline escape sequence
11850 token += '\n';
11851 next();
11852 } else {
11853 token += c;
11854 }
11855
11856 next();
11857 }
11858
11859 if (c != '"') {
11860 throw newSyntaxError('End of string " expected');
11861 }
11862
11863 next();
11864 tokenType = TOKENTYPE.IDENTIFIER;
11865 return;
11866 } // something unknown is found, wrong characters, a syntax error
11867
11868
11869 tokenType = TOKENTYPE.UNKNOWN;
11870
11871 while (c != '') {
11872 token += c;
11873 next();
11874 }
11875
11876 throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"');
11877 }
11878 /**
11879 * Parse a graph.
11880 * @returns {Object} graph
11881 */
11882
11883
11884 function parseGraph() {
11885 var graph = {};
11886 first();
11887 getToken(); // optional strict keyword
11888
11889 if (token === 'strict') {
11890 graph.strict = true;
11891 getToken();
11892 } // graph or digraph keyword
11893
11894
11895 if (token === 'graph' || token === 'digraph') {
11896 graph.type = token;
11897 getToken();
11898 } // optional graph id
11899
11900
11901 if (tokenType === TOKENTYPE.IDENTIFIER) {
11902 graph.id = token;
11903 getToken();
11904 } // open angle bracket
11905
11906
11907 if (token != '{') {
11908 throw newSyntaxError('Angle bracket { expected');
11909 }
11910
11911 getToken(); // statements
11912
11913 parseStatements(graph); // close angle bracket
11914
11915 if (token != '}') {
11916 throw newSyntaxError('Angle bracket } expected');
11917 }
11918
11919 getToken(); // end of file
11920
11921 if (token !== '') {
11922 throw newSyntaxError('End of file expected');
11923 }
11924
11925 getToken(); // remove temporary default options
11926
11927 delete graph.node;
11928 delete graph.edge;
11929 delete graph.graph;
11930 return graph;
11931 }
11932 /**
11933 * Parse a list with statements.
11934 * @param {Object} graph
11935 */
11936
11937
11938 function parseStatements(graph) {
11939 while (token !== '' && token != '}') {
11940 parseStatement(graph);
11941
11942 if (token === ';') {
11943 getToken();
11944 }
11945 }
11946 }
11947 /**
11948 * Parse a single statement. Can be a an attribute statement, node
11949 * statement, a series of node statements and edge statements, or a
11950 * parameter.
11951 * @param {Object} graph
11952 */
11953
11954
11955 function parseStatement(graph) {
11956 // parse subgraph
11957 var subgraph = parseSubgraph(graph);
11958
11959 if (subgraph) {
11960 // edge statements
11961 parseEdge(graph, subgraph);
11962 return;
11963 } // parse an attribute statement
11964
11965
11966 var attr = parseAttributeStatement(graph);
11967
11968 if (attr) {
11969 return;
11970 } // parse node
11971
11972
11973 if (tokenType != TOKENTYPE.IDENTIFIER) {
11974 throw newSyntaxError('Identifier expected');
11975 }
11976
11977 var id = token; // id can be a string or a number
11978
11979 getToken();
11980
11981 if (token === '=') {
11982 // id statement
11983 getToken();
11984
11985 if (tokenType != TOKENTYPE.IDENTIFIER) {
11986 throw newSyntaxError('Identifier expected');
11987 }
11988
11989 graph[id] = token;
11990 getToken(); // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] "
11991 } else {
11992 parseNodeStatement(graph, id);
11993 }
11994 }
11995 /**
11996 * Parse a subgraph
11997 * @param {Object} graph parent graph object
11998 * @return {Object | null} subgraph
11999 */
12000
12001
12002 function parseSubgraph(graph) {
12003 var subgraph = null; // optional subgraph keyword
12004
12005 if (token === 'subgraph') {
12006 subgraph = {};
12007 subgraph.type = 'subgraph';
12008 getToken(); // optional graph id
12009
12010 if (tokenType === TOKENTYPE.IDENTIFIER) {
12011 subgraph.id = token;
12012 getToken();
12013 }
12014 } // open angle bracket
12015
12016
12017 if (token === '{') {
12018 getToken();
12019
12020 if (!subgraph) {
12021 subgraph = {};
12022 }
12023
12024 subgraph.parent = graph;
12025 subgraph.node = graph.node;
12026 subgraph.edge = graph.edge;
12027 subgraph.graph = graph.graph; // statements
12028
12029 parseStatements(subgraph); // close angle bracket
12030
12031 if (token != '}') {
12032 throw newSyntaxError('Angle bracket } expected');
12033 }
12034
12035 getToken(); // remove temporary default options
12036
12037 delete subgraph.node;
12038 delete subgraph.edge;
12039 delete subgraph.graph;
12040 delete subgraph.parent; // register at the parent graph
12041
12042 if (!graph.subgraphs) {
12043 graph.subgraphs = [];
12044 }
12045
12046 graph.subgraphs.push(subgraph);
12047 }
12048
12049 return subgraph;
12050 }
12051 /**
12052 * parse an attribute statement like "node [shape=circle fontSize=16]".
12053 * Available keywords are 'node', 'edge', 'graph'.
12054 * The previous list with default attributes will be replaced
12055 * @param {Object} graph
12056 * @returns {String | null} keyword Returns the name of the parsed attribute
12057 * (node, edge, graph), or null if nothing
12058 * is parsed.
12059 */
12060
12061
12062 function parseAttributeStatement(graph) {
12063 // attribute statements
12064 if (token === 'node') {
12065 getToken(); // node attributes
12066
12067 graph.node = parseAttributeList();
12068 return 'node';
12069 } else if (token === 'edge') {
12070 getToken(); // edge attributes
12071
12072 graph.edge = parseAttributeList();
12073 return 'edge';
12074 } else if (token === 'graph') {
12075 getToken(); // graph attributes
12076
12077 graph.graph = parseAttributeList();
12078 return 'graph';
12079 }
12080
12081 return null;
12082 }
12083 /**
12084 * parse a node statement
12085 * @param {Object} graph
12086 * @param {string | number} id
12087 */
12088
12089
12090 function parseNodeStatement(graph, id) {
12091 // node statement
12092 var node = {
12093 id: id
12094 };
12095 var attr = parseAttributeList();
12096
12097 if (attr) {
12098 node.attr = attr;
12099 }
12100
12101 addNode(graph, node); // edge statements
12102
12103 parseEdge(graph, id);
12104 }
12105 /**
12106 * Parse an edge or a series of edges
12107 * @param {Object} graph
12108 * @param {string | number} from Id of the from node
12109 */
12110
12111
12112 function parseEdge(graph, from) {
12113 while (token === '->' || token === '--') {
12114 var to;
12115 var type = token;
12116 getToken();
12117 var subgraph = parseSubgraph(graph);
12118
12119 if (subgraph) {
12120 to = subgraph;
12121 } else {
12122 if (tokenType != TOKENTYPE.IDENTIFIER) {
12123 throw newSyntaxError('Identifier or subgraph expected');
12124 }
12125
12126 to = token;
12127 addNode(graph, {
12128 id: to
12129 });
12130 getToken();
12131 } // parse edge attributes
12132
12133
12134 var attr = parseAttributeList(); // create edge
12135
12136 var edge = createEdge(graph, from, to, type, attr);
12137 addEdge(graph, edge);
12138 from = to;
12139 }
12140 }
12141 /**
12142 * Parse a set with attributes,
12143 * for example [label="1.000", shape=solid]
12144 * @return {Object | null} attr
12145 */
12146
12147
12148 function parseAttributeList() {
12149 var i;
12150 var attr = null; // edge styles of dot and vis
12151
12152 var edgeStyles = {
12153 'dashed': true,
12154 'solid': false,
12155 'dotted': [1, 5]
12156 };
12157 /**
12158 * Define arrow types.
12159 * vis currently supports types defined in 'arrowTypes'.
12160 * Details of arrow shapes are described in
12161 * http://www.graphviz.org/content/arrow-shapes
12162 */
12163
12164 var arrowTypes = {
12165 dot: 'circle',
12166 box: 'box',
12167 crow: 'crow',
12168 curve: 'curve',
12169 icurve: 'inv_curve',
12170 normal: 'triangle',
12171 inv: 'inv_triangle',
12172 diamond: 'diamond',
12173 tee: 'bar',
12174 vee: 'vee'
12175 };
12176 /**
12177 * 'attr_list' contains attributes for checking if some of them are affected
12178 * later. For instance, both of 'arrowhead' and 'dir' (edge style defined
12179 * in DOT) make changes to 'arrows' attribute in vis.
12180 */
12181
12182 var attr_list = new Array();
12183 var attr_names = new Array(); // used for checking the case.
12184 // parse attributes
12185
12186 while (token === '[') {
12187 getToken();
12188 attr = {};
12189
12190 while (token !== '' && token != ']') {
12191 if (tokenType != TOKENTYPE.IDENTIFIER) {
12192 throw newSyntaxError('Attribute name expected');
12193 }
12194
12195 var name = token;
12196 getToken();
12197
12198 if (token != '=') {
12199 throw newSyntaxError('Equal sign = expected');
12200 }
12201
12202 getToken();
12203
12204 if (tokenType != TOKENTYPE.IDENTIFIER) {
12205 throw newSyntaxError('Attribute value expected');
12206 }
12207
12208 var value = token; // convert from dot style to vis
12209
12210 if (name === 'style') {
12211 value = edgeStyles[value];
12212 }
12213
12214 var arrowType;
12215
12216 if (name === 'arrowhead') {
12217 arrowType = arrowTypes[value];
12218 name = 'arrows';
12219 value = {
12220 'to': {
12221 'enabled': true,
12222 'type': arrowType
12223 }
12224 };
12225 }
12226
12227 if (name === 'arrowtail') {
12228 arrowType = arrowTypes[value];
12229 name = 'arrows';
12230 value = {
12231 'from': {
12232 'enabled': true,
12233 'type': arrowType
12234 }
12235 };
12236 }
12237
12238 attr_list.push({
12239 'attr': attr,
12240 'name': name,
12241 'value': value
12242 });
12243 attr_names.push(name);
12244 getToken();
12245
12246 if (token == ',') {
12247 getToken();
12248 }
12249 }
12250
12251 if (token != ']') {
12252 throw newSyntaxError('Bracket ] expected');
12253 }
12254
12255 getToken();
12256 }
12257 /**
12258 * As explained in [1], graphviz has limitations for combination of
12259 * arrow[head|tail] and dir. If attribute list includes 'dir',
12260 * following cases just be supported.
12261 * 1. both or none + arrowhead, arrowtail
12262 * 2. forward + arrowhead (arrowtail is not affedted)
12263 * 3. back + arrowtail (arrowhead is not affected)
12264 * [1] https://www.graphviz.org/doc/info/attrs.html#h:undir_note
12265 */
12266
12267
12268 if (attr_names.includes('dir')) {
12269 var idx = {}; // get index of 'arrows' and 'dir'
12270
12271 idx.arrows = {};
12272
12273 for (i = 0; i < attr_list.length; i++) {
12274 if (attr_list[i].name === 'arrows') {
12275 if (attr_list[i].value.to != null) {
12276 idx.arrows.to = i;
12277 } else if (attr_list[i].value.from != null) {
12278 idx.arrows.from = i;
12279 } else {
12280 throw newSyntaxError('Invalid value of arrows');
12281 }
12282 } else if (attr_list[i].name === 'dir') {
12283 idx.dir = i;
12284 }
12285 } // first, add default arrow shape if it is not assigned to avoid error
12286
12287
12288 var dir_type = attr_list[idx.dir].value;
12289
12290 if (!attr_names.includes('arrows')) {
12291 if (dir_type === 'both') {
12292 attr_list.push({
12293 'attr': attr_list[idx.dir].attr,
12294 'name': 'arrows',
12295 'value': {
12296 to: {
12297 enabled: true
12298 }
12299 }
12300 });
12301 idx.arrows.to = attr_list.length - 1;
12302 attr_list.push({
12303 'attr': attr_list[idx.dir].attr,
12304 'name': 'arrows',
12305 'value': {
12306 from: {
12307 enabled: true
12308 }
12309 }
12310 });
12311 idx.arrows.from = attr_list.length - 1;
12312 } else if (dir_type === 'forward') {
12313 attr_list.push({
12314 'attr': attr_list[idx.dir].attr,
12315 'name': 'arrows',
12316 'value': {
12317 to: {
12318 enabled: true
12319 }
12320 }
12321 });
12322 idx.arrows.to = attr_list.length - 1;
12323 } else if (dir_type === 'back') {
12324 attr_list.push({
12325 'attr': attr_list[idx.dir].attr,
12326 'name': 'arrows',
12327 'value': {
12328 from: {
12329 enabled: true
12330 }
12331 }
12332 });
12333 idx.arrows.from = attr_list.length - 1;
12334 } else if (dir_type === 'none') {
12335 attr_list.push({
12336 'attr': attr_list[idx.dir].attr,
12337 'name': 'arrows',
12338 'value': ''
12339 });
12340 idx.arrows.to = attr_list.length - 1;
12341 } else {
12342 throw newSyntaxError('Invalid dir type "' + dir_type + '"');
12343 }
12344 }
12345
12346 var from_type;
12347 var to_type; // update 'arrows' attribute from 'dir'.
12348
12349 if (dir_type === 'both') {
12350 // both of shapes of 'from' and 'to' are given
12351 if (idx.arrows.to && idx.arrows.from) {
12352 to_type = attr_list[idx.arrows.to].value.to.type;
12353 from_type = attr_list[idx.arrows.from].value.from.type;
12354 attr_list[idx.arrows.to] = {
12355 'attr': attr_list[idx.arrows.to].attr,
12356 'name': attr_list[idx.arrows.to].name,
12357 'value': {
12358 to: {
12359 enabled: true,
12360 type: to_type
12361 },
12362 from: {
12363 enabled: true,
12364 type: from_type
12365 }
12366 }
12367 };
12368 attr_list.splice(idx.arrows.from, 1); // shape of 'to' is assigned and use default to 'from'
12369 } else if (idx.arrows.to) {
12370 to_type = attr_list[idx.arrows.to].value.to.type;
12371 from_type = 'arrow';
12372 attr_list[idx.arrows.to] = {
12373 'attr': attr_list[idx.arrows.to].attr,
12374 'name': attr_list[idx.arrows.to].name,
12375 'value': {
12376 to: {
12377 enabled: true,
12378 type: to_type
12379 },
12380 from: {
12381 enabled: true,
12382 type: from_type
12383 }
12384 }
12385 }; // only shape of 'from' is assigned and use default for 'to'
12386 } else if (idx.arrows.from) {
12387 to_type = 'arrow';
12388 from_type = attr_list[idx.arrows.from].value.from.type;
12389 attr_list[idx.arrows.from] = {
12390 'attr': attr_list[idx.arrows.from].attr,
12391 'name': attr_list[idx.arrows.from].name,
12392 'value': {
12393 to: {
12394 enabled: true,
12395 type: to_type
12396 },
12397 from: {
12398 enabled: true,
12399 type: from_type
12400 }
12401 }
12402 };
12403 }
12404 } else if (dir_type === 'back') {
12405 // given both of shapes, but use only 'from'
12406 if (idx.arrows.to && idx.arrows.from) {
12407 to_type = '';
12408 from_type = attr_list[idx.arrows.from].value.from.type;
12409 attr_list[idx.arrows.from] = {
12410 'attr': attr_list[idx.arrows.from].attr,
12411 'name': attr_list[idx.arrows.from].name,
12412 'value': {
12413 to: {
12414 enabled: true,
12415 type: to_type
12416 },
12417 from: {
12418 enabled: true,
12419 type: from_type
12420 }
12421 }
12422 }; // given shape of 'to', but does not use it
12423 } else if (idx.arrows.to) {
12424 to_type = '';
12425 from_type = 'arrow';
12426 idx.arrows.from = idx.arrows.to;
12427 attr_list[idx.arrows.from] = {
12428 'attr': attr_list[idx.arrows.from].attr,
12429 'name': attr_list[idx.arrows.from].name,
12430 'value': {
12431 to: {
12432 enabled: true,
12433 type: to_type
12434 },
12435 from: {
12436 enabled: true,
12437 type: from_type
12438 }
12439 }
12440 }; // assign given 'from' shape
12441 } else if (idx.arrows.from) {
12442 to_type = '';
12443 from_type = attr_list[idx.arrows.from].value.from.type;
12444 attr_list[idx.arrows.to] = {
12445 'attr': attr_list[idx.arrows.from].attr,
12446 'name': attr_list[idx.arrows.from].name,
12447 'value': {
12448 to: {
12449 enabled: true,
12450 type: to_type
12451 },
12452 from: {
12453 enabled: true,
12454 type: from_type
12455 }
12456 }
12457 };
12458 }
12459
12460 attr_list[idx.arrows.from] = {
12461 'attr': attr_list[idx.arrows.from].attr,
12462 'name': attr_list[idx.arrows.from].name,
12463 'value': {
12464 from: {
12465 enabled: true,
12466 type: attr_list[idx.arrows.from].value.from.type
12467 }
12468 }
12469 };
12470 } else if (dir_type === 'none') {
12471 var idx_arrow;
12472
12473 if (idx.arrows.to) {
12474 idx_arrow = idx.arrows.to;
12475 } else {
12476 idx_arrow = idx.arrows.from;
12477 }
12478
12479 attr_list[idx_arrow] = {
12480 'attr': attr_list[idx_arrow].attr,
12481 'name': attr_list[idx_arrow].name,
12482 'value': ''
12483 };
12484 } else if (dir_type === 'forward') {
12485 // given both of shapes, but use only 'to'
12486 if (idx.arrows.to && idx.arrows.from) {
12487 to_type = attr_list[idx.arrows.to].value.to.type;
12488 from_type = '';
12489 attr_list[idx.arrows.to] = {
12490 'attr': attr_list[idx.arrows.to].attr,
12491 'name': attr_list[idx.arrows.to].name,
12492 'value': {
12493 to: {
12494 enabled: true,
12495 type: to_type
12496 },
12497 from: {
12498 enabled: true,
12499 type: from_type
12500 }
12501 }
12502 }; // assign given 'to' shape
12503 } else if (idx.arrows.to) {
12504 to_type = attr_list[idx.arrows.to].value.to.type;
12505 from_type = '';
12506 attr_list[idx.arrows.to] = {
12507 'attr': attr_list[idx.arrows.to].attr,
12508 'name': attr_list[idx.arrows.to].name,
12509 'value': {
12510 to: {
12511 enabled: true,
12512 type: to_type
12513 },
12514 from: {
12515 enabled: true,
12516 type: from_type
12517 }
12518 }
12519 }; // given shape of 'from', but does not use it
12520 } else if (idx.arrows.from) {
12521 to_type = 'arrow';
12522 from_type = '';
12523 idx.arrows.to = idx.arrows.from;
12524 attr_list[idx.arrows.to] = {
12525 'attr': attr_list[idx.arrows.to].attr,
12526 'name': attr_list[idx.arrows.to].name,
12527 'value': {
12528 to: {
12529 enabled: true,
12530 type: to_type
12531 },
12532 from: {
12533 enabled: true,
12534 type: from_type
12535 }
12536 }
12537 };
12538 }
12539
12540 attr_list[idx.arrows.to] = {
12541 'attr': attr_list[idx.arrows.to].attr,
12542 'name': attr_list[idx.arrows.to].name,
12543 'value': {
12544 to: {
12545 enabled: true,
12546 type: attr_list[idx.arrows.to].value.to.type
12547 }
12548 }
12549 };
12550 } else {
12551 throw newSyntaxError('Invalid dir type "' + dir_type + '"');
12552 } // remove 'dir' attribute no need anymore
12553
12554
12555 attr_list.splice(idx.dir, 1);
12556 } // parse 'penwidth'
12557
12558
12559 var nof_attr_list;
12560
12561 if (attr_names.includes('penwidth')) {
12562 var tmp_attr_list = [];
12563 nof_attr_list = attr_list.length;
12564
12565 for (i = 0; i < nof_attr_list; i++) {
12566 // exclude 'width' from attr_list if 'penwidth' exists
12567 if (attr_list[i].name !== 'width') {
12568 if (attr_list[i].name === 'penwidth') {
12569 attr_list[i].name = 'width';
12570 }
12571
12572 tmp_attr_list.push(attr_list[i]);
12573 }
12574 }
12575
12576 attr_list = tmp_attr_list;
12577 }
12578
12579 nof_attr_list = attr_list.length;
12580
12581 for (i = 0; i < nof_attr_list; i++) {
12582 setValue(attr_list[i].attr, attr_list[i].name, attr_list[i].value);
12583 }
12584
12585 return attr;
12586 }
12587 /**
12588 * Create a syntax error with extra information on current token and index.
12589 * @param {string} message
12590 * @returns {SyntaxError} err
12591 */
12592
12593
12594 function newSyntaxError(message) {
12595 return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')');
12596 }
12597 /**
12598 * Chop off text after a maximum length
12599 * @param {string} text
12600 * @param {number} maxLength
12601 * @returns {String}
12602 */
12603
12604
12605 function chop(text, maxLength) {
12606 return text.length <= maxLength ? text : text.substr(0, 27) + '...';
12607 }
12608 /**
12609 * Execute a function fn for each pair of elements in two arrays
12610 * @param {Array | *} array1
12611 * @param {Array | *} array2
12612 * @param {function} fn
12613 */
12614
12615
12616 function forEach2(array1, array2, fn) {
12617 if (Array.isArray(array1)) {
12618 array1.forEach(function (elem1) {
12619 if (Array.isArray(array2)) {
12620 array2.forEach(function (elem2) {
12621 fn(elem1, elem2);
12622 });
12623 } else {
12624 fn(elem1, array2);
12625 }
12626 });
12627 } else {
12628 if (Array.isArray(array2)) {
12629 array2.forEach(function (elem2) {
12630 fn(array1, elem2);
12631 });
12632 } else {
12633 fn(array1, array2);
12634 }
12635 }
12636 }
12637 /**
12638 * Set a nested property on an object
12639 * When nested objects are missing, they will be created.
12640 * For example setProp({}, 'font.color', 'red') will return {font: {color: 'red'}}
12641 * @param {Object} object
12642 * @param {string} path A dot separated string like 'font.color'
12643 * @param {*} value Value for the property
12644 * @return {Object} Returns the original object, allows for chaining.
12645 */
12646
12647
12648 function setProp(object, path, value) {
12649 var names = path.split('.');
12650 var prop = names.pop(); // traverse over the nested objects
12651
12652 var obj = object;
12653
12654 for (var i = 0; i < names.length; i++) {
12655 var name = names[i];
12656
12657 if (!(name in obj)) {
12658 obj[name] = {};
12659 }
12660
12661 obj = obj[name];
12662 } // set the property value
12663
12664
12665 obj[prop] = value;
12666 return object;
12667 }
12668 /**
12669 * Convert an object with DOT attributes to their vis.js equivalents.
12670 * @param {Object} attr Object with DOT attributes
12671 * @param {Object} mapping
12672 * @return {Object} Returns an object with vis.js attributes
12673 */
12674
12675
12676 function convertAttr(attr, mapping) {
12677 var converted = {};
12678
12679 for (var prop in attr) {
12680 if (attr.hasOwnProperty(prop)) {
12681 var visProp = mapping[prop];
12682
12683 if (Array.isArray(visProp)) {
12684 visProp.forEach(function (visPropI) {
12685 setProp(converted, visPropI, attr[prop]);
12686 });
12687 } else if (typeof visProp === 'string') {
12688 setProp(converted, visProp, attr[prop]);
12689 } else {
12690 setProp(converted, prop, attr[prop]);
12691 }
12692 }
12693 }
12694
12695 return converted;
12696 }
12697 /**
12698 * Convert a string containing a graph in DOT language into a map containing
12699 * with nodes and edges in the format of graph.
12700 * @param {string} data Text containing a graph in DOT-notation
12701 * @return {Object} graphData
12702 */
12703
12704
12705 function DOTToGraph(data) {
12706 // parse the DOT file
12707 var dotData = parseDOT(data);
12708 var graphData = {
12709 nodes: [],
12710 edges: [],
12711 options: {}
12712 }; // copy the nodes
12713
12714 if (dotData.nodes) {
12715 dotData.nodes.forEach(function (dotNode) {
12716 var graphNode = {
12717 id: dotNode.id,
12718 label: String(dotNode.label || dotNode.id)
12719 };
12720 merge(graphNode, convertAttr(dotNode.attr, NODE_ATTR_MAPPING));
12721
12722 if (graphNode.image) {
12723 graphNode.shape = 'image';
12724 }
12725
12726 graphData.nodes.push(graphNode);
12727 });
12728 } // copy the edges
12729
12730
12731 if (dotData.edges) {
12732 /**
12733 * Convert an edge in DOT format to an edge with VisGraph format
12734 * @param {Object} dotEdge
12735 * @returns {Object} graphEdge
12736 */
12737 var convertEdge = function convertEdge(dotEdge) {
12738 var graphEdge = {
12739 from: dotEdge.from,
12740 to: dotEdge.to
12741 };
12742 merge(graphEdge, convertAttr(dotEdge.attr, EDGE_ATTR_MAPPING)); // Add arrows attribute to default styled arrow.
12743 // The reason why default style is not added in parseAttributeList() is
12744 // because only default is cleared before here.
12745
12746 if (graphEdge.arrows == null && dotEdge.type === '->') {
12747 graphEdge.arrows = 'to';
12748 }
12749
12750 return graphEdge;
12751 };
12752
12753 dotData.edges.forEach(function (dotEdge) {
12754 var from, to;
12755
12756 if (dotEdge.from instanceof Object) {
12757 from = dotEdge.from.nodes;
12758 } else {
12759 from = {
12760 id: dotEdge.from
12761 };
12762 }
12763
12764 if (dotEdge.to instanceof Object) {
12765 to = dotEdge.to.nodes;
12766 } else {
12767 to = {
12768 id: dotEdge.to
12769 };
12770 }
12771
12772 if (dotEdge.from instanceof Object && dotEdge.from.edges) {
12773 dotEdge.from.edges.forEach(function (subEdge) {
12774 var graphEdge = convertEdge(subEdge);
12775 graphData.edges.push(graphEdge);
12776 });
12777 }
12778
12779 forEach2(from, to, function (from, to) {
12780 var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr);
12781 var graphEdge = convertEdge(subEdge);
12782 graphData.edges.push(graphEdge);
12783 });
12784
12785 if (dotEdge.to instanceof Object && dotEdge.to.edges) {
12786 dotEdge.to.edges.forEach(function (subEdge) {
12787 var graphEdge = convertEdge(subEdge);
12788 graphData.edges.push(graphEdge);
12789 });
12790 }
12791 });
12792 } // copy the options
12793
12794
12795 if (dotData.attr) {
12796 graphData.options = dotData.attr;
12797 }
12798
12799 return graphData;
12800 } // exports
12801
12802
12803 var parseDOT_1 = parseDOT;
12804 var DOTToGraph_1 = DOTToGraph;
12805 var dotparser = {
12806 parseDOT: parseDOT_1,
12807 DOTToGraph: DOTToGraph_1
12808 };
12809
12810 var dotparser$1 = /*#__PURE__*/Object.freeze({
12811 __proto__: null,
12812 'default': dotparser,
12813 __moduleExports: dotparser,
12814 parseDOT: parseDOT_1,
12815 DOTToGraph: DOTToGraph_1
12816 });
12817
12818 var $map = arrayIteration.map; // `Array.prototype.map` method
12819 // https://tc39.github.io/ecma262/#sec-array.prototype.map
12820 // with adding support of @@species
12821
12822 _export({
12823 target: 'Array',
12824 proto: true,
12825 forced: !arrayMethodHasSpeciesSupport('map')
12826 }, {
12827 map: function map(callbackfn
12828 /* , thisArg */
12829 ) {
12830 return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
12831 }
12832 });
12833
12834 var quot = /"/g; // B.2.3.2.1 CreateHTML(string, tag, attribute, value)
12835 // https://tc39.github.io/ecma262/#sec-createhtml
12836
12837 var createHtml = function (string, tag, attribute, value) {
12838 var S = String(requireObjectCoercible(string));
12839 var p1 = '<' + tag;
12840 if (attribute !== '') p1 += ' ' + attribute + '="' + String(value).replace(quot, '&quot;') + '"';
12841 return p1 + '>' + S + '</' + tag + '>';
12842 };
12843
12844 // of a tag and escaping quotes in arguments
12845
12846 var forcedStringHtmlMethod = function (METHOD_NAME) {
12847 return fails(function () {
12848 var test = ''[METHOD_NAME]('"');
12849 return test !== test.toLowerCase() || test.split('"').length > 3;
12850 });
12851 };
12852
12853 // https://tc39.github.io/ecma262/#sec-string.prototype.fixed
12854
12855
12856 _export({
12857 target: 'String',
12858 proto: true,
12859 forced: forcedStringHtmlMethod('fixed')
12860 }, {
12861 fixed: function fixed() {
12862 return createHtml(this, 'tt', '', '');
12863 }
12864 });
12865
12866 /**
12867 * Convert Gephi to Vis.
12868 *
12869 * @param gephiJSON - The parsed JSON data in Gephi format.
12870 * @param optionsObj - Additional options.
12871 *
12872 * @returns The converted data ready to be used in Vis.
12873 */
12874 function parseGephi(gephiJSON, optionsObj) {
12875 var options = {
12876 edges: {
12877 inheritColor: false
12878 },
12879 nodes: {
12880 fixed: false,
12881 parseColor: false
12882 }
12883 };
12884
12885 if (optionsObj != null) {
12886 if (optionsObj.fixed != null) {
12887 options.nodes.fixed = optionsObj.fixed;
12888 }
12889
12890 if (optionsObj.parseColor != null) {
12891 options.nodes.parseColor = optionsObj.parseColor;
12892 }
12893
12894 if (optionsObj.inheritColor != null) {
12895 options.edges.inheritColor = optionsObj.inheritColor;
12896 }
12897 }
12898
12899 var gEdges = gephiJSON.edges;
12900 var vEdges = gEdges.map(function (gEdge) {
12901 var vEdge = {
12902 from: gEdge.source,
12903 id: gEdge.id,
12904 to: gEdge.target
12905 };
12906
12907 if (gEdge.attributes != null) {
12908 vEdge.attributes = gEdge.attributes;
12909 }
12910
12911 if (gEdge.label != null) {
12912 vEdge.label = gEdge.label;
12913 }
12914
12915 if (gEdge.attributes != null && gEdge.attributes.title != null) {
12916 vEdge.title = gEdge.attributes.title;
12917 }
12918
12919 if (gEdge.type === 'Directed') {
12920 vEdge.arrows = 'to';
12921 } // edge['value'] = gEdge.attributes != null ? gEdge.attributes.Weight : undefined;
12922 // edge['width'] = edge['value'] != null ? undefined : edgegEdge.size;
12923
12924
12925 if (gEdge.color && options.edges.inheritColor === false) {
12926 vEdge.color = gEdge.color;
12927 }
12928
12929 return vEdge;
12930 });
12931 var vNodes = gephiJSON.nodes.map(function (gNode) {
12932 var vNode = {
12933 id: gNode.id,
12934 fixed: options.nodes.fixed && gNode.x != null && gNode.y != null
12935 };
12936
12937 if (gNode.attributes != null) {
12938 vNode.attributes = gNode.attributes;
12939 }
12940
12941 if (gNode.label != null) {
12942 vNode.label = gNode.label;
12943 }
12944
12945 if (gNode.size != null) {
12946 vNode.size = gNode.size;
12947 }
12948
12949 if (gNode.attributes != null && gNode.attributes.title != null) {
12950 vNode.title = gNode.attributes.title;
12951 }
12952
12953 if (gNode.title != null) {
12954 vNode.title = gNode.title;
12955 }
12956
12957 if (gNode.x != null) {
12958 vNode.x = gNode.x;
12959 }
12960
12961 if (gNode.y != null) {
12962 vNode.y = gNode.y;
12963 }
12964
12965 if (gNode.color != null) {
12966 if (options.nodes.parseColor === true) {
12967 vNode.color = gNode.color;
12968 } else {
12969 vNode.color = {
12970 background: gNode.color,
12971 border: gNode.color,
12972 highlight: {
12973 background: gNode.color,
12974 border: gNode.color
12975 },
12976 hover: {
12977 background: gNode.color,
12978 border: gNode.color
12979 }
12980 };
12981 }
12982 }
12983
12984 return vNode;
12985 });
12986 return {
12987 nodes: vNodes,
12988 edges: vEdges
12989 };
12990 }
12991
12992 var gephiParser = /*#__PURE__*/Object.freeze({
12993 __proto__: null,
12994 parseGephi: parseGephi
12995 });
12996
12997
12998
12999 var Activator = /*#__PURE__*/Object.freeze({
13000 __proto__: null,
13001 'default': undefined
13002 });
13003
13004 var keycharm = createCommonjsModule(function (module, exports) {
13005 /**
13006 * Created by Alex on 11/6/2014.
13007 */
13008 // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60
13009 // if the module has no dependencies, the above pattern can be simplified to
13010
13011 (function (root, factory) {
13012 {
13013 // Node. Does not work with strict CommonJS, but
13014 // only CommonJS-like environments that support module.exports,
13015 // like Node.
13016 module.exports = factory();
13017 }
13018 })(commonjsGlobal, function () {
13019 function keycharm(options) {
13020 var preventDefault = options && options.preventDefault || false;
13021 var container = options && options.container || window;
13022 var _exportFunctions = {};
13023 var _bound = {
13024 keydown: {},
13025 keyup: {}
13026 };
13027 var _keys = {};
13028 var i; // a - z
13029
13030 for (i = 97; i <= 122; i++) {
13031 _keys[String.fromCharCode(i)] = {
13032 code: 65 + (i - 97),
13033 shift: false
13034 };
13035 } // A - Z
13036
13037
13038 for (i = 65; i <= 90; i++) {
13039 _keys[String.fromCharCode(i)] = {
13040 code: i,
13041 shift: true
13042 };
13043 } // 0 - 9
13044
13045
13046 for (i = 0; i <= 9; i++) {
13047 _keys['' + i] = {
13048 code: 48 + i,
13049 shift: false
13050 };
13051 } // F1 - F12
13052
13053
13054 for (i = 1; i <= 12; i++) {
13055 _keys['F' + i] = {
13056 code: 111 + i,
13057 shift: false
13058 };
13059 } // num0 - num9
13060
13061
13062 for (i = 0; i <= 9; i++) {
13063 _keys['num' + i] = {
13064 code: 96 + i,
13065 shift: false
13066 };
13067 } // numpad misc
13068
13069
13070 _keys['num*'] = {
13071 code: 106,
13072 shift: false
13073 };
13074 _keys['num+'] = {
13075 code: 107,
13076 shift: false
13077 };
13078 _keys['num-'] = {
13079 code: 109,
13080 shift: false
13081 };
13082 _keys['num/'] = {
13083 code: 111,
13084 shift: false
13085 };
13086 _keys['num.'] = {
13087 code: 110,
13088 shift: false
13089 }; // arrows
13090
13091 _keys['left'] = {
13092 code: 37,
13093 shift: false
13094 };
13095 _keys['up'] = {
13096 code: 38,
13097 shift: false
13098 };
13099 _keys['right'] = {
13100 code: 39,
13101 shift: false
13102 };
13103 _keys['down'] = {
13104 code: 40,
13105 shift: false
13106 }; // extra keys
13107
13108 _keys['space'] = {
13109 code: 32,
13110 shift: false
13111 };
13112 _keys['enter'] = {
13113 code: 13,
13114 shift: false
13115 };
13116 _keys['shift'] = {
13117 code: 16,
13118 shift: undefined
13119 };
13120 _keys['esc'] = {
13121 code: 27,
13122 shift: false
13123 };
13124 _keys['backspace'] = {
13125 code: 8,
13126 shift: false
13127 };
13128 _keys['tab'] = {
13129 code: 9,
13130 shift: false
13131 };
13132 _keys['ctrl'] = {
13133 code: 17,
13134 shift: false
13135 };
13136 _keys['alt'] = {
13137 code: 18,
13138 shift: false
13139 };
13140 _keys['delete'] = {
13141 code: 46,
13142 shift: false
13143 };
13144 _keys['pageup'] = {
13145 code: 33,
13146 shift: false
13147 };
13148 _keys['pagedown'] = {
13149 code: 34,
13150 shift: false
13151 }; // symbols
13152
13153 _keys['='] = {
13154 code: 187,
13155 shift: false
13156 };
13157 _keys['-'] = {
13158 code: 189,
13159 shift: false
13160 };
13161 _keys[']'] = {
13162 code: 221,
13163 shift: false
13164 };
13165 _keys['['] = {
13166 code: 219,
13167 shift: false
13168 };
13169
13170 var down = function (event) {
13171 handleEvent(event, 'keydown');
13172 };
13173
13174 var up = function (event) {
13175 handleEvent(event, 'keyup');
13176 }; // handle the actualy bound key with the event
13177
13178
13179 var handleEvent = function (event, type) {
13180 if (_bound[type][event.keyCode] !== undefined) {
13181 var bound = _bound[type][event.keyCode];
13182
13183 for (var i = 0; i < bound.length; i++) {
13184 if (bound[i].shift === undefined) {
13185 bound[i].fn(event);
13186 } else if (bound[i].shift == true && event.shiftKey == true) {
13187 bound[i].fn(event);
13188 } else if (bound[i].shift == false && event.shiftKey == false) {
13189 bound[i].fn(event);
13190 }
13191 }
13192
13193 if (preventDefault == true) {
13194 event.preventDefault();
13195 }
13196 }
13197 }; // bind a key to a callback
13198
13199
13200 _exportFunctions.bind = function (key, callback, type) {
13201 if (type === undefined) {
13202 type = 'keydown';
13203 }
13204
13205 if (_keys[key] === undefined) {
13206 throw new Error("unsupported key: " + key);
13207 }
13208
13209 if (_bound[type][_keys[key].code] === undefined) {
13210 _bound[type][_keys[key].code] = [];
13211 }
13212
13213 _bound[type][_keys[key].code].push({
13214 fn: callback,
13215 shift: _keys[key].shift
13216 });
13217 }; // bind all keys to a call back (demo purposes)
13218
13219
13220 _exportFunctions.bindAll = function (callback, type) {
13221 if (type === undefined) {
13222 type = 'keydown';
13223 }
13224
13225 for (var key in _keys) {
13226 if (_keys.hasOwnProperty(key)) {
13227 _exportFunctions.bind(key, callback, type);
13228 }
13229 }
13230 }; // get the key label from an event
13231
13232
13233 _exportFunctions.getKey = function (event) {
13234 for (var key in _keys) {
13235 if (_keys.hasOwnProperty(key)) {
13236 if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) {
13237 return key;
13238 } else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) {
13239 return key;
13240 } else if (event.keyCode == _keys[key].code && key == 'shift') {
13241 return key;
13242 }
13243 }
13244 }
13245
13246 return "unknown key, currently not supported";
13247 }; // unbind either a specific callback from a key or all of them (by leaving callback undefined)
13248
13249
13250 _exportFunctions.unbind = function (key, callback, type) {
13251 if (type === undefined) {
13252 type = 'keydown';
13253 }
13254
13255 if (_keys[key] === undefined) {
13256 throw new Error("unsupported key: " + key);
13257 }
13258
13259 if (callback !== undefined) {
13260 var newBindings = [];
13261 var bound = _bound[type][_keys[key].code];
13262
13263 if (bound !== undefined) {
13264 for (var i = 0; i < bound.length; i++) {
13265 if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) {
13266 newBindings.push(_bound[type][_keys[key].code][i]);
13267 }
13268 }
13269 }
13270
13271 _bound[type][_keys[key].code] = newBindings;
13272 } else {
13273 _bound[type][_keys[key].code] = [];
13274 }
13275 }; // reset all bound variables.
13276
13277
13278 _exportFunctions.reset = function () {
13279 _bound = {
13280 keydown: {},
13281 keyup: {}
13282 };
13283 }; // unbind all listeners and reset all variables.
13284
13285
13286 _exportFunctions.destroy = function () {
13287 _bound = {
13288 keydown: {},
13289 keyup: {}
13290 };
13291 container.removeEventListener('keydown', down, true);
13292 container.removeEventListener('keyup', up, true);
13293 }; // create listeners.
13294
13295
13296 container.addEventListener('keydown', down, true);
13297 container.addEventListener('keyup', up, true); // return the public functions.
13298
13299 return _exportFunctions;
13300 }
13301
13302 return keycharm;
13303 });
13304 });
13305
13306 var keycharm$1 = /*#__PURE__*/Object.freeze({
13307 __proto__: null,
13308 'default': keycharm,
13309 __moduleExports: keycharm
13310 });
13311
13312 /*! Hammer.JS - v2.0.15 - 2019-04-04
13313 * http://naver.github.io/egjs
13314 *
13315 * Forked By Naver egjs
13316 * Copyright (c) hammerjs
13317 * Licensed under the MIT license */
13318 function _extends() {
13319 _extends = Object.assign || function (target) {
13320 for (var i = 1; i < arguments.length; i++) {
13321 var source = arguments[i];
13322
13323 for (var key in source) {
13324 if (Object.prototype.hasOwnProperty.call(source, key)) {
13325 target[key] = source[key];
13326 }
13327 }
13328 }
13329
13330 return target;
13331 };
13332
13333 return _extends.apply(this, arguments);
13334 }
13335
13336 function _inheritsLoose(subClass, superClass) {
13337 subClass.prototype = Object.create(superClass.prototype);
13338 subClass.prototype.constructor = subClass;
13339 subClass.__proto__ = superClass;
13340 }
13341
13342 function _assertThisInitialized(self) {
13343 if (self === void 0) {
13344 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
13345 }
13346
13347 return self;
13348 }
13349 /**
13350 * @private
13351 * extend object.
13352 * means that properties in dest will be overwritten by the ones in src.
13353 * @param {Object} target
13354 * @param {...Object} objects_to_assign
13355 * @returns {Object} target
13356 */
13357
13358
13359 var assign;
13360
13361 if (typeof Object.assign !== 'function') {
13362 assign = function assign(target) {
13363 if (target === undefined || target === null) {
13364 throw new TypeError('Cannot convert undefined or null to object');
13365 }
13366
13367 var output = Object(target);
13368
13369 for (var index = 1; index < arguments.length; index++) {
13370 var source = arguments[index];
13371
13372 if (source !== undefined && source !== null) {
13373 for (var nextKey in source) {
13374 if (source.hasOwnProperty(nextKey)) {
13375 output[nextKey] = source[nextKey];
13376 }
13377 }
13378 }
13379 }
13380
13381 return output;
13382 };
13383 } else {
13384 assign = Object.assign;
13385 }
13386
13387 var assign$1 = assign;
13388 var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
13389 var TEST_ELEMENT = typeof document === "undefined" ? {
13390 style: {}
13391 } : document.createElement('div');
13392 var TYPE_FUNCTION = 'function';
13393 var round = Math.round,
13394 abs$1 = Math.abs;
13395 var now = Date.now;
13396 /**
13397 * @private
13398 * get the prefixed property
13399 * @param {Object} obj
13400 * @param {String} property
13401 * @returns {String|Undefined} prefixed
13402 */
13403
13404 function prefixed(obj, property) {
13405 var prefix;
13406 var prop;
13407 var camelProp = property[0].toUpperCase() + property.slice(1);
13408 var i = 0;
13409
13410 while (i < VENDOR_PREFIXES.length) {
13411 prefix = VENDOR_PREFIXES[i];
13412 prop = prefix ? prefix + camelProp : property;
13413
13414 if (prop in obj) {
13415 return prop;
13416 }
13417
13418 i++;
13419 }
13420
13421 return undefined;
13422 }
13423 /* eslint-disable no-new-func, no-nested-ternary */
13424
13425
13426 var win;
13427
13428 if (typeof window === "undefined") {
13429 // window is undefined in node.js
13430 win = {};
13431 } else {
13432 win = window;
13433 }
13434
13435 var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
13436 var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
13437
13438 function getTouchActionProps() {
13439 if (!NATIVE_TOUCH_ACTION) {
13440 return false;
13441 }
13442
13443 var touchMap = {};
13444 var cssSupports = win.CSS && win.CSS.supports;
13445 ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function (val) {
13446 // If css.supports is not supported but there is native touch-action assume it supports
13447 // all values. This is the case for IE 10 and 11.
13448 return touchMap[val] = cssSupports ? win.CSS.supports('touch-action', val) : true;
13449 });
13450 return touchMap;
13451 }
13452
13453 var TOUCH_ACTION_COMPUTE = 'compute';
13454 var TOUCH_ACTION_AUTO = 'auto';
13455 var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
13456
13457 var TOUCH_ACTION_NONE = 'none';
13458 var TOUCH_ACTION_PAN_X = 'pan-x';
13459 var TOUCH_ACTION_PAN_Y = 'pan-y';
13460 var TOUCH_ACTION_MAP = getTouchActionProps();
13461 var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
13462 var SUPPORT_TOUCH = 'ontouchstart' in win;
13463 var SUPPORT_POINTER_EVENTS = prefixed(win, 'PointerEvent') !== undefined;
13464 var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
13465 var INPUT_TYPE_TOUCH = 'touch';
13466 var INPUT_TYPE_PEN = 'pen';
13467 var INPUT_TYPE_MOUSE = 'mouse';
13468 var INPUT_TYPE_KINECT = 'kinect';
13469 var COMPUTE_INTERVAL = 25;
13470 var INPUT_START = 1;
13471 var INPUT_MOVE = 2;
13472 var INPUT_END = 4;
13473 var INPUT_CANCEL = 8;
13474 var DIRECTION_NONE = 1;
13475 var DIRECTION_LEFT = 2;
13476 var DIRECTION_RIGHT = 4;
13477 var DIRECTION_UP = 8;
13478 var DIRECTION_DOWN = 16;
13479 var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
13480 var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
13481 var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
13482 var PROPS_XY = ['x', 'y'];
13483 var PROPS_CLIENT_XY = ['clientX', 'clientY'];
13484 /**
13485 * @private
13486 * walk objects and arrays
13487 * @param {Object} obj
13488 * @param {Function} iterator
13489 * @param {Object} context
13490 */
13491
13492 function each(obj, iterator, context) {
13493 var i;
13494
13495 if (!obj) {
13496 return;
13497 }
13498
13499 if (obj.forEach) {
13500 obj.forEach(iterator, context);
13501 } else if (obj.length !== undefined) {
13502 i = 0;
13503
13504 while (i < obj.length) {
13505 iterator.call(context, obj[i], i, obj);
13506 i++;
13507 }
13508 } else {
13509 for (i in obj) {
13510 obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
13511 }
13512 }
13513 }
13514 /**
13515 * @private
13516 * let a boolean value also be a function that must return a boolean
13517 * this first item in args will be used as the context
13518 * @param {Boolean|Function} val
13519 * @param {Array} [args]
13520 * @returns {Boolean}
13521 */
13522
13523
13524 function boolOrFn(val, args) {
13525 if (typeof val === TYPE_FUNCTION) {
13526 return val.apply(args ? args[0] || undefined : undefined, args);
13527 }
13528
13529 return val;
13530 }
13531 /**
13532 * @private
13533 * small indexOf wrapper
13534 * @param {String} str
13535 * @param {String} find
13536 * @returns {Boolean} found
13537 */
13538
13539
13540 function inStr(str, find) {
13541 return str.indexOf(find) > -1;
13542 }
13543 /**
13544 * @private
13545 * when the touchActions are collected they are not a valid value, so we need to clean things up. *
13546 * @param {String} actions
13547 * @returns {*}
13548 */
13549
13550
13551 function cleanTouchActions(actions) {
13552 // none
13553 if (inStr(actions, TOUCH_ACTION_NONE)) {
13554 return TOUCH_ACTION_NONE;
13555 }
13556
13557 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
13558 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); // if both pan-x and pan-y are set (different recognizers
13559 // for different directions, e.g. horizontal pan but vertical swipe?)
13560 // we need none (as otherwise with pan-x pan-y combined none of these
13561 // recognizers will work, since the browser would handle all panning
13562
13563 if (hasPanX && hasPanY) {
13564 return TOUCH_ACTION_NONE;
13565 } // pan-x OR pan-y
13566
13567
13568 if (hasPanX || hasPanY) {
13569 return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
13570 } // manipulation
13571
13572
13573 if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
13574 return TOUCH_ACTION_MANIPULATION;
13575 }
13576
13577 return TOUCH_ACTION_AUTO;
13578 }
13579 /**
13580 * @private
13581 * Touch Action
13582 * sets the touchAction property or uses the js alternative
13583 * @param {Manager} manager
13584 * @param {String} value
13585 * @constructor
13586 */
13587
13588
13589 var TouchAction =
13590 /*#__PURE__*/
13591 function () {
13592 function TouchAction(manager, value) {
13593 this.manager = manager;
13594 this.set(value);
13595 }
13596 /**
13597 * @private
13598 * set the touchAction value on the element or enable the polyfill
13599 * @param {String} value
13600 */
13601
13602
13603 var _proto = TouchAction.prototype;
13604
13605 _proto.set = function set(value) {
13606 // find out the touch-action by the event handlers
13607 if (value === TOUCH_ACTION_COMPUTE) {
13608 value = this.compute();
13609 }
13610
13611 if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
13612 this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
13613 }
13614
13615 this.actions = value.toLowerCase().trim();
13616 };
13617 /**
13618 * @private
13619 * just re-set the touchAction value
13620 */
13621
13622
13623 _proto.update = function update() {
13624 this.set(this.manager.options.touchAction);
13625 };
13626 /**
13627 * @private
13628 * compute the value for the touchAction property based on the recognizer's settings
13629 * @returns {String} value
13630 */
13631
13632
13633 _proto.compute = function compute() {
13634 var actions = [];
13635 each(this.manager.recognizers, function (recognizer) {
13636 if (boolOrFn(recognizer.options.enable, [recognizer])) {
13637 actions = actions.concat(recognizer.getTouchAction());
13638 }
13639 });
13640 return cleanTouchActions(actions.join(' '));
13641 };
13642 /**
13643 * @private
13644 * this method is called on each input cycle and provides the preventing of the browser behavior
13645 * @param {Object} input
13646 */
13647
13648
13649 _proto.preventDefaults = function preventDefaults(input) {
13650 var srcEvent = input.srcEvent;
13651 var direction = input.offsetDirection; // if the touch action did prevented once this session
13652
13653 if (this.manager.session.prevented) {
13654 srcEvent.preventDefault();
13655 return;
13656 }
13657
13658 var actions = this.actions;
13659 var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
13660 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
13661 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
13662
13663 if (hasNone) {
13664 // do not prevent defaults if this is a tap gesture
13665 var isTapPointer = input.pointers.length === 1;
13666 var isTapMovement = input.distance < 2;
13667 var isTapTouchTime = input.deltaTime < 250;
13668
13669 if (isTapPointer && isTapMovement && isTapTouchTime) {
13670 return;
13671 }
13672 }
13673
13674 if (hasPanX && hasPanY) {
13675 // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
13676 return;
13677 }
13678
13679 if (hasNone || hasPanY && direction & DIRECTION_HORIZONTAL || hasPanX && direction & DIRECTION_VERTICAL) {
13680 return this.preventSrc(srcEvent);
13681 }
13682 };
13683 /**
13684 * @private
13685 * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
13686 * @param {Object} srcEvent
13687 */
13688
13689
13690 _proto.preventSrc = function preventSrc(srcEvent) {
13691 this.manager.session.prevented = true;
13692 srcEvent.preventDefault();
13693 };
13694
13695 return TouchAction;
13696 }();
13697 /**
13698 * @private
13699 * find if a node is in the given parent
13700 * @method hasParent
13701 * @param {HTMLElement} node
13702 * @param {HTMLElement} parent
13703 * @return {Boolean} found
13704 */
13705
13706
13707 function hasParent$1(node, parent) {
13708 while (node) {
13709 if (node === parent) {
13710 return true;
13711 }
13712
13713 node = node.parentNode;
13714 }
13715
13716 return false;
13717 }
13718 /**
13719 * @private
13720 * get the center of all the pointers
13721 * @param {Array} pointers
13722 * @return {Object} center contains `x` and `y` properties
13723 */
13724
13725
13726 function getCenter(pointers) {
13727 var pointersLength = pointers.length; // no need to loop when only one touch
13728
13729 if (pointersLength === 1) {
13730 return {
13731 x: round(pointers[0].clientX),
13732 y: round(pointers[0].clientY)
13733 };
13734 }
13735
13736 var x = 0;
13737 var y = 0;
13738 var i = 0;
13739
13740 while (i < pointersLength) {
13741 x += pointers[i].clientX;
13742 y += pointers[i].clientY;
13743 i++;
13744 }
13745
13746 return {
13747 x: round(x / pointersLength),
13748 y: round(y / pointersLength)
13749 };
13750 }
13751 /**
13752 * @private
13753 * create a simple clone from the input used for storage of firstInput and firstMultiple
13754 * @param {Object} input
13755 * @returns {Object} clonedInputData
13756 */
13757
13758
13759 function simpleCloneInputData(input) {
13760 // make a simple copy of the pointers because we will get a reference if we don't
13761 // we only need clientXY for the calculations
13762 var pointers = [];
13763 var i = 0;
13764
13765 while (i < input.pointers.length) {
13766 pointers[i] = {
13767 clientX: round(input.pointers[i].clientX),
13768 clientY: round(input.pointers[i].clientY)
13769 };
13770 i++;
13771 }
13772
13773 return {
13774 timeStamp: now(),
13775 pointers: pointers,
13776 center: getCenter(pointers),
13777 deltaX: input.deltaX,
13778 deltaY: input.deltaY
13779 };
13780 }
13781 /**
13782 * @private
13783 * calculate the absolute distance between two points
13784 * @param {Object} p1 {x, y}
13785 * @param {Object} p2 {x, y}
13786 * @param {Array} [props] containing x and y keys
13787 * @return {Number} distance
13788 */
13789
13790
13791 function getDistance(p1, p2, props) {
13792 if (!props) {
13793 props = PROPS_XY;
13794 }
13795
13796 var x = p2[props[0]] - p1[props[0]];
13797 var y = p2[props[1]] - p1[props[1]];
13798 return Math.sqrt(x * x + y * y);
13799 }
13800 /**
13801 * @private
13802 * calculate the angle between two coordinates
13803 * @param {Object} p1
13804 * @param {Object} p2
13805 * @param {Array} [props] containing x and y keys
13806 * @return {Number} angle
13807 */
13808
13809
13810 function getAngle(p1, p2, props) {
13811 if (!props) {
13812 props = PROPS_XY;
13813 }
13814
13815 var x = p2[props[0]] - p1[props[0]];
13816 var y = p2[props[1]] - p1[props[1]];
13817 return Math.atan2(y, x) * 180 / Math.PI;
13818 }
13819 /**
13820 * @private
13821 * get the direction between two points
13822 * @param {Number} x
13823 * @param {Number} y
13824 * @return {Number} direction
13825 */
13826
13827
13828 function getDirection(x, y) {
13829 if (x === y) {
13830 return DIRECTION_NONE;
13831 }
13832
13833 if (abs$1(x) >= abs$1(y)) {
13834 return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
13835 }
13836
13837 return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
13838 }
13839
13840 function computeDeltaXY(session, input) {
13841 var center = input.center; // let { offsetDelta:offset = {}, prevDelta = {}, prevInput = {} } = session;
13842 // jscs throwing error on defalut destructured values and without defaults tests fail
13843
13844 var offset = session.offsetDelta || {};
13845 var prevDelta = session.prevDelta || {};
13846 var prevInput = session.prevInput || {};
13847
13848 if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
13849 prevDelta = session.prevDelta = {
13850 x: prevInput.deltaX || 0,
13851 y: prevInput.deltaY || 0
13852 };
13853 offset = session.offsetDelta = {
13854 x: center.x,
13855 y: center.y
13856 };
13857 }
13858
13859 input.deltaX = prevDelta.x + (center.x - offset.x);
13860 input.deltaY = prevDelta.y + (center.y - offset.y);
13861 }
13862 /**
13863 * @private
13864 * calculate the velocity between two points. unit is in px per ms.
13865 * @param {Number} deltaTime
13866 * @param {Number} x
13867 * @param {Number} y
13868 * @return {Object} velocity `x` and `y`
13869 */
13870
13871
13872 function getVelocity(deltaTime, x, y) {
13873 return {
13874 x: x / deltaTime || 0,
13875 y: y / deltaTime || 0
13876 };
13877 }
13878 /**
13879 * @private
13880 * calculate the scale factor between two pointersets
13881 * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
13882 * @param {Array} start array of pointers
13883 * @param {Array} end array of pointers
13884 * @return {Number} scale
13885 */
13886
13887
13888 function getScale(start, end) {
13889 return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
13890 }
13891 /**
13892 * @private
13893 * calculate the rotation degrees between two pointersets
13894 * @param {Array} start array of pointers
13895 * @param {Array} end array of pointers
13896 * @return {Number} rotation
13897 */
13898
13899
13900 function getRotation(start, end) {
13901 return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
13902 }
13903 /**
13904 * @private
13905 * velocity is calculated every x ms
13906 * @param {Object} session
13907 * @param {Object} input
13908 */
13909
13910
13911 function computeIntervalInputData(session, input) {
13912 var last = session.lastInterval || input;
13913 var deltaTime = input.timeStamp - last.timeStamp;
13914 var velocity;
13915 var velocityX;
13916 var velocityY;
13917 var direction;
13918
13919 if (input.eventType !== INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
13920 var deltaX = input.deltaX - last.deltaX;
13921 var deltaY = input.deltaY - last.deltaY;
13922 var v = getVelocity(deltaTime, deltaX, deltaY);
13923 velocityX = v.x;
13924 velocityY = v.y;
13925 velocity = abs$1(v.x) > abs$1(v.y) ? v.x : v.y;
13926 direction = getDirection(deltaX, deltaY);
13927 session.lastInterval = input;
13928 } else {
13929 // use latest velocity info if it doesn't overtake a minimum period
13930 velocity = last.velocity;
13931 velocityX = last.velocityX;
13932 velocityY = last.velocityY;
13933 direction = last.direction;
13934 }
13935
13936 input.velocity = velocity;
13937 input.velocityX = velocityX;
13938 input.velocityY = velocityY;
13939 input.direction = direction;
13940 }
13941 /**
13942 * @private
13943 * extend the data with some usable properties like scale, rotate, velocity etc
13944 * @param {Object} manager
13945 * @param {Object} input
13946 */
13947
13948
13949 function computeInputData(manager, input) {
13950 var session = manager.session;
13951 var pointers = input.pointers;
13952 var pointersLength = pointers.length; // store the first input to calculate the distance and direction
13953
13954 if (!session.firstInput) {
13955 session.firstInput = simpleCloneInputData(input);
13956 } // to compute scale and rotation we need to store the multiple touches
13957
13958
13959 if (pointersLength > 1 && !session.firstMultiple) {
13960 session.firstMultiple = simpleCloneInputData(input);
13961 } else if (pointersLength === 1) {
13962 session.firstMultiple = false;
13963 }
13964
13965 var firstInput = session.firstInput,
13966 firstMultiple = session.firstMultiple;
13967 var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
13968 var center = input.center = getCenter(pointers);
13969 input.timeStamp = now();
13970 input.deltaTime = input.timeStamp - firstInput.timeStamp;
13971 input.angle = getAngle(offsetCenter, center);
13972 input.distance = getDistance(offsetCenter, center);
13973 computeDeltaXY(session, input);
13974 input.offsetDirection = getDirection(input.deltaX, input.deltaY);
13975 var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
13976 input.overallVelocityX = overallVelocity.x;
13977 input.overallVelocityY = overallVelocity.y;
13978 input.overallVelocity = abs$1(overallVelocity.x) > abs$1(overallVelocity.y) ? overallVelocity.x : overallVelocity.y;
13979 input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
13980 input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
13981 input.maxPointers = !session.prevInput ? input.pointers.length : input.pointers.length > session.prevInput.maxPointers ? input.pointers.length : session.prevInput.maxPointers;
13982 computeIntervalInputData(session, input); // find the correct target
13983
13984 var target = manager.element;
13985
13986 if (hasParent$1(input.srcEvent.target, target)) {
13987 target = input.srcEvent.target;
13988 }
13989
13990 input.target = target;
13991 }
13992 /**
13993 * @private
13994 * handle input events
13995 * @param {Manager} manager
13996 * @param {String} eventType
13997 * @param {Object} input
13998 */
13999
14000
14001 function inputHandler(manager, eventType, input) {
14002 var pointersLen = input.pointers.length;
14003 var changedPointersLen = input.changedPointers.length;
14004 var isFirst = eventType & INPUT_START && pointersLen - changedPointersLen === 0;
14005 var isFinal = eventType & (INPUT_END | INPUT_CANCEL) && pointersLen - changedPointersLen === 0;
14006 input.isFirst = !!isFirst;
14007 input.isFinal = !!isFinal;
14008
14009 if (isFirst) {
14010 manager.session = {};
14011 } // source event is the normalized value of the domEvents
14012 // like 'touchstart, mouseup, pointerdown'
14013
14014
14015 input.eventType = eventType; // compute scale, rotation etc
14016
14017 computeInputData(manager, input); // emit secret event
14018
14019 manager.emit('hammer.input', input);
14020 manager.recognize(input);
14021 manager.session.prevInput = input;
14022 }
14023 /**
14024 * @private
14025 * split string on whitespace
14026 * @param {String} str
14027 * @returns {Array} words
14028 */
14029
14030
14031 function splitStr(str) {
14032 return str.trim().split(/\s+/g);
14033 }
14034 /**
14035 * @private
14036 * addEventListener with multiple events at once
14037 * @param {EventTarget} target
14038 * @param {String} types
14039 * @param {Function} handler
14040 */
14041
14042
14043 function addEventListeners(target, types, handler) {
14044 each(splitStr(types), function (type) {
14045 target.addEventListener(type, handler, false);
14046 });
14047 }
14048 /**
14049 * @private
14050 * removeEventListener with multiple events at once
14051 * @param {EventTarget} target
14052 * @param {String} types
14053 * @param {Function} handler
14054 */
14055
14056
14057 function removeEventListeners(target, types, handler) {
14058 each(splitStr(types), function (type) {
14059 target.removeEventListener(type, handler, false);
14060 });
14061 }
14062 /**
14063 * @private
14064 * get the window object of an element
14065 * @param {HTMLElement} element
14066 * @returns {DocumentView|Window}
14067 */
14068
14069
14070 function getWindowForElement(element) {
14071 var doc = element.ownerDocument || element;
14072 return doc.defaultView || doc.parentWindow || window;
14073 }
14074 /**
14075 * @private
14076 * create new input type manager
14077 * @param {Manager} manager
14078 * @param {Function} callback
14079 * @returns {Input}
14080 * @constructor
14081 */
14082
14083
14084 var Input =
14085 /*#__PURE__*/
14086 function () {
14087 function Input(manager, callback) {
14088 var self = this;
14089 this.manager = manager;
14090 this.callback = callback;
14091 this.element = manager.element;
14092 this.target = manager.options.inputTarget; // smaller wrapper around the handler, for the scope and the enabled state of the manager,
14093 // so when disabled the input events are completely bypassed.
14094
14095 this.domHandler = function (ev) {
14096 if (boolOrFn(manager.options.enable, [manager])) {
14097 self.handler(ev);
14098 }
14099 };
14100
14101 this.init();
14102 }
14103 /**
14104 * @private
14105 * should handle the inputEvent data and trigger the callback
14106 * @virtual
14107 */
14108
14109
14110 var _proto = Input.prototype;
14111
14112 _proto.handler = function handler() {};
14113 /**
14114 * @private
14115 * bind the events
14116 */
14117
14118
14119 _proto.init = function init() {
14120 this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
14121 this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
14122 this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
14123 };
14124 /**
14125 * @private
14126 * unbind the events
14127 */
14128
14129
14130 _proto.destroy = function destroy() {
14131 this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
14132 this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
14133 this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
14134 };
14135
14136 return Input;
14137 }();
14138 /**
14139 * @private
14140 * find if a array contains the object using indexOf or a simple polyFill
14141 * @param {Array} src
14142 * @param {String} find
14143 * @param {String} [findByKey]
14144 * @return {Boolean|Number} false when not found, or the index
14145 */
14146
14147
14148 function inArray(src, find, findByKey) {
14149 if (src.indexOf && !findByKey) {
14150 return src.indexOf(find);
14151 } else {
14152 var i = 0;
14153
14154 while (i < src.length) {
14155 if (findByKey && src[i][findByKey] == find || !findByKey && src[i] === find) {
14156 // do not use === here, test fails
14157 return i;
14158 }
14159
14160 i++;
14161 }
14162
14163 return -1;
14164 }
14165 }
14166
14167 var POINTER_INPUT_MAP = {
14168 pointerdown: INPUT_START,
14169 pointermove: INPUT_MOVE,
14170 pointerup: INPUT_END,
14171 pointercancel: INPUT_CANCEL,
14172 pointerout: INPUT_CANCEL
14173 }; // in IE10 the pointer types is defined as an enum
14174
14175 var IE10_POINTER_TYPE_ENUM = {
14176 2: INPUT_TYPE_TOUCH,
14177 3: INPUT_TYPE_PEN,
14178 4: INPUT_TYPE_MOUSE,
14179 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
14180
14181 };
14182 var POINTER_ELEMENT_EVENTS = 'pointerdown';
14183 var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; // IE10 has prefixed support, and case-sensitive
14184
14185 if (win.MSPointerEvent && !win.PointerEvent) {
14186 POINTER_ELEMENT_EVENTS = 'MSPointerDown';
14187 POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
14188 }
14189 /**
14190 * @private
14191 * Pointer events input
14192 * @constructor
14193 * @extends Input
14194 */
14195
14196
14197 var PointerEventInput =
14198 /*#__PURE__*/
14199 function (_Input) {
14200 _inheritsLoose(PointerEventInput, _Input);
14201
14202 function PointerEventInput() {
14203 var _this;
14204
14205 var proto = PointerEventInput.prototype;
14206 proto.evEl = POINTER_ELEMENT_EVENTS;
14207 proto.evWin = POINTER_WINDOW_EVENTS;
14208 _this = _Input.apply(this, arguments) || this;
14209 _this.store = _this.manager.session.pointerEvents = [];
14210 return _this;
14211 }
14212 /**
14213 * @private
14214 * handle mouse events
14215 * @param {Object} ev
14216 */
14217
14218
14219 var _proto = PointerEventInput.prototype;
14220
14221 _proto.handler = function handler(ev) {
14222 var store = this.store;
14223 var removePointer = false;
14224 var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
14225 var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
14226 var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
14227 var isTouch = pointerType === INPUT_TYPE_TOUCH; // get index of the event in the store
14228
14229 var storeIndex = inArray(store, ev.pointerId, 'pointerId'); // start and mouse must be down
14230
14231 if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
14232 if (storeIndex < 0) {
14233 store.push(ev);
14234 storeIndex = store.length - 1;
14235 }
14236 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
14237 removePointer = true;
14238 } // it not found, so the pointer hasn't been down (so it's probably a hover)
14239
14240
14241 if (storeIndex < 0) {
14242 return;
14243 } // update the event in the store
14244
14245
14246 store[storeIndex] = ev;
14247 this.callback(this.manager, eventType, {
14248 pointers: store,
14249 changedPointers: [ev],
14250 pointerType: pointerType,
14251 srcEvent: ev
14252 });
14253
14254 if (removePointer) {
14255 // remove from the store
14256 store.splice(storeIndex, 1);
14257 }
14258 };
14259
14260 return PointerEventInput;
14261 }(Input);
14262 /**
14263 * @private
14264 * convert array-like objects to real arrays
14265 * @param {Object} obj
14266 * @returns {Array}
14267 */
14268
14269
14270 function toArray$1(obj) {
14271 return Array.prototype.slice.call(obj, 0);
14272 }
14273 /**
14274 * @private
14275 * unique array with objects based on a key (like 'id') or just by the array's value
14276 * @param {Array} src [{id:1},{id:2},{id:1}]
14277 * @param {String} [key]
14278 * @param {Boolean} [sort=False]
14279 * @returns {Array} [{id:1},{id:2}]
14280 */
14281
14282
14283 function uniqueArray(src, key, sort) {
14284 var results = [];
14285 var values = [];
14286 var i = 0;
14287
14288 while (i < src.length) {
14289 var val = key ? src[i][key] : src[i];
14290
14291 if (inArray(values, val) < 0) {
14292 results.push(src[i]);
14293 }
14294
14295 values[i] = val;
14296 i++;
14297 }
14298
14299 if (sort) {
14300 if (!key) {
14301 results = results.sort();
14302 } else {
14303 results = results.sort(function (a, b) {
14304 return a[key] > b[key];
14305 });
14306 }
14307 }
14308
14309 return results;
14310 }
14311
14312 var TOUCH_INPUT_MAP = {
14313 touchstart: INPUT_START,
14314 touchmove: INPUT_MOVE,
14315 touchend: INPUT_END,
14316 touchcancel: INPUT_CANCEL
14317 };
14318 var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
14319 /**
14320 * @private
14321 * Multi-user touch events input
14322 * @constructor
14323 * @extends Input
14324 */
14325
14326 var TouchInput =
14327 /*#__PURE__*/
14328 function (_Input) {
14329 _inheritsLoose(TouchInput, _Input);
14330
14331 function TouchInput() {
14332 var _this;
14333
14334 TouchInput.prototype.evTarget = TOUCH_TARGET_EVENTS;
14335 _this = _Input.apply(this, arguments) || this;
14336 _this.targetIds = {}; // this.evTarget = TOUCH_TARGET_EVENTS;
14337
14338 return _this;
14339 }
14340
14341 var _proto = TouchInput.prototype;
14342
14343 _proto.handler = function handler(ev) {
14344 var type = TOUCH_INPUT_MAP[ev.type];
14345 var touches = getTouches.call(this, ev, type);
14346
14347 if (!touches) {
14348 return;
14349 }
14350
14351 this.callback(this.manager, type, {
14352 pointers: touches[0],
14353 changedPointers: touches[1],
14354 pointerType: INPUT_TYPE_TOUCH,
14355 srcEvent: ev
14356 });
14357 };
14358
14359 return TouchInput;
14360 }(Input);
14361
14362 function getTouches(ev, type) {
14363 var allTouches = toArray$1(ev.touches);
14364 var targetIds = this.targetIds; // when there is only one touch, the process can be simplified
14365
14366 if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
14367 targetIds[allTouches[0].identifier] = true;
14368 return [allTouches, allTouches];
14369 }
14370
14371 var i;
14372 var targetTouches;
14373 var changedTouches = toArray$1(ev.changedTouches);
14374 var changedTargetTouches = [];
14375 var target = this.target; // get target touches from touches
14376
14377 targetTouches = allTouches.filter(function (touch) {
14378 return hasParent$1(touch.target, target);
14379 }); // collect touches
14380
14381 if (type === INPUT_START) {
14382 i = 0;
14383
14384 while (i < targetTouches.length) {
14385 targetIds[targetTouches[i].identifier] = true;
14386 i++;
14387 }
14388 } // filter changed touches to only contain touches that exist in the collected target ids
14389
14390
14391 i = 0;
14392
14393 while (i < changedTouches.length) {
14394 if (targetIds[changedTouches[i].identifier]) {
14395 changedTargetTouches.push(changedTouches[i]);
14396 } // cleanup removed touches
14397
14398
14399 if (type & (INPUT_END | INPUT_CANCEL)) {
14400 delete targetIds[changedTouches[i].identifier];
14401 }
14402
14403 i++;
14404 }
14405
14406 if (!changedTargetTouches.length) {
14407 return;
14408 }
14409
14410 return [// merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
14411 uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), changedTargetTouches];
14412 }
14413
14414 var MOUSE_INPUT_MAP = {
14415 mousedown: INPUT_START,
14416 mousemove: INPUT_MOVE,
14417 mouseup: INPUT_END
14418 };
14419 var MOUSE_ELEMENT_EVENTS = 'mousedown';
14420 var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
14421 /**
14422 * @private
14423 * Mouse events input
14424 * @constructor
14425 * @extends Input
14426 */
14427
14428 var MouseInput =
14429 /*#__PURE__*/
14430 function (_Input) {
14431 _inheritsLoose(MouseInput, _Input);
14432
14433 function MouseInput() {
14434 var _this;
14435
14436 var proto = MouseInput.prototype;
14437 proto.evEl = MOUSE_ELEMENT_EVENTS;
14438 proto.evWin = MOUSE_WINDOW_EVENTS;
14439 _this = _Input.apply(this, arguments) || this;
14440 _this.pressed = false; // mousedown state
14441
14442 return _this;
14443 }
14444 /**
14445 * @private
14446 * handle mouse events
14447 * @param {Object} ev
14448 */
14449
14450
14451 var _proto = MouseInput.prototype;
14452
14453 _proto.handler = function handler(ev) {
14454 var eventType = MOUSE_INPUT_MAP[ev.type]; // on start we want to have the left mouse button down
14455
14456 if (eventType & INPUT_START && ev.button === 0) {
14457 this.pressed = true;
14458 }
14459
14460 if (eventType & INPUT_MOVE && ev.which !== 1) {
14461 eventType = INPUT_END;
14462 } // mouse must be down
14463
14464
14465 if (!this.pressed) {
14466 return;
14467 }
14468
14469 if (eventType & INPUT_END) {
14470 this.pressed = false;
14471 }
14472
14473 this.callback(this.manager, eventType, {
14474 pointers: [ev],
14475 changedPointers: [ev],
14476 pointerType: INPUT_TYPE_MOUSE,
14477 srcEvent: ev
14478 });
14479 };
14480
14481 return MouseInput;
14482 }(Input);
14483 /**
14484 * @private
14485 * Combined touch and mouse input
14486 *
14487 * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
14488 * This because touch devices also emit mouse events while doing a touch.
14489 *
14490 * @constructor
14491 * @extends Input
14492 */
14493
14494
14495 var DEDUP_TIMEOUT = 2500;
14496 var DEDUP_DISTANCE = 25;
14497
14498 function setLastTouch(eventData) {
14499 var _eventData$changedPoi = eventData.changedPointers,
14500 touch = _eventData$changedPoi[0];
14501
14502 if (touch.identifier === this.primaryTouch) {
14503 var lastTouch = {
14504 x: touch.clientX,
14505 y: touch.clientY
14506 };
14507 var lts = this.lastTouches;
14508 this.lastTouches.push(lastTouch);
14509
14510 var removeLastTouch = function removeLastTouch() {
14511 var i = lts.indexOf(lastTouch);
14512
14513 if (i > -1) {
14514 lts.splice(i, 1);
14515 }
14516 };
14517
14518 setTimeout(removeLastTouch, DEDUP_TIMEOUT);
14519 }
14520 }
14521
14522 function recordTouches(eventType, eventData) {
14523 if (eventType & INPUT_START) {
14524 this.primaryTouch = eventData.changedPointers[0].identifier;
14525 setLastTouch.call(this, eventData);
14526 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
14527 setLastTouch.call(this, eventData);
14528 }
14529 }
14530
14531 function isSyntheticEvent(eventData) {
14532 var x = eventData.srcEvent.clientX;
14533 var y = eventData.srcEvent.clientY;
14534
14535 for (var i = 0; i < this.lastTouches.length; i++) {
14536 var t = this.lastTouches[i];
14537 var dx = Math.abs(x - t.x);
14538 var dy = Math.abs(y - t.y);
14539
14540 if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
14541 return true;
14542 }
14543 }
14544
14545 return false;
14546 }
14547
14548 var TouchMouseInput =
14549 /*#__PURE__*/
14550 function () {
14551 var TouchMouseInput =
14552 /*#__PURE__*/
14553 function (_Input) {
14554 _inheritsLoose(TouchMouseInput, _Input);
14555
14556 function TouchMouseInput(_manager, callback) {
14557 var _this;
14558
14559 _this = _Input.call(this, _manager, callback) || this;
14560
14561 _this.handler = function (manager, inputEvent, inputData) {
14562 var isTouch = inputData.pointerType === INPUT_TYPE_TOUCH;
14563 var isMouse = inputData.pointerType === INPUT_TYPE_MOUSE;
14564
14565 if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
14566 return;
14567 } // when we're in a touch event, record touches to de-dupe synthetic mouse event
14568
14569
14570 if (isTouch) {
14571 recordTouches.call(_assertThisInitialized(_assertThisInitialized(_this)), inputEvent, inputData);
14572 } else if (isMouse && isSyntheticEvent.call(_assertThisInitialized(_assertThisInitialized(_this)), inputData)) {
14573 return;
14574 }
14575
14576 _this.callback(manager, inputEvent, inputData);
14577 };
14578
14579 _this.touch = new TouchInput(_this.manager, _this.handler);
14580 _this.mouse = new MouseInput(_this.manager, _this.handler);
14581 _this.primaryTouch = null;
14582 _this.lastTouches = [];
14583 return _this;
14584 }
14585 /**
14586 * @private
14587 * handle mouse and touch events
14588 * @param {Hammer} manager
14589 * @param {String} inputEvent
14590 * @param {Object} inputData
14591 */
14592
14593
14594 var _proto = TouchMouseInput.prototype;
14595 /**
14596 * @private
14597 * remove the event listeners
14598 */
14599
14600 _proto.destroy = function destroy() {
14601 this.touch.destroy();
14602 this.mouse.destroy();
14603 };
14604
14605 return TouchMouseInput;
14606 }(Input);
14607
14608 return TouchMouseInput;
14609 }();
14610 /**
14611 * @private
14612 * create new input type manager
14613 * called by the Manager constructor
14614 * @param {Hammer} manager
14615 * @returns {Input}
14616 */
14617
14618
14619 function createInputInstance(manager) {
14620 var Type; // let inputClass = manager.options.inputClass;
14621
14622 var inputClass = manager.options.inputClass;
14623
14624 if (inputClass) {
14625 Type = inputClass;
14626 } else if (SUPPORT_POINTER_EVENTS) {
14627 Type = PointerEventInput;
14628 } else if (SUPPORT_ONLY_TOUCH) {
14629 Type = TouchInput;
14630 } else if (!SUPPORT_TOUCH) {
14631 Type = MouseInput;
14632 } else {
14633 Type = TouchMouseInput;
14634 }
14635
14636 return new Type(manager, inputHandler);
14637 }
14638 /**
14639 * @private
14640 * if the argument is an array, we want to execute the fn on each entry
14641 * if it aint an array we don't want to do a thing.
14642 * this is used by all the methods that accept a single and array argument.
14643 * @param {*|Array} arg
14644 * @param {String} fn
14645 * @param {Object} [context]
14646 * @returns {Boolean}
14647 */
14648
14649
14650 function invokeArrayArg(arg, fn, context) {
14651 if (Array.isArray(arg)) {
14652 each(arg, context[fn], context);
14653 return true;
14654 }
14655
14656 return false;
14657 }
14658
14659 var STATE_POSSIBLE = 1;
14660 var STATE_BEGAN = 2;
14661 var STATE_CHANGED = 4;
14662 var STATE_ENDED = 8;
14663 var STATE_RECOGNIZED = STATE_ENDED;
14664 var STATE_CANCELLED = 16;
14665 var STATE_FAILED = 32;
14666 /**
14667 * @private
14668 * get a unique id
14669 * @returns {number} uniqueId
14670 */
14671
14672 var _uniqueId = 1;
14673
14674 function uniqueId() {
14675 return _uniqueId++;
14676 }
14677 /**
14678 * @private
14679 * get a recognizer by name if it is bound to a manager
14680 * @param {Recognizer|String} otherRecognizer
14681 * @param {Recognizer} recognizer
14682 * @returns {Recognizer}
14683 */
14684
14685
14686 function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
14687 var manager = recognizer.manager;
14688
14689 if (manager) {
14690 return manager.get(otherRecognizer);
14691 }
14692
14693 return otherRecognizer;
14694 }
14695 /**
14696 * @private
14697 * get a usable string, used as event postfix
14698 * @param {constant} state
14699 * @returns {String} state
14700 */
14701
14702
14703 function stateStr(state) {
14704 if (state & STATE_CANCELLED) {
14705 return 'cancel';
14706 } else if (state & STATE_ENDED) {
14707 return 'end';
14708 } else if (state & STATE_CHANGED) {
14709 return 'move';
14710 } else if (state & STATE_BEGAN) {
14711 return 'start';
14712 }
14713
14714 return '';
14715 }
14716 /**
14717 * @private
14718 * Recognizer flow explained; *
14719 * All recognizers have the initial state of POSSIBLE when a input session starts.
14720 * The definition of a input session is from the first input until the last input, with all it's movement in it. *
14721 * Example session for mouse-input: mousedown -> mousemove -> mouseup
14722 *
14723 * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
14724 * which determines with state it should be.
14725 *
14726 * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
14727 * POSSIBLE to give it another change on the next cycle.
14728 *
14729 * Possible
14730 * |
14731 * +-----+---------------+
14732 * | |
14733 * +-----+-----+ |
14734 * | | |
14735 * Failed Cancelled |
14736 * +-------+------+
14737 * | |
14738 * Recognized Began
14739 * |
14740 * Changed
14741 * |
14742 * Ended/Recognized
14743 */
14744
14745 /**
14746 * @private
14747 * Recognizer
14748 * Every recognizer needs to extend from this class.
14749 * @constructor
14750 * @param {Object} options
14751 */
14752
14753
14754 var Recognizer =
14755 /*#__PURE__*/
14756 function () {
14757 function Recognizer(options) {
14758 if (options === void 0) {
14759 options = {};
14760 }
14761
14762 this.options = _extends({
14763 enable: true
14764 }, options);
14765 this.id = uniqueId();
14766 this.manager = null; // default is enable true
14767
14768 this.state = STATE_POSSIBLE;
14769 this.simultaneous = {};
14770 this.requireFail = [];
14771 }
14772 /**
14773 * @private
14774 * set options
14775 * @param {Object} options
14776 * @return {Recognizer}
14777 */
14778
14779
14780 var _proto = Recognizer.prototype;
14781
14782 _proto.set = function set(options) {
14783 assign$1(this.options, options); // also update the touchAction, in case something changed about the directions/enabled state
14784
14785 this.manager && this.manager.touchAction.update();
14786 return this;
14787 };
14788 /**
14789 * @private
14790 * recognize simultaneous with an other recognizer.
14791 * @param {Recognizer} otherRecognizer
14792 * @returns {Recognizer} this
14793 */
14794
14795
14796 _proto.recognizeWith = function recognizeWith(otherRecognizer) {
14797 if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
14798 return this;
14799 }
14800
14801 var simultaneous = this.simultaneous;
14802 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
14803
14804 if (!simultaneous[otherRecognizer.id]) {
14805 simultaneous[otherRecognizer.id] = otherRecognizer;
14806 otherRecognizer.recognizeWith(this);
14807 }
14808
14809 return this;
14810 };
14811 /**
14812 * @private
14813 * drop the simultaneous link. it doesnt remove the link on the other recognizer.
14814 * @param {Recognizer} otherRecognizer
14815 * @returns {Recognizer} this
14816 */
14817
14818
14819 _proto.dropRecognizeWith = function dropRecognizeWith(otherRecognizer) {
14820 if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
14821 return this;
14822 }
14823
14824 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
14825 delete this.simultaneous[otherRecognizer.id];
14826 return this;
14827 };
14828 /**
14829 * @private
14830 * recognizer can only run when an other is failing
14831 * @param {Recognizer} otherRecognizer
14832 * @returns {Recognizer} this
14833 */
14834
14835
14836 _proto.requireFailure = function requireFailure(otherRecognizer) {
14837 if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
14838 return this;
14839 }
14840
14841 var requireFail = this.requireFail;
14842 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
14843
14844 if (inArray(requireFail, otherRecognizer) === -1) {
14845 requireFail.push(otherRecognizer);
14846 otherRecognizer.requireFailure(this);
14847 }
14848
14849 return this;
14850 };
14851 /**
14852 * @private
14853 * drop the requireFailure link. it does not remove the link on the other recognizer.
14854 * @param {Recognizer} otherRecognizer
14855 * @returns {Recognizer} this
14856 */
14857
14858
14859 _proto.dropRequireFailure = function dropRequireFailure(otherRecognizer) {
14860 if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
14861 return this;
14862 }
14863
14864 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
14865 var index = inArray(this.requireFail, otherRecognizer);
14866
14867 if (index > -1) {
14868 this.requireFail.splice(index, 1);
14869 }
14870
14871 return this;
14872 };
14873 /**
14874 * @private
14875 * has require failures boolean
14876 * @returns {boolean}
14877 */
14878
14879
14880 _proto.hasRequireFailures = function hasRequireFailures() {
14881 return this.requireFail.length > 0;
14882 };
14883 /**
14884 * @private
14885 * if the recognizer can recognize simultaneous with an other recognizer
14886 * @param {Recognizer} otherRecognizer
14887 * @returns {Boolean}
14888 */
14889
14890
14891 _proto.canRecognizeWith = function canRecognizeWith(otherRecognizer) {
14892 return !!this.simultaneous[otherRecognizer.id];
14893 };
14894 /**
14895 * @private
14896 * You should use `tryEmit` instead of `emit` directly to check
14897 * that all the needed recognizers has failed before emitting.
14898 * @param {Object} input
14899 */
14900
14901
14902 _proto.emit = function emit(input) {
14903 var self = this;
14904 var state = this.state;
14905
14906 function emit(event) {
14907 self.manager.emit(event, input);
14908 } // 'panstart' and 'panmove'
14909
14910
14911 if (state < STATE_ENDED) {
14912 emit(self.options.event + stateStr(state));
14913 }
14914
14915 emit(self.options.event); // simple 'eventName' events
14916
14917 if (input.additionalEvent) {
14918 // additional event(panleft, panright, pinchin, pinchout...)
14919 emit(input.additionalEvent);
14920 } // panend and pancancel
14921
14922
14923 if (state >= STATE_ENDED) {
14924 emit(self.options.event + stateStr(state));
14925 }
14926 };
14927 /**
14928 * @private
14929 * Check that all the require failure recognizers has failed,
14930 * if true, it emits a gesture event,
14931 * otherwise, setup the state to FAILED.
14932 * @param {Object} input
14933 */
14934
14935
14936 _proto.tryEmit = function tryEmit(input) {
14937 if (this.canEmit()) {
14938 return this.emit(input);
14939 } // it's failing anyway
14940
14941
14942 this.state = STATE_FAILED;
14943 };
14944 /**
14945 * @private
14946 * can we emit?
14947 * @returns {boolean}
14948 */
14949
14950
14951 _proto.canEmit = function canEmit() {
14952 var i = 0;
14953
14954 while (i < this.requireFail.length) {
14955 if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
14956 return false;
14957 }
14958
14959 i++;
14960 }
14961
14962 return true;
14963 };
14964 /**
14965 * @private
14966 * update the recognizer
14967 * @param {Object} inputData
14968 */
14969
14970
14971 _proto.recognize = function recognize(inputData) {
14972 // make a new copy of the inputData
14973 // so we can change the inputData without messing up the other recognizers
14974 var inputDataClone = assign$1({}, inputData); // is is enabled and allow recognizing?
14975
14976 if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
14977 this.reset();
14978 this.state = STATE_FAILED;
14979 return;
14980 } // reset when we've reached the end
14981
14982
14983 if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
14984 this.state = STATE_POSSIBLE;
14985 }
14986
14987 this.state = this.process(inputDataClone); // the recognizer has recognized a gesture
14988 // so trigger an event
14989
14990 if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
14991 this.tryEmit(inputDataClone);
14992 }
14993 };
14994 /**
14995 * @private
14996 * return the state of the recognizer
14997 * the actual recognizing happens in this method
14998 * @virtual
14999 * @param {Object} inputData
15000 * @returns {constant} STATE
15001 */
15002
15003 /* jshint ignore:start */
15004
15005
15006 _proto.process = function process(inputData) {};
15007 /* jshint ignore:end */
15008
15009 /**
15010 * @private
15011 * return the preferred touch-action
15012 * @virtual
15013 * @returns {Array}
15014 */
15015
15016
15017 _proto.getTouchAction = function getTouchAction() {};
15018 /**
15019 * @private
15020 * called when the gesture isn't allowed to recognize
15021 * like when another is being recognized or it is disabled
15022 * @virtual
15023 */
15024
15025
15026 _proto.reset = function reset() {};
15027
15028 return Recognizer;
15029 }();
15030
15031 var defaults = {
15032 /**
15033 * @private
15034 * set if DOM events are being triggered.
15035 * But this is slower and unused by simple implementations, so disabled by default.
15036 * @type {Boolean}
15037 * @default false
15038 */
15039 domEvents: false,
15040
15041 /**
15042 * @private
15043 * The value for the touchAction property/fallback.
15044 * When set to `compute` it will magically set the correct value based on the added recognizers.
15045 * @type {String}
15046 * @default compute
15047 */
15048 touchAction: TOUCH_ACTION_COMPUTE,
15049
15050 /**
15051 * @private
15052 * @type {Boolean}
15053 * @default true
15054 */
15055 enable: true,
15056
15057 /**
15058 * @private
15059 * EXPERIMENTAL FEATURE -- can be removed/changed
15060 * Change the parent input target element.
15061 * If Null, then it is being set the to main element.
15062 * @type {Null|EventTarget}
15063 * @default null
15064 */
15065 inputTarget: null,
15066
15067 /**
15068 * @private
15069 * force an input class
15070 * @type {Null|Function}
15071 * @default null
15072 */
15073 inputClass: null,
15074
15075 /**
15076 * @private
15077 * Default recognizer setup when calling `Hammer()`
15078 * When creating a new Manager these will be skipped.
15079 * @type {Array}
15080 */
15081 preset: [],
15082
15083 /**
15084 * @private
15085 * Some CSS properties can be used to improve the working of Hammer.
15086 * Add them to this method and they will be set when creating a new Manager.
15087 * @namespace
15088 */
15089 cssProps: {
15090 /**
15091 * @private
15092 * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
15093 * @type {String}
15094 * @default 'none'
15095 */
15096 userSelect: "none",
15097
15098 /**
15099 * @private
15100 * Disable the Windows Phone grippers when pressing an element.
15101 * @type {String}
15102 * @default 'none'
15103 */
15104 touchSelect: "none",
15105
15106 /**
15107 * @private
15108 * Disables the default callout shown when you touch and hold a touch target.
15109 * On iOS, when you touch and hold a touch target such as a link, Safari displays
15110 * a callout containing information about the link. This property allows you to disable that callout.
15111 * @type {String}
15112 * @default 'none'
15113 */
15114 touchCallout: "none",
15115
15116 /**
15117 * @private
15118 * Specifies whether zooming is enabled. Used by IE10>
15119 * @type {String}
15120 * @default 'none'
15121 */
15122 contentZooming: "none",
15123
15124 /**
15125 * @private
15126 * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
15127 * @type {String}
15128 * @default 'none'
15129 */
15130 userDrag: "none",
15131
15132 /**
15133 * @private
15134 * Overrides the highlight color shown when the user taps a link or a JavaScript
15135 * clickable element in iOS. This property obeys the alpha value, if specified.
15136 * @type {String}
15137 * @default 'rgba(0,0,0,0)'
15138 */
15139 tapHighlightColor: "rgba(0,0,0,0)"
15140 }
15141 };
15142 var STOP = 1;
15143 var FORCED_STOP = 2;
15144 /**
15145 * @private
15146 * add/remove the css properties as defined in manager.options.cssProps
15147 * @param {Manager} manager
15148 * @param {Boolean} add
15149 */
15150
15151 function toggleCssProps(manager, add) {
15152 var element = manager.element;
15153
15154 if (!element.style) {
15155 return;
15156 }
15157
15158 var prop;
15159 each(manager.options.cssProps, function (value, name) {
15160 prop = prefixed(element.style, name);
15161
15162 if (add) {
15163 manager.oldCssProps[prop] = element.style[prop];
15164 element.style[prop] = value;
15165 } else {
15166 element.style[prop] = manager.oldCssProps[prop] || "";
15167 }
15168 });
15169
15170 if (!add) {
15171 manager.oldCssProps = {};
15172 }
15173 }
15174 /**
15175 * @private
15176 * trigger dom event
15177 * @param {String} event
15178 * @param {Object} data
15179 */
15180
15181
15182 function triggerDomEvent(event, data) {
15183 var gestureEvent = document.createEvent("Event");
15184 gestureEvent.initEvent(event, true, true);
15185 gestureEvent.gesture = data;
15186 data.target.dispatchEvent(gestureEvent);
15187 }
15188 /**
15189 * @private
15190 * Manager
15191 * @param {HTMLElement} element
15192 * @param {Object} [options]
15193 * @constructor
15194 */
15195
15196
15197 var Manager =
15198 /*#__PURE__*/
15199 function () {
15200 function Manager(element, options) {
15201 var _this = this;
15202
15203 this.options = assign$1({}, defaults, options || {});
15204 this.options.inputTarget = this.options.inputTarget || element;
15205 this.handlers = {};
15206 this.session = {};
15207 this.recognizers = [];
15208 this.oldCssProps = {};
15209 this.element = element;
15210 this.input = createInputInstance(this);
15211 this.touchAction = new TouchAction(this, this.options.touchAction);
15212 toggleCssProps(this, true);
15213 each(this.options.recognizers, function (item) {
15214 var recognizer = _this.add(new item[0](item[1]));
15215
15216 item[2] && recognizer.recognizeWith(item[2]);
15217 item[3] && recognizer.requireFailure(item[3]);
15218 }, this);
15219 }
15220 /**
15221 * @private
15222 * set options
15223 * @param {Object} options
15224 * @returns {Manager}
15225 */
15226
15227
15228 var _proto = Manager.prototype;
15229
15230 _proto.set = function set(options) {
15231 assign$1(this.options, options); // Options that need a little more setup
15232
15233 if (options.touchAction) {
15234 this.touchAction.update();
15235 }
15236
15237 if (options.inputTarget) {
15238 // Clean up existing event listeners and reinitialize
15239 this.input.destroy();
15240 this.input.target = options.inputTarget;
15241 this.input.init();
15242 }
15243
15244 return this;
15245 };
15246 /**
15247 * @private
15248 * stop recognizing for this session.
15249 * This session will be discarded, when a new [input]start event is fired.
15250 * When forced, the recognizer cycle is stopped immediately.
15251 * @param {Boolean} [force]
15252 */
15253
15254
15255 _proto.stop = function stop(force) {
15256 this.session.stopped = force ? FORCED_STOP : STOP;
15257 };
15258 /**
15259 * @private
15260 * run the recognizers!
15261 * called by the inputHandler function on every movement of the pointers (touches)
15262 * it walks through all the recognizers and tries to detect the gesture that is being made
15263 * @param {Object} inputData
15264 */
15265
15266
15267 _proto.recognize = function recognize(inputData) {
15268 var session = this.session;
15269
15270 if (session.stopped) {
15271 return;
15272 } // run the touch-action polyfill
15273
15274
15275 this.touchAction.preventDefaults(inputData);
15276 var recognizer;
15277 var recognizers = this.recognizers; // this holds the recognizer that is being recognized.
15278 // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
15279 // if no recognizer is detecting a thing, it is set to `null`
15280
15281 var curRecognizer = session.curRecognizer; // reset when the last recognizer is recognized
15282 // or when we're in a new session
15283
15284 if (!curRecognizer || curRecognizer && curRecognizer.state & STATE_RECOGNIZED) {
15285 session.curRecognizer = null;
15286 curRecognizer = null;
15287 }
15288
15289 var i = 0;
15290
15291 while (i < recognizers.length) {
15292 recognizer = recognizers[i]; // find out if we are allowed try to recognize the input for this one.
15293 // 1. allow if the session is NOT forced stopped (see the .stop() method)
15294 // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
15295 // that is being recognized.
15296 // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
15297 // this can be setup with the `recognizeWith()` method on the recognizer.
15298
15299 if (session.stopped !== FORCED_STOP && ( // 1
15300 !curRecognizer || recognizer === curRecognizer || // 2
15301 recognizer.canRecognizeWith(curRecognizer))) {
15302 // 3
15303 recognizer.recognize(inputData);
15304 } else {
15305 recognizer.reset();
15306 } // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
15307 // current active recognizer. but only if we don't already have an active recognizer
15308
15309
15310 if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
15311 session.curRecognizer = recognizer;
15312 curRecognizer = recognizer;
15313 }
15314
15315 i++;
15316 }
15317 };
15318 /**
15319 * @private
15320 * get a recognizer by its event name.
15321 * @param {Recognizer|String} recognizer
15322 * @returns {Recognizer|Null}
15323 */
15324
15325
15326 _proto.get = function get(recognizer) {
15327 if (recognizer instanceof Recognizer) {
15328 return recognizer;
15329 }
15330
15331 var recognizers = this.recognizers;
15332
15333 for (var i = 0; i < recognizers.length; i++) {
15334 if (recognizers[i].options.event === recognizer) {
15335 return recognizers[i];
15336 }
15337 }
15338
15339 return null;
15340 };
15341 /**
15342 * @private add a recognizer to the manager
15343 * existing recognizers with the same event name will be removed
15344 * @param {Recognizer} recognizer
15345 * @returns {Recognizer|Manager}
15346 */
15347
15348
15349 _proto.add = function add(recognizer) {
15350 if (invokeArrayArg(recognizer, "add", this)) {
15351 return this;
15352 } // remove existing
15353
15354
15355 var existing = this.get(recognizer.options.event);
15356
15357 if (existing) {
15358 this.remove(existing);
15359 }
15360
15361 this.recognizers.push(recognizer);
15362 recognizer.manager = this;
15363 this.touchAction.update();
15364 return recognizer;
15365 };
15366 /**
15367 * @private
15368 * remove a recognizer by name or instance
15369 * @param {Recognizer|String} recognizer
15370 * @returns {Manager}
15371 */
15372
15373
15374 _proto.remove = function remove(recognizer) {
15375 if (invokeArrayArg(recognizer, "remove", this)) {
15376 return this;
15377 }
15378
15379 var targetRecognizer = this.get(recognizer); // let's make sure this recognizer exists
15380
15381 if (recognizer) {
15382 var recognizers = this.recognizers;
15383 var index = inArray(recognizers, targetRecognizer);
15384
15385 if (index !== -1) {
15386 recognizers.splice(index, 1);
15387 this.touchAction.update();
15388 }
15389 }
15390
15391 return this;
15392 };
15393 /**
15394 * @private
15395 * bind event
15396 * @param {String} events
15397 * @param {Function} handler
15398 * @returns {EventEmitter} this
15399 */
15400
15401
15402 _proto.on = function on(events, handler) {
15403 if (events === undefined || handler === undefined) {
15404 return this;
15405 }
15406
15407 var handlers = this.handlers;
15408 each(splitStr(events), function (event) {
15409 handlers[event] = handlers[event] || [];
15410 handlers[event].push(handler);
15411 });
15412 return this;
15413 };
15414 /**
15415 * @private unbind event, leave emit blank to remove all handlers
15416 * @param {String} events
15417 * @param {Function} [handler]
15418 * @returns {EventEmitter} this
15419 */
15420
15421
15422 _proto.off = function off(events, handler) {
15423 if (events === undefined) {
15424 return this;
15425 }
15426
15427 var handlers = this.handlers;
15428 each(splitStr(events), function (event) {
15429 if (!handler) {
15430 delete handlers[event];
15431 } else {
15432 handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
15433 }
15434 });
15435 return this;
15436 };
15437 /**
15438 * @private emit event to the listeners
15439 * @param {String} event
15440 * @param {Object} data
15441 */
15442
15443
15444 _proto.emit = function emit(event, data) {
15445 // we also want to trigger dom events
15446 if (this.options.domEvents) {
15447 triggerDomEvent(event, data);
15448 } // no handlers, so skip it all
15449
15450
15451 var handlers = this.handlers[event] && this.handlers[event].slice();
15452
15453 if (!handlers || !handlers.length) {
15454 return;
15455 }
15456
15457 data.type = event;
15458
15459 data.preventDefault = function () {
15460 data.srcEvent.preventDefault();
15461 };
15462
15463 var i = 0;
15464
15465 while (i < handlers.length) {
15466 handlers[i](data);
15467 i++;
15468 }
15469 };
15470 /**
15471 * @private
15472 * destroy the manager and unbinds all events
15473 * it doesn't unbind dom events, that is the user own responsibility
15474 */
15475
15476
15477 _proto.destroy = function destroy() {
15478 this.element && toggleCssProps(this, false);
15479 this.handlers = {};
15480 this.session = {};
15481 this.input.destroy();
15482 this.element = null;
15483 };
15484
15485 return Manager;
15486 }();
15487
15488 var SINGLE_TOUCH_INPUT_MAP = {
15489 touchstart: INPUT_START,
15490 touchmove: INPUT_MOVE,
15491 touchend: INPUT_END,
15492 touchcancel: INPUT_CANCEL
15493 };
15494 var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
15495 var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
15496 /**
15497 * @private
15498 * Touch events input
15499 * @constructor
15500 * @extends Input
15501 */
15502
15503 var SingleTouchInput =
15504 /*#__PURE__*/
15505 function (_Input) {
15506 _inheritsLoose(SingleTouchInput, _Input);
15507
15508 function SingleTouchInput() {
15509 var _this;
15510
15511 var proto = SingleTouchInput.prototype;
15512 proto.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
15513 proto.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
15514 _this = _Input.apply(this, arguments) || this;
15515 _this.started = false;
15516 return _this;
15517 }
15518
15519 var _proto = SingleTouchInput.prototype;
15520
15521 _proto.handler = function handler(ev) {
15522 var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; // should we handle the touch events?
15523
15524 if (type === INPUT_START) {
15525 this.started = true;
15526 }
15527
15528 if (!this.started) {
15529 return;
15530 }
15531
15532 var touches = normalizeSingleTouches.call(this, ev, type); // when done, reset the started state
15533
15534 if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
15535 this.started = false;
15536 }
15537
15538 this.callback(this.manager, type, {
15539 pointers: touches[0],
15540 changedPointers: touches[1],
15541 pointerType: INPUT_TYPE_TOUCH,
15542 srcEvent: ev
15543 });
15544 };
15545
15546 return SingleTouchInput;
15547 }(Input);
15548
15549 function normalizeSingleTouches(ev, type) {
15550 var all = toArray$1(ev.touches);
15551 var changed = toArray$1(ev.changedTouches);
15552
15553 if (type & (INPUT_END | INPUT_CANCEL)) {
15554 all = uniqueArray(all.concat(changed), 'identifier', true);
15555 }
15556
15557 return [all, changed];
15558 }
15559 /**
15560 * @private
15561 * This recognizer is just used as a base for the simple attribute recognizers.
15562 * @constructor
15563 * @extends Recognizer
15564 */
15565
15566
15567 var AttrRecognizer =
15568 /*#__PURE__*/
15569 function (_Recognizer) {
15570 _inheritsLoose(AttrRecognizer, _Recognizer);
15571
15572 function AttrRecognizer(options) {
15573 if (options === void 0) {
15574 options = {};
15575 }
15576
15577 return _Recognizer.call(this, _extends({
15578 pointers: 1
15579 }, options)) || this;
15580 }
15581 /**
15582 * @private
15583 * Used to check if it the recognizer receives valid input, like input.distance > 10.
15584 * @memberof AttrRecognizer
15585 * @param {Object} input
15586 * @returns {Boolean} recognized
15587 */
15588
15589
15590 var _proto = AttrRecognizer.prototype;
15591
15592 _proto.attrTest = function attrTest(input) {
15593 var optionPointers = this.options.pointers;
15594 return optionPointers === 0 || input.pointers.length === optionPointers;
15595 };
15596 /**
15597 * @private
15598 * Process the input and return the state for the recognizer
15599 * @memberof AttrRecognizer
15600 * @param {Object} input
15601 * @returns {*} State
15602 */
15603
15604
15605 _proto.process = function process(input) {
15606 var state = this.state;
15607 var eventType = input.eventType;
15608 var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
15609 var isValid = this.attrTest(input); // on cancel input and we've recognized before, return STATE_CANCELLED
15610
15611 if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
15612 return state | STATE_CANCELLED;
15613 } else if (isRecognized || isValid) {
15614 if (eventType & INPUT_END) {
15615 return state | STATE_ENDED;
15616 } else if (!(state & STATE_BEGAN)) {
15617 return STATE_BEGAN;
15618 }
15619
15620 return state | STATE_CHANGED;
15621 }
15622
15623 return STATE_FAILED;
15624 };
15625
15626 return AttrRecognizer;
15627 }(Recognizer);
15628 /**
15629 * @private
15630 * A tap is recognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
15631 * between the given interval and position. The delay option can be used to recognize multi-taps without firing
15632 * a single tap.
15633 *
15634 * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
15635 * multi-taps being recognized.
15636 * @constructor
15637 * @extends Recognizer
15638 */
15639
15640
15641 var TapRecognizer =
15642 /*#__PURE__*/
15643 function (_Recognizer) {
15644 _inheritsLoose(TapRecognizer, _Recognizer);
15645
15646 function TapRecognizer(options) {
15647 var _this;
15648
15649 if (options === void 0) {
15650 options = {};
15651 }
15652
15653 _this = _Recognizer.call(this, _extends({
15654 event: 'tap',
15655 pointers: 1,
15656 taps: 1,
15657 interval: 300,
15658 // max time between the multi-tap taps
15659 time: 250,
15660 // max time of the pointer to be down (like finger on the screen)
15661 threshold: 9,
15662 // a minimal movement is ok, but keep it low
15663 posThreshold: 10
15664 }, options)) || this; // previous time and center,
15665 // used for tap counting
15666
15667 _this.pTime = false;
15668 _this.pCenter = false;
15669 _this._timer = null;
15670 _this._input = null;
15671 _this.count = 0;
15672 return _this;
15673 }
15674
15675 var _proto = TapRecognizer.prototype;
15676
15677 _proto.getTouchAction = function getTouchAction() {
15678 return [TOUCH_ACTION_MANIPULATION];
15679 };
15680
15681 _proto.process = function process(input) {
15682 var _this2 = this;
15683
15684 var options = this.options;
15685 var validPointers = input.pointers.length === options.pointers;
15686 var validMovement = input.distance < options.threshold;
15687 var validTouchTime = input.deltaTime < options.time;
15688 this.reset();
15689
15690 if (input.eventType & INPUT_START && this.count === 0) {
15691 return this.failTimeout();
15692 } // we only allow little movement
15693 // and we've reached an end event, so a tap is possible
15694
15695
15696 if (validMovement && validTouchTime && validPointers) {
15697 if (input.eventType !== INPUT_END) {
15698 return this.failTimeout();
15699 }
15700
15701 var validInterval = this.pTime ? input.timeStamp - this.pTime < options.interval : true;
15702 var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
15703 this.pTime = input.timeStamp;
15704 this.pCenter = input.center;
15705
15706 if (!validMultiTap || !validInterval) {
15707 this.count = 1;
15708 } else {
15709 this.count += 1;
15710 }
15711
15712 this._input = input; // if tap count matches we have recognized it,
15713 // else it has began recognizing...
15714
15715 var tapCount = this.count % options.taps;
15716
15717 if (tapCount === 0) {
15718 // no failing requirements, immediately trigger the tap event
15719 // or wait as long as the multitap interval to trigger
15720 if (!this.hasRequireFailures()) {
15721 return STATE_RECOGNIZED;
15722 } else {
15723 this._timer = setTimeout(function () {
15724 _this2.state = STATE_RECOGNIZED;
15725
15726 _this2.tryEmit();
15727 }, options.interval);
15728 return STATE_BEGAN;
15729 }
15730 }
15731 }
15732
15733 return STATE_FAILED;
15734 };
15735
15736 _proto.failTimeout = function failTimeout() {
15737 var _this3 = this;
15738
15739 this._timer = setTimeout(function () {
15740 _this3.state = STATE_FAILED;
15741 }, this.options.interval);
15742 return STATE_FAILED;
15743 };
15744
15745 _proto.reset = function reset() {
15746 clearTimeout(this._timer);
15747 };
15748
15749 _proto.emit = function emit() {
15750 if (this.state === STATE_RECOGNIZED) {
15751 this._input.tapCount = this.count;
15752 this.manager.emit(this.options.event, this._input);
15753 }
15754 };
15755
15756 return TapRecognizer;
15757 }(Recognizer);
15758 /**
15759 * @private
15760 * direction cons to string
15761 * @param {constant} direction
15762 * @returns {String}
15763 */
15764
15765
15766 function directionStr(direction) {
15767 if (direction === DIRECTION_DOWN) {
15768 return 'down';
15769 } else if (direction === DIRECTION_UP) {
15770 return 'up';
15771 } else if (direction === DIRECTION_LEFT) {
15772 return 'left';
15773 } else if (direction === DIRECTION_RIGHT) {
15774 return 'right';
15775 }
15776
15777 return '';
15778 }
15779 /**
15780 * @private
15781 * Pan
15782 * Recognized when the pointer is down and moved in the allowed direction.
15783 * @constructor
15784 * @extends AttrRecognizer
15785 */
15786
15787
15788 var PanRecognizer =
15789 /*#__PURE__*/
15790 function (_AttrRecognizer) {
15791 _inheritsLoose(PanRecognizer, _AttrRecognizer);
15792
15793 function PanRecognizer(options) {
15794 var _this;
15795
15796 if (options === void 0) {
15797 options = {};
15798 }
15799
15800 _this = _AttrRecognizer.call(this, _extends({
15801 event: 'pan',
15802 threshold: 10,
15803 pointers: 1,
15804 direction: DIRECTION_ALL
15805 }, options)) || this;
15806 _this.pX = null;
15807 _this.pY = null;
15808 return _this;
15809 }
15810
15811 var _proto = PanRecognizer.prototype;
15812
15813 _proto.getTouchAction = function getTouchAction() {
15814 var direction = this.options.direction;
15815 var actions = [];
15816
15817 if (direction & DIRECTION_HORIZONTAL) {
15818 actions.push(TOUCH_ACTION_PAN_Y);
15819 }
15820
15821 if (direction & DIRECTION_VERTICAL) {
15822 actions.push(TOUCH_ACTION_PAN_X);
15823 }
15824
15825 return actions;
15826 };
15827
15828 _proto.directionTest = function directionTest(input) {
15829 var options = this.options;
15830 var hasMoved = true;
15831 var distance = input.distance;
15832 var direction = input.direction;
15833 var x = input.deltaX;
15834 var y = input.deltaY; // lock to axis?
15835
15836 if (!(direction & options.direction)) {
15837 if (options.direction & DIRECTION_HORIZONTAL) {
15838 direction = x === 0 ? DIRECTION_NONE : x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
15839 hasMoved = x !== this.pX;
15840 distance = Math.abs(input.deltaX);
15841 } else {
15842 direction = y === 0 ? DIRECTION_NONE : y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
15843 hasMoved = y !== this.pY;
15844 distance = Math.abs(input.deltaY);
15845 }
15846 }
15847
15848 input.direction = direction;
15849 return hasMoved && distance > options.threshold && direction & options.direction;
15850 };
15851
15852 _proto.attrTest = function attrTest(input) {
15853 return AttrRecognizer.prototype.attrTest.call(this, input) && ( // replace with a super call
15854 this.state & STATE_BEGAN || !(this.state & STATE_BEGAN) && this.directionTest(input));
15855 };
15856
15857 _proto.emit = function emit(input) {
15858 this.pX = input.deltaX;
15859 this.pY = input.deltaY;
15860 var direction = directionStr(input.direction);
15861
15862 if (direction) {
15863 input.additionalEvent = this.options.event + direction;
15864 }
15865
15866 _AttrRecognizer.prototype.emit.call(this, input);
15867 };
15868
15869 return PanRecognizer;
15870 }(AttrRecognizer);
15871 /**
15872 * @private
15873 * Swipe
15874 * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
15875 * @constructor
15876 * @extends AttrRecognizer
15877 */
15878
15879
15880 var SwipeRecognizer =
15881 /*#__PURE__*/
15882 function (_AttrRecognizer) {
15883 _inheritsLoose(SwipeRecognizer, _AttrRecognizer);
15884
15885 function SwipeRecognizer(options) {
15886 if (options === void 0) {
15887 options = {};
15888 }
15889
15890 return _AttrRecognizer.call(this, _extends({
15891 event: 'swipe',
15892 threshold: 10,
15893 velocity: 0.3,
15894 direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
15895 pointers: 1
15896 }, options)) || this;
15897 }
15898
15899 var _proto = SwipeRecognizer.prototype;
15900
15901 _proto.getTouchAction = function getTouchAction() {
15902 return PanRecognizer.prototype.getTouchAction.call(this);
15903 };
15904
15905 _proto.attrTest = function attrTest(input) {
15906 var direction = this.options.direction;
15907 var velocity;
15908
15909 if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
15910 velocity = input.overallVelocity;
15911 } else if (direction & DIRECTION_HORIZONTAL) {
15912 velocity = input.overallVelocityX;
15913 } else if (direction & DIRECTION_VERTICAL) {
15914 velocity = input.overallVelocityY;
15915 }
15916
15917 return _AttrRecognizer.prototype.attrTest.call(this, input) && direction & input.offsetDirection && input.distance > this.options.threshold && input.maxPointers === this.options.pointers && abs$1(velocity) > this.options.velocity && input.eventType & INPUT_END;
15918 };
15919
15920 _proto.emit = function emit(input) {
15921 var direction = directionStr(input.offsetDirection);
15922
15923 if (direction) {
15924 this.manager.emit(this.options.event + direction, input);
15925 }
15926
15927 this.manager.emit(this.options.event, input);
15928 };
15929
15930 return SwipeRecognizer;
15931 }(AttrRecognizer);
15932 /**
15933 * @private
15934 * Pinch
15935 * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
15936 * @constructor
15937 * @extends AttrRecognizer
15938 */
15939
15940
15941 var PinchRecognizer =
15942 /*#__PURE__*/
15943 function (_AttrRecognizer) {
15944 _inheritsLoose(PinchRecognizer, _AttrRecognizer);
15945
15946 function PinchRecognizer(options) {
15947 if (options === void 0) {
15948 options = {};
15949 }
15950
15951 return _AttrRecognizer.call(this, _extends({
15952 event: 'pinch',
15953 threshold: 0,
15954 pointers: 2
15955 }, options)) || this;
15956 }
15957
15958 var _proto = PinchRecognizer.prototype;
15959
15960 _proto.getTouchAction = function getTouchAction() {
15961 return [TOUCH_ACTION_NONE];
15962 };
15963
15964 _proto.attrTest = function attrTest(input) {
15965 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
15966 };
15967
15968 _proto.emit = function emit(input) {
15969 if (input.scale !== 1) {
15970 var inOut = input.scale < 1 ? 'in' : 'out';
15971 input.additionalEvent = this.options.event + inOut;
15972 }
15973
15974 _AttrRecognizer.prototype.emit.call(this, input);
15975 };
15976
15977 return PinchRecognizer;
15978 }(AttrRecognizer);
15979 /**
15980 * @private
15981 * Rotate
15982 * Recognized when two or more pointer are moving in a circular motion.
15983 * @constructor
15984 * @extends AttrRecognizer
15985 */
15986
15987
15988 var RotateRecognizer =
15989 /*#__PURE__*/
15990 function (_AttrRecognizer) {
15991 _inheritsLoose(RotateRecognizer, _AttrRecognizer);
15992
15993 function RotateRecognizer(options) {
15994 if (options === void 0) {
15995 options = {};
15996 }
15997
15998 return _AttrRecognizer.call(this, _extends({
15999 event: 'rotate',
16000 threshold: 0,
16001 pointers: 2
16002 }, options)) || this;
16003 }
16004
16005 var _proto = RotateRecognizer.prototype;
16006
16007 _proto.getTouchAction = function getTouchAction() {
16008 return [TOUCH_ACTION_NONE];
16009 };
16010
16011 _proto.attrTest = function attrTest(input) {
16012 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
16013 };
16014
16015 return RotateRecognizer;
16016 }(AttrRecognizer);
16017 /**
16018 * @private
16019 * Press
16020 * Recognized when the pointer is down for x ms without any movement.
16021 * @constructor
16022 * @extends Recognizer
16023 */
16024
16025
16026 var PressRecognizer =
16027 /*#__PURE__*/
16028 function (_Recognizer) {
16029 _inheritsLoose(PressRecognizer, _Recognizer);
16030
16031 function PressRecognizer(options) {
16032 var _this;
16033
16034 if (options === void 0) {
16035 options = {};
16036 }
16037
16038 _this = _Recognizer.call(this, _extends({
16039 event: 'press',
16040 pointers: 1,
16041 time: 251,
16042 // minimal time of the pointer to be pressed
16043 threshold: 9
16044 }, options)) || this;
16045 _this._timer = null;
16046 _this._input = null;
16047 return _this;
16048 }
16049
16050 var _proto = PressRecognizer.prototype;
16051
16052 _proto.getTouchAction = function getTouchAction() {
16053 return [TOUCH_ACTION_AUTO];
16054 };
16055
16056 _proto.process = function process(input) {
16057 var _this2 = this;
16058
16059 var options = this.options;
16060 var validPointers = input.pointers.length === options.pointers;
16061 var validMovement = input.distance < options.threshold;
16062 var validTime = input.deltaTime > options.time;
16063 this._input = input; // we only allow little movement
16064 // and we've reached an end event, so a tap is possible
16065
16066 if (!validMovement || !validPointers || input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime) {
16067 this.reset();
16068 } else if (input.eventType & INPUT_START) {
16069 this.reset();
16070 this._timer = setTimeout(function () {
16071 _this2.state = STATE_RECOGNIZED;
16072
16073 _this2.tryEmit();
16074 }, options.time);
16075 } else if (input.eventType & INPUT_END) {
16076 return STATE_RECOGNIZED;
16077 }
16078
16079 return STATE_FAILED;
16080 };
16081
16082 _proto.reset = function reset() {
16083 clearTimeout(this._timer);
16084 };
16085
16086 _proto.emit = function emit(input) {
16087 if (this.state !== STATE_RECOGNIZED) {
16088 return;
16089 }
16090
16091 if (input && input.eventType & INPUT_END) {
16092 this.manager.emit(this.options.event + "up", input);
16093 } else {
16094 this._input.timeStamp = now();
16095 this.manager.emit(this.options.event, this._input);
16096 }
16097 };
16098
16099 return PressRecognizer;
16100 }(Recognizer);
16101 /**
16102 * @private
16103 * wrap a method with a deprecation warning and stack trace
16104 * @param {Function} method
16105 * @param {String} name
16106 * @param {String} message
16107 * @returns {Function} A new function wrapping the supplied method.
16108 */
16109
16110
16111 function deprecate(method, name, message) {
16112 var deprecationMessage = "DEPRECATED METHOD: " + name + "\n" + message + " AT \n";
16113 return function () {
16114 var e = new Error('get-stack-trace');
16115 var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '').replace(/^\s+at\s+/gm, '').replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
16116 var log = window.console && (window.console.warn || window.console.log);
16117
16118 if (log) {
16119 log.call(window.console, deprecationMessage, stack);
16120 }
16121
16122 return method.apply(this, arguments);
16123 };
16124 }
16125 /**
16126 * @private
16127 * extend object.
16128 * means that properties in dest will be overwritten by the ones in src.
16129 * @param {Object} dest
16130 * @param {Object} src
16131 * @param {Boolean} [merge=false]
16132 * @returns {Object} dest
16133 */
16134
16135
16136 var extend$1 = deprecate(function (dest, src, merge) {
16137 var keys = Object.keys(src);
16138 var i = 0;
16139
16140 while (i < keys.length) {
16141 if (!merge || merge && dest[keys[i]] === undefined) {
16142 dest[keys[i]] = src[keys[i]];
16143 }
16144
16145 i++;
16146 }
16147
16148 return dest;
16149 }, 'extend', 'Use `assign`.');
16150 /**
16151 * @private
16152 * merge the values from src in the dest.
16153 * means that properties that exist in dest will not be overwritten by src
16154 * @param {Object} dest
16155 * @param {Object} src
16156 * @returns {Object} dest
16157 */
16158
16159 var merge$1 = deprecate(function (dest, src) {
16160 return extend$1(dest, src, true);
16161 }, 'merge', 'Use `assign`.');
16162 /**
16163 * @private
16164 * simple class inheritance
16165 * @param {Function} child
16166 * @param {Function} base
16167 * @param {Object} [properties]
16168 */
16169
16170 function inherit(child, base, properties) {
16171 var baseP = base.prototype;
16172 var childP;
16173 childP = child.prototype = Object.create(baseP);
16174 childP.constructor = child;
16175 childP._super = baseP;
16176
16177 if (properties) {
16178 assign$1(childP, properties);
16179 }
16180 }
16181 /**
16182 * @private
16183 * simple function bind
16184 * @param {Function} fn
16185 * @param {Object} context
16186 * @returns {Function}
16187 */
16188
16189
16190 function bindFn(fn, context) {
16191 return function boundFn() {
16192 return fn.apply(context, arguments);
16193 };
16194 }
16195 /**
16196 * @private
16197 * Simple way to create a manager with a default set of recognizers.
16198 * @param {HTMLElement} element
16199 * @param {Object} [options]
16200 * @constructor
16201 */
16202
16203
16204 var Hammer =
16205 /*#__PURE__*/
16206 function () {
16207 var Hammer =
16208 /**
16209 * @private
16210 * @const {string}
16211 */
16212 function Hammer(element, options) {
16213 if (options === void 0) {
16214 options = {};
16215 }
16216
16217 return new Manager(element, _extends({
16218 recognizers: [// RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
16219 [RotateRecognizer, {
16220 enable: false
16221 }], [PinchRecognizer, {
16222 enable: false
16223 }, ['rotate']], [SwipeRecognizer, {
16224 direction: DIRECTION_HORIZONTAL
16225 }], [PanRecognizer, {
16226 direction: DIRECTION_HORIZONTAL
16227 }, ['swipe']], [TapRecognizer], [TapRecognizer, {
16228 event: 'doubletap',
16229 taps: 2
16230 }, ['tap']], [PressRecognizer]]
16231 }, options));
16232 };
16233
16234 Hammer.VERSION = "2.0.15";
16235 Hammer.DIRECTION_ALL = DIRECTION_ALL;
16236 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
16237 Hammer.DIRECTION_LEFT = DIRECTION_LEFT;
16238 Hammer.DIRECTION_RIGHT = DIRECTION_RIGHT;
16239 Hammer.DIRECTION_UP = DIRECTION_UP;
16240 Hammer.DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL;
16241 Hammer.DIRECTION_VERTICAL = DIRECTION_VERTICAL;
16242 Hammer.DIRECTION_NONE = DIRECTION_NONE;
16243 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
16244 Hammer.INPUT_START = INPUT_START;
16245 Hammer.INPUT_MOVE = INPUT_MOVE;
16246 Hammer.INPUT_END = INPUT_END;
16247 Hammer.INPUT_CANCEL = INPUT_CANCEL;
16248 Hammer.STATE_POSSIBLE = STATE_POSSIBLE;
16249 Hammer.STATE_BEGAN = STATE_BEGAN;
16250 Hammer.STATE_CHANGED = STATE_CHANGED;
16251 Hammer.STATE_ENDED = STATE_ENDED;
16252 Hammer.STATE_RECOGNIZED = STATE_RECOGNIZED;
16253 Hammer.STATE_CANCELLED = STATE_CANCELLED;
16254 Hammer.STATE_FAILED = STATE_FAILED;
16255 Hammer.Manager = Manager;
16256 Hammer.Input = Input;
16257 Hammer.TouchAction = TouchAction;
16258 Hammer.TouchInput = TouchInput;
16259 Hammer.MouseInput = MouseInput;
16260 Hammer.PointerEventInput = PointerEventInput;
16261 Hammer.TouchMouseInput = TouchMouseInput;
16262 Hammer.SingleTouchInput = SingleTouchInput;
16263 Hammer.Recognizer = Recognizer;
16264 Hammer.AttrRecognizer = AttrRecognizer;
16265 Hammer.Tap = TapRecognizer;
16266 Hammer.Pan = PanRecognizer;
16267 Hammer.Swipe = SwipeRecognizer;
16268 Hammer.Pinch = PinchRecognizer;
16269 Hammer.Rotate = RotateRecognizer;
16270 Hammer.Press = PressRecognizer;
16271 Hammer.on = addEventListeners;
16272 Hammer.off = removeEventListeners;
16273 Hammer.each = each;
16274 Hammer.merge = merge$1;
16275 Hammer.extend = extend$1;
16276 Hammer.bindFn = bindFn;
16277 Hammer.assign = assign$1;
16278 Hammer.inherit = inherit;
16279 Hammer.bindFn = bindFn;
16280 Hammer.prefixed = prefixed;
16281 Hammer.toArray = toArray$1;
16282 Hammer.inArray = inArray;
16283 Hammer.uniqueArray = uniqueArray;
16284 Hammer.splitStr = splitStr;
16285 Hammer.boolOrFn = boolOrFn;
16286 Hammer.hasParent = hasParent$1;
16287 Hammer.addEventListeners = addEventListeners;
16288 Hammer.removeEventListeners = removeEventListeners;
16289 Hammer.defaults = defaults;
16290 return Hammer;
16291 }();
16292
16293 var hammer = createCommonjsModule(function (module) {
16294 /**
16295 * Setup a mock hammer.js object, for unit testing.
16296 *
16297 * Inspiration: https://github.com/uber/deck.gl/pull/658
16298 *
16299 * @returns {{on: noop, off: noop, destroy: noop, emit: noop, get: get}}
16300 */
16301 function hammerMock() {
16302 var noop = function noop() {};
16303
16304 return {
16305 on: noop,
16306 off: noop,
16307 destroy: noop,
16308 emit: noop,
16309 get: function get(m) {
16310 //eslint-disable-line no-unused-vars
16311 return {
16312 set: noop
16313 };
16314 }
16315 };
16316 }
16317
16318 if (typeof window !== 'undefined') {
16319 var Hammer$1 = window['Hammer'] || Hammer;
16320 module.exports = Hammer$1;
16321 } else {
16322 module.exports = function () {
16323 // hammer.js is only available in a browser, not in node.js. Replacing it with a mock object.
16324 return hammerMock();
16325 };
16326 }
16327 });
16328
16329 var hammer$1 = /*#__PURE__*/Object.freeze({
16330 __proto__: null,
16331 'default': hammer,
16332 __moduleExports: hammer
16333 });
16334
16335 getCjsExportFromNamespace(Activator);
16336
16337 /**
16338 * Turn an element into an clickToUse element.
16339 * When not active, the element has a transparent overlay. When the overlay is
16340 * clicked, the mode is changed to active.
16341 * When active, the element is displayed with a blue border around it, and
16342 * the interactive contents of the element can be used. When clicked outside
16343 * the element, the elements mode is changed to inactive.
16344 * @param {Element} container
16345 * @constructor Activator
16346 */
16347
16348 function Activator$1(container) {
16349 var _this = this;
16350
16351 this.active = false;
16352 this.dom = {
16353 container: container
16354 };
16355 this.dom.overlay = document.createElement('div');
16356 this.dom.overlay.className = 'vis-overlay';
16357 this.dom.container.appendChild(this.dom.overlay);
16358 this.hammer = hammer(this.dom.overlay);
16359 this.hammer.on('tap', this._onTapOverlay.bind(this)); // block all touch events (except tap)
16360
16361 var events = ['tap', 'doubletap', 'press', 'pinch', 'pan', 'panstart', 'panmove', 'panend'];
16362 events.forEach(function (event) {
16363 _this.hammer.on(event, function (event) {
16364 event.srcEvent.stopPropagation();
16365 });
16366 }); // attach a click event to the window, in order to deactivate when clicking outside the timeline
16367
16368 if (document && document.body) {
16369 this.onClick = function (event) {
16370 if (!_hasParent(event.target, container)) {
16371 _this.deactivate();
16372 }
16373 };
16374
16375 document.body.addEventListener('click', this.onClick);
16376 }
16377
16378 if (this.keycharm !== undefined) {
16379 this.keycharm.destroy();
16380 }
16381
16382 this.keycharm = keycharm(); // keycharm listener only bounded when active)
16383
16384 this.escListener = this.deactivate.bind(this);
16385 } // turn into an event emitter
16386
16387
16388 componentEmitter(Activator$1.prototype); // The currently active activator
16389
16390 Activator$1.current = null;
16391 /**
16392 * Destroy the activator. Cleans up all created DOM and event listeners
16393 */
16394
16395 Activator$1.prototype.destroy = function () {
16396 this.deactivate(); // remove dom
16397
16398 this.dom.overlay.parentNode.removeChild(this.dom.overlay); // remove global event listener
16399
16400 if (this.onClick) {
16401 document.body.removeEventListener('click', this.onClick);
16402 } // remove keycharm
16403
16404
16405 if (this.keycharm !== undefined) {
16406 this.keycharm.destroy();
16407 }
16408
16409 this.keycharm = null; // cleanup hammer instances
16410
16411 this.hammer.destroy();
16412 this.hammer = null; // FIXME: cleaning up hammer instances doesn't work (Timeline not removed from memory)
16413 };
16414 /**
16415 * Activate the element
16416 * Overlay is hidden, element is decorated with a blue shadow border
16417 */
16418
16419
16420 Activator$1.prototype.activate = function () {
16421 // we allow only one active activator at a time
16422 if (Activator$1.current) {
16423 Activator$1.current.deactivate();
16424 }
16425
16426 Activator$1.current = this;
16427 this.active = true;
16428 this.dom.overlay.style.display = 'none';
16429 util.addClassName(this.dom.container, 'vis-active');
16430 this.emit('change');
16431 this.emit('activate'); // ugly hack: bind ESC after emitting the events, as the Network rebinds all
16432 // keyboard events on a 'change' event
16433
16434 this.keycharm.bind('esc', this.escListener);
16435 };
16436 /**
16437 * Deactivate the element
16438 * Overlay is displayed on top of the element
16439 */
16440
16441
16442 Activator$1.prototype.deactivate = function () {
16443 this.active = false;
16444 this.dom.overlay.style.display = 'block';
16445 util.removeClassName(this.dom.container, 'vis-active');
16446 this.keycharm.unbind('esc', this.escListener);
16447 this.emit('change');
16448 this.emit('deactivate');
16449 };
16450 /**
16451 * Handle a tap event: activate the container
16452 * @param {Event} event The event
16453 * @private
16454 */
16455
16456
16457 Activator$1.prototype._onTapOverlay = function (event) {
16458 // activate the container
16459 this.activate();
16460 event.srcEvent.stopPropagation();
16461 };
16462 /**
16463 * Test whether the element has the requested parent element somewhere in
16464 * its chain of parent nodes.
16465 * @param {HTMLElement} element
16466 * @param {HTMLElement} parent
16467 * @returns {boolean} Returns true when the parent is found somewhere in the
16468 * chain of parent nodes.
16469 * @private
16470 */
16471
16472
16473 function _hasParent(element, parent) {
16474 while (element) {
16475 if (element === parent) {
16476 return true;
16477 }
16478
16479 element = element.parentNode;
16480 }
16481
16482 return false;
16483 }
16484
16485 var Activator_1 = Activator$1;
16486
16487 var locales = createCommonjsModule(function (module, exports) {
16488 // English
16489 exports['en'] = {
16490 edit: 'Edit',
16491 del: 'Delete selected',
16492 back: 'Back',
16493 addNode: 'Add Node',
16494 addEdge: 'Add Edge',
16495 editNode: 'Edit Node',
16496 editEdge: 'Edit Edge',
16497 addDescription: 'Click in an empty space to place a new node.',
16498 edgeDescription: 'Click on a node and drag the edge to another node to connect them.',
16499 editEdgeDescription: 'Click on the control points and drag them to a node to connect to it.',
16500 createEdgeError: 'Cannot link edges to a cluster.',
16501 deleteClusterError: 'Clusters cannot be deleted.',
16502 editClusterError: 'Clusters cannot be edited.'
16503 };
16504 exports['en_EN'] = exports['en'];
16505 exports['en_US'] = exports['en']; // German
16506
16507 exports['de'] = {
16508 edit: 'Editieren',
16509 del: "L\xF6sche Auswahl",
16510 back: "Zur\xFCck",
16511 addNode: "Knoten hinzuf\xFCgen",
16512 addEdge: "Kante hinzuf\xFCgen",
16513 editNode: 'Knoten editieren',
16514 editEdge: 'Kante editieren',
16515 addDescription: 'Klicke auf eine freie Stelle, um einen neuen Knoten zu plazieren.',
16516 edgeDescription: 'Klicke auf einen Knoten und ziehe die Kante zu einem anderen Knoten, um diese zu verbinden.',
16517 editEdgeDescription: 'Klicke auf die Verbindungspunkte und ziehe diese auf einen Knoten, um sie zu verbinden.',
16518 createEdgeError: "Es ist nicht m\xF6glich, Kanten mit Clustern zu verbinden.",
16519 deleteClusterError: "Cluster k\xF6nnen nicht gel\xF6scht werden.",
16520 editClusterError: "Cluster k\xF6nnen nicht editiert werden."
16521 };
16522 exports['de_DE'] = exports['de']; // Spanish
16523
16524 exports['es'] = {
16525 edit: 'Editar',
16526 del: "Eliminar selecci\xF3n",
16527 back: "Atr\xE1s",
16528 addNode: "A\xF1adir nodo",
16529 addEdge: "A\xF1adir arista",
16530 editNode: 'Editar nodo',
16531 editEdge: 'Editar arista',
16532 addDescription: "Haga clic en un lugar vac\xEDo para colocar un nuevo nodo.",
16533 edgeDescription: 'Haga clic en un nodo y arrastre la arista hacia otro nodo para conectarlos.',
16534 editEdgeDescription: 'Haga clic en un punto de control y arrastrelo a un nodo para conectarlo.',
16535 createEdgeError: 'No se puede conectar una arista a un grupo.',
16536 deleteClusterError: 'No es posible eliminar grupos.',
16537 editClusterError: 'No es posible editar grupos.'
16538 };
16539 exports['es_ES'] = exports['es']; //Italiano
16540
16541 exports['it'] = {
16542 edit: 'Modifica',
16543 del: 'Cancella la selezione',
16544 back: 'Indietro',
16545 addNode: 'Aggiungi un nodo',
16546 addEdge: 'Aggiungi un vertice',
16547 editNode: 'Modifica il nodo',
16548 editEdge: 'Modifica il vertice',
16549 addDescription: 'Clicca per aggiungere un nuovo nodo',
16550 edgeDescription: 'Clicca su un nodo e trascinalo ad un altro nodo per connetterli.',
16551 editEdgeDescription: 'Clicca sui Punti di controllo e trascinali ad un nodo per connetterli.',
16552 createEdgeError: 'Non si possono collegare vertici ad un cluster',
16553 deleteClusterError: 'I cluster non possono essere cancellati',
16554 editClusterError: 'I clusters non possono essere modificati.'
16555 };
16556 exports['it_IT'] = exports['it']; // Dutch
16557
16558 exports['nl'] = {
16559 edit: 'Wijzigen',
16560 del: 'Selectie verwijderen',
16561 back: 'Terug',
16562 addNode: 'Node toevoegen',
16563 addEdge: 'Link toevoegen',
16564 editNode: 'Node wijzigen',
16565 editEdge: 'Link wijzigen',
16566 addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.',
16567 edgeDescription: 'Klik op een node en sleep de link naar een andere node om ze te verbinden.',
16568 editEdgeDescription: 'Klik op de verbindingspunten en sleep ze naar een node om daarmee te verbinden.',
16569 createEdgeError: 'Kan geen link maken naar een cluster.',
16570 deleteClusterError: 'Clusters kunnen niet worden verwijderd.',
16571 editClusterError: 'Clusters kunnen niet worden aangepast.'
16572 };
16573 exports['nl_NL'] = exports['nl'];
16574 exports['nl_BE'] = exports['nl']; // Portuguese Brazil
16575
16576 exports['pt-br'] = {
16577 edit: 'Editar',
16578 del: 'Remover selecionado',
16579 back: 'Voltar',
16580 addNode: 'Adicionar nó',
16581 addEdge: 'Adicionar aresta',
16582 editNode: 'Editar nó',
16583 editEdge: 'Editar aresta',
16584 addDescription: 'Clique em um espaço em branco para adicionar um novo nó',
16585 edgeDescription: 'Clique em um nó e arraste a aresta até outro nó para conectá-los',
16586 editEdgeDescription: 'Clique nos pontos de controle e os arraste para um nó para conectá-los',
16587 createEdgeError: 'Não foi possível linkar arestas a um cluster.',
16588 deleteClusterError: 'Clusters não puderam ser removidos.',
16589 editClusterError: 'Clusters não puderam ser editados.'
16590 };
16591 exports['pt-BR'] = exports['pt-br'];
16592 exports['pt_BR'] = exports['pt-br'];
16593 exports['pt_br'] = exports['pt-br']; // Russian
16594
16595 exports['ru'] = {
16596 edit: 'Редактировать',
16597 del: 'Удалить выбранное',
16598 back: 'Назад',
16599 addNode: 'Добавить узел',
16600 addEdge: 'Добавить ребро',
16601 editNode: 'Редактировать узел',
16602 editEdge: 'Редактировать ребро',
16603 addDescription: 'Кликните в свободное место, чтобы добавить новый узел.',
16604 edgeDescription: 'Кликните на узел и протяните ребро к другому узлу, чтобы соединить их.',
16605 editEdgeDescription: 'Кликните на контрольные точки и перетащите их в узел, чтобы подключиться к нему.',
16606 createEdgeError: 'Невозможно соединить ребра в кластер.',
16607 deleteClusterError: 'Кластеры не могут быть удалены',
16608 editClusterError: 'Кластеры недоступны для редактирования.'
16609 };
16610 exports['ru_RU'] = exports['ru']; // Chinese
16611
16612 exports['cn'] = {
16613 edit: '编辑',
16614 del: '删除选定',
16615 back: '返回',
16616 addNode: '添加节点',
16617 addEdge: '添加连接线',
16618 editNode: '编辑节点',
16619 editEdge: '编辑连接线',
16620 addDescription: '单击空白处放置新节点。',
16621 edgeDescription: '单击某个节点并将该连接线拖动到另一个节点以连接它们。',
16622 editEdgeDescription: '单击控制节点并将它们拖到节点上连接。',
16623 createEdgeError: '无法将连接线连接到群集。',
16624 deleteClusterError: '无法删除群集。',
16625 editClusterError: '无法编辑群集。'
16626 };
16627 exports['zh_CN'] = exports['cn']; // Ukrainian
16628
16629 exports['uk'] = {
16630 edit: 'Редагувати',
16631 del: 'Видалити обране',
16632 back: 'Назад',
16633 addNode: 'Додати вузол',
16634 addEdge: 'Додати край',
16635 editNode: 'Редагувати вузол',
16636 editEdge: 'Редагувати край',
16637 addDescription: 'Kлікніть на вільне місце, щоб додати новий вузол.',
16638 edgeDescription: 'Клікніть на вузол і перетягніть край до іншого вузла, щоб їх з\'єднати.',
16639 editEdgeDescription: 'Клікніть на контрольні точки і перетягніть їх у вузол, щоб підключитися до нього.',
16640 createEdgeError: 'Не можливо об\'єднати краї в групу.',
16641 deleteClusterError: 'Групи не можуть бути видалені.',
16642 editClusterError: 'Групи недоступні для редагування.'
16643 };
16644 exports['uk_UA'] = exports['uk']; // French
16645
16646 exports['fr'] = {
16647 edit: 'Editer',
16648 del: 'Effacer la selection',
16649 back: 'Retour',
16650 addNode: 'Ajouter un noeud',
16651 addEdge: 'Ajouter un lien',
16652 editNode: 'Editer le noeud',
16653 editEdge: 'Editer le lien',
16654 addDescription: 'Cliquez dans un endroit vide pour placer un noeud.',
16655 edgeDescription: 'Cliquez sur un noeud et glissez le lien vers un autre noeud pour les connecter.',
16656 editEdgeDescription: 'Cliquez sur les points de contrôle et glissez-les pour connecter un noeud.',
16657 createEdgeError: 'Impossible de créer un lien vers un cluster.',
16658 deleteClusterError: 'Les clusters ne peuvent pas être éffacés.',
16659 editClusterError: 'Les clusters ne peuvent pas être édites.'
16660 };
16661 exports['fr_FR'] = exports['fr']; // Czech
16662
16663 exports['cs'] = {
16664 edit: 'Upravit',
16665 del: 'Smazat výběr',
16666 back: 'Zpět',
16667 addNode: 'Přidat vrchol',
16668 addEdge: 'Přidat hranu',
16669 editNode: 'Upravit vrchol',
16670 editEdge: 'Upravit hranu',
16671 addDescription: 'Kluknutím do prázdného prostoru můžete přidat nový vrchol.',
16672 edgeDescription: 'Přetažením z jednoho vrcholu do druhého můžete spojit tyto vrcholy novou hranou.',
16673 editEdgeDescription: 'Přetažením kontrolního vrcholu hrany ji můžete připojit k jinému vrcholu.',
16674 createEdgeError: 'Nelze připojit hranu ke shluku.',
16675 deleteClusterError: 'Nelze mazat shluky.',
16676 editClusterError: 'Nelze upravovat shluky.'
16677 };
16678 exports['cs_CZ'] = exports['cs'];
16679 });
16680
16681 function _typeof$1(obj) {
16682 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
16683 _typeof$1 = function (obj) {
16684 return typeof obj;
16685 };
16686 } else {
16687 _typeof$1 = function (obj) {
16688 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
16689 };
16690 }
16691
16692 return _typeof$1(obj);
16693 }
16694
16695 function _classCallCheck(instance, Constructor) {
16696 if (!(instance instanceof Constructor)) {
16697 throw new TypeError("Cannot call a class as a function");
16698 }
16699 }
16700
16701 function _defineProperties(target, props) {
16702 for (var i = 0; i < props.length; i++) {
16703 var descriptor = props[i];
16704 descriptor.enumerable = descriptor.enumerable || false;
16705 descriptor.configurable = true;
16706 if ("value" in descriptor) descriptor.writable = true;
16707 Object.defineProperty(target, descriptor.key, descriptor);
16708 }
16709 }
16710
16711 function _createClass(Constructor, protoProps, staticProps) {
16712 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
16713 if (staticProps) _defineProperties(Constructor, staticProps);
16714 return Constructor;
16715 }
16716
16717 function _defineProperty$1(obj, key, value) {
16718 if (key in obj) {
16719 Object.defineProperty(obj, key, {
16720 value: value,
16721 enumerable: true,
16722 configurable: true,
16723 writable: true
16724 });
16725 } else {
16726 obj[key] = value;
16727 }
16728
16729 return obj;
16730 }
16731
16732 function ownKeys$2(object, enumerableOnly) {
16733 var keys = Object.keys(object);
16734
16735 if (Object.getOwnPropertySymbols) {
16736 var symbols = Object.getOwnPropertySymbols(object);
16737 if (enumerableOnly) symbols = symbols.filter(function (sym) {
16738 return Object.getOwnPropertyDescriptor(object, sym).enumerable;
16739 });
16740 keys.push.apply(keys, symbols);
16741 }
16742
16743 return keys;
16744 }
16745
16746 function _objectSpread2$1(target) {
16747 for (var i = 1; i < arguments.length; i++) {
16748 var source = arguments[i] != null ? arguments[i] : {};
16749
16750 if (i % 2) {
16751 ownKeys$2(source, true).forEach(function (key) {
16752 _defineProperty$1(target, key, source[key]);
16753 });
16754 } else if (Object.getOwnPropertyDescriptors) {
16755 Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
16756 } else {
16757 ownKeys$2(source).forEach(function (key) {
16758 Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
16759 });
16760 }
16761 }
16762
16763 return target;
16764 }
16765
16766 function _inherits(subClass, superClass) {
16767 if (typeof superClass !== "function" && superClass !== null) {
16768 throw new TypeError("Super expression must either be null or a function");
16769 }
16770
16771 subClass.prototype = Object.create(superClass && superClass.prototype, {
16772 constructor: {
16773 value: subClass,
16774 writable: true,
16775 configurable: true
16776 }
16777 });
16778 if (superClass) _setPrototypeOf(subClass, superClass);
16779 }
16780
16781 function _getPrototypeOf(o) {
16782 _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
16783 return o.__proto__ || Object.getPrototypeOf(o);
16784 };
16785 return _getPrototypeOf(o);
16786 }
16787
16788 function _setPrototypeOf(o, p) {
16789 _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
16790 o.__proto__ = p;
16791 return o;
16792 };
16793
16794 return _setPrototypeOf(o, p);
16795 }
16796
16797 function _assertThisInitialized$1(self) {
16798 if (self === void 0) {
16799 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
16800 }
16801
16802 return self;
16803 }
16804
16805 function _possibleConstructorReturn(self, call) {
16806 if (call && (typeof call === "object" || typeof call === "function")) {
16807 return call;
16808 }
16809
16810 return _assertThisInitialized$1(self);
16811 }
16812
16813 function _superPropBase(object, property) {
16814 while (!Object.prototype.hasOwnProperty.call(object, property)) {
16815 object = _getPrototypeOf(object);
16816 if (object === null) break;
16817 }
16818
16819 return object;
16820 }
16821
16822 function _get(target, property, receiver) {
16823 if (typeof Reflect !== "undefined" && Reflect.get) {
16824 _get = Reflect.get;
16825 } else {
16826 _get = function _get(target, property, receiver) {
16827 var base = _superPropBase(target, property);
16828
16829 if (!base) return;
16830 var desc = Object.getOwnPropertyDescriptor(base, property);
16831
16832 if (desc.get) {
16833 return desc.get.call(receiver);
16834 }
16835
16836 return desc.value;
16837 };
16838 }
16839
16840 return _get(target, property, receiver || target);
16841 }
16842
16843 function _readOnlyError(name) {
16844 throw new Error("\"" + name + "\" is read-only");
16845 }
16846
16847 function _slicedToArray(arr, i) {
16848 return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
16849 }
16850
16851 function _arrayWithHoles(arr) {
16852 if (Array.isArray(arr)) return arr;
16853 }
16854
16855 function _iterableToArrayLimit(arr, i) {
16856 if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
16857 return;
16858 }
16859
16860 var _arr = [];
16861 var _n = true;
16862 var _d = false;
16863 var _e = undefined;
16864
16865 try {
16866 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
16867 _arr.push(_s.value);
16868
16869 if (i && _arr.length === i) break;
16870 }
16871 } catch (err) {
16872 _d = true;
16873 _e = err;
16874 } finally {
16875 try {
16876 if (!_n && _i["return"] != null) _i["return"]();
16877 } finally {
16878 if (_d) throw _e;
16879 }
16880 }
16881
16882 return _arr;
16883 }
16884
16885 function _nonIterableRest() {
16886 throw new TypeError("Invalid attempt to destructure non-iterable instance");
16887 }
16888
16889 /**
16890 * Associates a canvas to a given image, containing a number of renderings
16891 * of the image at various sizes.
16892 *
16893 * This technique is known as 'mipmapping'.
16894 *
16895 * NOTE: Images can also be of type 'data:svg+xml`. This code also works
16896 * for svg, but the mipmapping may not be necessary.
16897 *
16898 * @param {Image} image
16899 */
16900 var CachedImage =
16901 /*#__PURE__*/
16902 function () {
16903 /**
16904 * @ignore
16905 */
16906 function CachedImage() {
16907 _classCallCheck(this, CachedImage);
16908
16909 // eslint-disable-line no-unused-vars
16910 this.NUM_ITERATIONS = 4; // Number of items in the coordinates array
16911
16912 this.image = new Image();
16913 this.canvas = document.createElement('canvas');
16914 }
16915 /**
16916 * Called when the image has been successfully loaded.
16917 */
16918
16919
16920 _createClass(CachedImage, [{
16921 key: "init",
16922 value: function init() {
16923 if (this.initialized()) return;
16924 this.src = this.image.src; // For same interface with Image
16925
16926 var w = this.image.width;
16927 var h = this.image.height; // Ease external access
16928
16929 this.width = w;
16930 this.height = h;
16931 var h2 = Math.floor(h / 2);
16932 var h4 = Math.floor(h / 4);
16933 var h8 = Math.floor(h / 8);
16934 var h16 = Math.floor(h / 16);
16935 var w2 = Math.floor(w / 2);
16936 var w4 = Math.floor(w / 4);
16937 var w8 = Math.floor(w / 8);
16938 var w16 = Math.floor(w / 16); // Make canvas as small as possible
16939
16940 this.canvas.width = 3 * w4;
16941 this.canvas.height = h2; // Coordinates and sizes of images contained in the canvas
16942 // Values per row: [top x, left y, width, height]
16943
16944 this.coordinates = [[0, 0, w2, h2], [w2, 0, w4, h4], [w2, h4, w8, h8], [5 * w8, h4, w16, h16]];
16945
16946 this._fillMipMap();
16947 }
16948 /**
16949 * @return {Boolean} true if init() has been called, false otherwise.
16950 */
16951
16952 }, {
16953 key: "initialized",
16954 value: function initialized() {
16955 return this.coordinates !== undefined;
16956 }
16957 /**
16958 * Redraw main image in various sizes to the context.
16959 *
16960 * The rationale behind this is to reduce artefacts due to interpolation
16961 * at differing zoom levels.
16962 *
16963 * Source: http://stackoverflow.com/q/18761404/1223531
16964 *
16965 * This methods takes the resizing out of the drawing loop, in order to
16966 * reduce performance overhead.
16967 *
16968 * TODO: The code assumes that a 2D context can always be gotten. This is
16969 * not necessarily true! OTOH, if not true then usage of this class
16970 * is senseless.
16971 *
16972 * @private
16973 */
16974
16975 }, {
16976 key: "_fillMipMap",
16977 value: function _fillMipMap() {
16978 var ctx = this.canvas.getContext('2d'); // First zoom-level comes from the image
16979
16980 var to = this.coordinates[0];
16981 ctx.drawImage(this.image, to[0], to[1], to[2], to[3]); // The rest are copy actions internal to the canvas/context
16982
16983 for (var iterations = 1; iterations < this.NUM_ITERATIONS; iterations++) {
16984 var from = this.coordinates[iterations - 1];
16985 var _to = this.coordinates[iterations];
16986 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], _to[0], _to[1], _to[2], _to[3]);
16987 }
16988 }
16989 /**
16990 * Draw the image, using the mipmap if necessary.
16991 *
16992 * MipMap is only used if param factor > 2; otherwise, original bitmap
16993 * is resized. This is also used to skip mipmap usage, e.g. by setting factor = 1
16994 *
16995 * Credits to 'Alex de Mulder' for original implementation.
16996 *
16997 * @param {CanvasRenderingContext2D} ctx context on which to draw zoomed image
16998 * @param {Float} factor scale factor at which to draw
16999 * @param {number} left
17000 * @param {number} top
17001 * @param {number} width
17002 * @param {number} height
17003 */
17004
17005 }, {
17006 key: "drawImageAtPosition",
17007 value: function drawImageAtPosition(ctx, factor, left, top, width, height) {
17008 if (!this.initialized()) return; //can't draw image yet not intialized
17009
17010 if (factor > 2) {
17011 // Determine which zoomed image to use
17012 factor *= 0.5;
17013 var iterations = 0;
17014
17015 while (factor > 2 && iterations < this.NUM_ITERATIONS) {
17016 factor *= 0.5;
17017 iterations += 1;
17018 }
17019
17020 if (iterations >= this.NUM_ITERATIONS) {
17021 iterations = this.NUM_ITERATIONS - 1;
17022 } //console.log("iterations: " + iterations);
17023
17024
17025 var from = this.coordinates[iterations];
17026 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], left, top, width, height);
17027 } else {
17028 // Draw image directly
17029 ctx.drawImage(this.image, left, top, width, height);
17030 }
17031 }
17032 }]);
17033
17034 return CachedImage;
17035 }();
17036
17037 /**
17038 * This callback is a callback that accepts an Image.
17039 * @callback ImageCallback
17040 * @param {Image} image
17041 */
17042
17043 /**
17044 * This class loads images and keeps them stored.
17045 *
17046 * @param {ImageCallback} callback
17047 */
17048
17049 var Images =
17050 /*#__PURE__*/
17051 function () {
17052 /**
17053 * @param {ImageCallback} callback
17054 */
17055 function Images(callback) {
17056 _classCallCheck(this, Images);
17057
17058 this.images = {};
17059 this.imageBroken = {};
17060 this.callback = callback;
17061 }
17062 /**
17063 * @param {string} url The original Url that failed to load, if the broken image is successfully loaded it will be added to the cache using this Url as the key so that subsequent requests for this Url will return the broken image
17064 * @param {string} brokenUrl Url the broken image to try and load
17065 * @param {Image} imageToLoadBrokenUrlOn The image object
17066 */
17067
17068
17069 _createClass(Images, [{
17070 key: "_tryloadBrokenUrl",
17071 value: function _tryloadBrokenUrl(url, brokenUrl, imageToLoadBrokenUrlOn) {
17072 //If these parameters aren't specified then exit the function because nothing constructive can be done
17073 if (url === undefined || imageToLoadBrokenUrlOn === undefined) return;
17074
17075 if (brokenUrl === undefined) {
17076 console.warn("No broken url image defined");
17077 return;
17078 } //Clear the old subscription to the error event and put a new in place that only handle errors in loading the brokenImageUrl
17079
17080
17081 imageToLoadBrokenUrlOn.image.onerror = function () {
17082 console.error("Could not load brokenImage:", brokenUrl); // cache item will contain empty image, this should be OK for default
17083 }; //Set the source of the image to the brokenUrl, this is actually what kicks off the loading of the broken image
17084
17085
17086 imageToLoadBrokenUrlOn.image.src = brokenUrl;
17087 }
17088 /**
17089 *
17090 * @param {vis.Image} imageToRedrawWith
17091 * @private
17092 */
17093
17094 }, {
17095 key: "_redrawWithImage",
17096 value: function _redrawWithImage(imageToRedrawWith) {
17097 if (this.callback) {
17098 this.callback(imageToRedrawWith);
17099 }
17100 }
17101 /**
17102 * @param {string} url Url of the image
17103 * @param {string} brokenUrl Url of an image to use if the url image is not found
17104 * @return {Image} img The image object
17105 */
17106
17107 }, {
17108 key: "load",
17109 value: function load(url, brokenUrl) {
17110 var _this = this;
17111
17112 //Try and get the image from the cache, if successful then return the cached image
17113 var cachedImage = this.images[url];
17114 if (cachedImage) return cachedImage; //Create a new image
17115
17116 var img = new CachedImage(); // Need to add to cache here, otherwise final return will spawn different copies of the same image,
17117 // Also, there will be multiple loads of the same image.
17118
17119 this.images[url] = img; //Subscribe to the event that is raised if the image loads successfully
17120
17121 img.image.onload = function () {
17122 // Properly init the cached item and then request a redraw
17123 _this._fixImageCoordinates(img.image);
17124
17125 img.init();
17126
17127 _this._redrawWithImage(img);
17128 }; //Subscribe to the event that is raised if the image fails to load
17129
17130
17131 img.image.onerror = function () {
17132 console.error("Could not load image:", url); //Try and load the image specified by the brokenUrl using
17133
17134 _this._tryloadBrokenUrl(url, brokenUrl, img);
17135 }; //Set the source of the image to the url, this is what actually kicks off the loading of the image
17136
17137
17138 img.image.src = url; //Return the new image
17139
17140 return img;
17141 }
17142 /**
17143 * IE11 fix -- thanks dponch!
17144 *
17145 * Local helper function
17146 * @param {vis.Image} imageToCache
17147 * @private
17148 */
17149
17150 }, {
17151 key: "_fixImageCoordinates",
17152 value: function _fixImageCoordinates(imageToCache) {
17153 if (imageToCache.width === 0) {
17154 document.body.appendChild(imageToCache);
17155 imageToCache.width = imageToCache.offsetWidth;
17156 imageToCache.height = imageToCache.offsetHeight;
17157 document.body.removeChild(imageToCache);
17158 }
17159 }
17160 }]);
17161
17162 return Images;
17163 }();
17164
17165 /**
17166 * This class can store groups and options specific for groups.
17167 */
17168
17169 var Groups =
17170 /*#__PURE__*/
17171 function () {
17172 /**
17173 * @ignore
17174 */
17175 function Groups() {
17176 _classCallCheck(this, Groups);
17177
17178 this.clear();
17179 this.defaultIndex = 0;
17180 this.groupsArray = [];
17181 this.groupIndex = 0;
17182 this.defaultGroups = [{
17183 border: "#2B7CE9",
17184 background: "#97C2FC",
17185 highlight: {
17186 border: "#2B7CE9",
17187 background: "#D2E5FF"
17188 },
17189 hover: {
17190 border: "#2B7CE9",
17191 background: "#D2E5FF"
17192 }
17193 }, // 0: blue
17194 {
17195 border: "#FFA500",
17196 background: "#FFFF00",
17197 highlight: {
17198 border: "#FFA500",
17199 background: "#FFFFA3"
17200 },
17201 hover: {
17202 border: "#FFA500",
17203 background: "#FFFFA3"
17204 }
17205 }, // 1: yellow
17206 {
17207 border: "#FA0A10",
17208 background: "#FB7E81",
17209 highlight: {
17210 border: "#FA0A10",
17211 background: "#FFAFB1"
17212 },
17213 hover: {
17214 border: "#FA0A10",
17215 background: "#FFAFB1"
17216 }
17217 }, // 2: red
17218 {
17219 border: "#41A906",
17220 background: "#7BE141",
17221 highlight: {
17222 border: "#41A906",
17223 background: "#A1EC76"
17224 },
17225 hover: {
17226 border: "#41A906",
17227 background: "#A1EC76"
17228 }
17229 }, // 3: green
17230 {
17231 border: "#E129F0",
17232 background: "#EB7DF4",
17233 highlight: {
17234 border: "#E129F0",
17235 background: "#F0B3F5"
17236 },
17237 hover: {
17238 border: "#E129F0",
17239 background: "#F0B3F5"
17240 }
17241 }, // 4: magenta
17242 {
17243 border: "#7C29F0",
17244 background: "#AD85E4",
17245 highlight: {
17246 border: "#7C29F0",
17247 background: "#D3BDF0"
17248 },
17249 hover: {
17250 border: "#7C29F0",
17251 background: "#D3BDF0"
17252 }
17253 }, // 5: purple
17254 {
17255 border: "#C37F00",
17256 background: "#FFA807",
17257 highlight: {
17258 border: "#C37F00",
17259 background: "#FFCA66"
17260 },
17261 hover: {
17262 border: "#C37F00",
17263 background: "#FFCA66"
17264 }
17265 }, // 6: orange
17266 {
17267 border: "#4220FB",
17268 background: "#6E6EFD",
17269 highlight: {
17270 border: "#4220FB",
17271 background: "#9B9BFD"
17272 },
17273 hover: {
17274 border: "#4220FB",
17275 background: "#9B9BFD"
17276 }
17277 }, // 7: darkblue
17278 {
17279 border: "#FD5A77",
17280 background: "#FFC0CB",
17281 highlight: {
17282 border: "#FD5A77",
17283 background: "#FFD1D9"
17284 },
17285 hover: {
17286 border: "#FD5A77",
17287 background: "#FFD1D9"
17288 }
17289 }, // 8: pink
17290 {
17291 border: "#4AD63A",
17292 background: "#C2FABC",
17293 highlight: {
17294 border: "#4AD63A",
17295 background: "#E6FFE3"
17296 },
17297 hover: {
17298 border: "#4AD63A",
17299 background: "#E6FFE3"
17300 }
17301 }, // 9: mint
17302 {
17303 border: "#990000",
17304 background: "#EE0000",
17305 highlight: {
17306 border: "#BB0000",
17307 background: "#FF3333"
17308 },
17309 hover: {
17310 border: "#BB0000",
17311 background: "#FF3333"
17312 }
17313 }, // 10:bright red
17314 {
17315 border: "#FF6000",
17316 background: "#FF6000",
17317 highlight: {
17318 border: "#FF6000",
17319 background: "#FF6000"
17320 },
17321 hover: {
17322 border: "#FF6000",
17323 background: "#FF6000"
17324 }
17325 }, // 12: real orange
17326 {
17327 border: "#97C2FC",
17328 background: "#2B7CE9",
17329 highlight: {
17330 border: "#D2E5FF",
17331 background: "#2B7CE9"
17332 },
17333 hover: {
17334 border: "#D2E5FF",
17335 background: "#2B7CE9"
17336 }
17337 }, // 13: blue
17338 {
17339 border: "#399605",
17340 background: "#255C03",
17341 highlight: {
17342 border: "#399605",
17343 background: "#255C03"
17344 },
17345 hover: {
17346 border: "#399605",
17347 background: "#255C03"
17348 }
17349 }, // 14: green
17350 {
17351 border: "#B70054",
17352 background: "#FF007E",
17353 highlight: {
17354 border: "#B70054",
17355 background: "#FF007E"
17356 },
17357 hover: {
17358 border: "#B70054",
17359 background: "#FF007E"
17360 }
17361 }, // 15: magenta
17362 {
17363 border: "#AD85E4",
17364 background: "#7C29F0",
17365 highlight: {
17366 border: "#D3BDF0",
17367 background: "#7C29F0"
17368 },
17369 hover: {
17370 border: "#D3BDF0",
17371 background: "#7C29F0"
17372 }
17373 }, // 16: purple
17374 {
17375 border: "#4557FA",
17376 background: "#000EA1",
17377 highlight: {
17378 border: "#6E6EFD",
17379 background: "#000EA1"
17380 },
17381 hover: {
17382 border: "#6E6EFD",
17383 background: "#000EA1"
17384 }
17385 }, // 17: darkblue
17386 {
17387 border: "#FFC0CB",
17388 background: "#FD5A77",
17389 highlight: {
17390 border: "#FFD1D9",
17391 background: "#FD5A77"
17392 },
17393 hover: {
17394 border: "#FFD1D9",
17395 background: "#FD5A77"
17396 }
17397 }, // 18: pink
17398 {
17399 border: "#C2FABC",
17400 background: "#74D66A",
17401 highlight: {
17402 border: "#E6FFE3",
17403 background: "#74D66A"
17404 },
17405 hover: {
17406 border: "#E6FFE3",
17407 background: "#74D66A"
17408 }
17409 }, // 19: mint
17410 {
17411 border: "#EE0000",
17412 background: "#990000",
17413 highlight: {
17414 border: "#FF3333",
17415 background: "#BB0000"
17416 },
17417 hover: {
17418 border: "#FF3333",
17419 background: "#BB0000"
17420 }
17421 } // 20:bright red
17422 ];
17423 this.options = {};
17424 this.defaultOptions = {
17425 useDefaultGroups: true
17426 };
17427 extend(this.options, this.defaultOptions);
17428 }
17429 /**
17430 *
17431 * @param {Object} options
17432 */
17433
17434
17435 _createClass(Groups, [{
17436 key: "setOptions",
17437 value: function setOptions(options) {
17438 var optionFields = ['useDefaultGroups'];
17439
17440 if (options !== undefined) {
17441 for (var groupName in options) {
17442 if (options.hasOwnProperty(groupName)) {
17443 if (optionFields.indexOf(groupName) === -1) {
17444 var group = options[groupName];
17445 this.add(groupName, group);
17446 }
17447 }
17448 }
17449 }
17450 }
17451 /**
17452 * Clear all groups
17453 */
17454
17455 }, {
17456 key: "clear",
17457 value: function clear() {
17458 this.groups = {};
17459 this.groupsArray = [];
17460 }
17461 /**
17462 * Get group options of a groupname.
17463 * If groupname is not found, a new group may be created.
17464 *
17465 * @param {*} groupname Can be a number, string, Date, etc.
17466 * @param {boolean} [shouldCreate=true] If true, create a new group
17467 * @return {Object} The found or created group
17468 */
17469
17470 }, {
17471 key: "get",
17472 value: function get(groupname) {
17473 var shouldCreate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
17474 var group = this.groups[groupname];
17475
17476 if (group === undefined && shouldCreate) {
17477 if (this.options.useDefaultGroups === false && this.groupsArray.length > 0) {
17478 // create new group
17479 var index = this.groupIndex % this.groupsArray.length;
17480 this.groupIndex++;
17481 group = {};
17482 group.color = this.groups[this.groupsArray[index]];
17483 this.groups[groupname] = group;
17484 } else {
17485 // create new group
17486 var _index = this.defaultIndex % this.defaultGroups.length;
17487
17488 this.defaultIndex++;
17489 group = {};
17490 group.color = this.defaultGroups[_index];
17491 this.groups[groupname] = group;
17492 }
17493 }
17494
17495 return group;
17496 }
17497 /**
17498 * Add a custom group style
17499 * @param {string} groupName
17500 * @param {Object} style An object containing borderColor,
17501 * backgroundColor, etc.
17502 * @return {Object} group The created group object
17503 */
17504
17505 }, {
17506 key: "add",
17507 value: function add(groupName, style) {
17508 this.groups[groupName] = style;
17509 this.groupsArray.push(groupName);
17510 return style;
17511 }
17512 }]);
17513
17514 return Groups;
17515 }();
17516
17517 var $some = arrayIteration.some; // `Array.prototype.some` method
17518 // https://tc39.github.io/ecma262/#sec-array.prototype.some
17519
17520 _export({
17521 target: 'Array',
17522 proto: true,
17523 forced: sloppyArrayMethod('some')
17524 }, {
17525 some: function some(callbackfn
17526 /* , thisArg */
17527 ) {
17528 return $some(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
17529 }
17530 });
17531
17532 /**
17533 * vis-data - data
17534 * http://visjs.org/
17535 *
17536 * Manage unstructured data using DataSet. Add, update, and remove data, and listen for changes in the data.
17537 *
17538 * @version 6.2.1
17539 * @date 2019-09-13T21:24:53Z
17540 *
17541 * @copyright (c) 2011-2017 Almende B.V, http://almende.com
17542 * @copyright (c) 2018-2019 visjs contributors, https://github.com/visjs
17543 *
17544 * @license
17545 * vis.js is dual licensed under both
17546 *
17547 * 1. The Apache 2.0 License
17548 * http://www.apache.org/licenses/LICENSE-2.0
17549 *
17550 * and
17551 *
17552 * 2. The MIT License
17553 * http://opensource.org/licenses/MIT
17554 *
17555 * vis.js may be distributed under either license.
17556 */
17557 function createCommonjsModule$2(fn, module) {
17558 return module = {
17559 exports: {}
17560 }, fn(module, module.exports), module.exports;
17561 }
17562
17563 var runtime_1 = createCommonjsModule$2(function (module) {
17564 /**
17565 * Copyright (c) 2014-present, Facebook, Inc.
17566 *
17567 * This source code is licensed under the MIT license found in the
17568 * LICENSE file in the root directory of this source tree.
17569 */
17570 var runtime = function (exports) {
17571 var Op = Object.prototype;
17572 var hasOwn = Op.hasOwnProperty;
17573 var undefined$1; // More compressible than void 0.
17574
17575 var $Symbol = typeof Symbol === "function" ? Symbol : {};
17576 var iteratorSymbol = $Symbol.iterator || "@@iterator";
17577 var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
17578 var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
17579
17580 function wrap(innerFn, outerFn, self, tryLocsList) {
17581 // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
17582 var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
17583 var generator = Object.create(protoGenerator.prototype);
17584 var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
17585 // .throw, and .return methods.
17586
17587 generator._invoke = makeInvokeMethod(innerFn, self, context);
17588 return generator;
17589 }
17590
17591 exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
17592 // record like context.tryEntries[i].completion. This interface could
17593 // have been (and was previously) designed to take a closure to be
17594 // invoked without arguments, but in all the cases we care about we
17595 // already have an existing method we want to call, so there's no need
17596 // to create a new function object. We can even get away with assuming
17597 // the method takes exactly one argument, since that happens to be true
17598 // in every case, so we don't have to touch the arguments object. The
17599 // only additional allocation required is the completion record, which
17600 // has a stable shape and so hopefully should be cheap to allocate.
17601
17602 function tryCatch(fn, obj, arg) {
17603 try {
17604 return {
17605 type: "normal",
17606 arg: fn.call(obj, arg)
17607 };
17608 } catch (err) {
17609 return {
17610 type: "throw",
17611 arg: err
17612 };
17613 }
17614 }
17615
17616 var GenStateSuspendedStart = "suspendedStart";
17617 var GenStateSuspendedYield = "suspendedYield";
17618 var GenStateExecuting = "executing";
17619 var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
17620 // breaking out of the dispatch switch statement.
17621
17622 var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
17623 // .constructor.prototype properties for functions that return Generator
17624 // objects. For full spec compliance, you may wish to configure your
17625 // minifier not to mangle the names of these two functions.
17626
17627 function Generator() {}
17628
17629 function GeneratorFunction() {}
17630
17631 function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
17632 // don't natively support it.
17633
17634
17635 var IteratorPrototype = {};
17636
17637 IteratorPrototype[iteratorSymbol] = function () {
17638 return this;
17639 };
17640
17641 var getProto = Object.getPrototypeOf;
17642 var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
17643
17644 if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
17645 // This environment has a native %IteratorPrototype%; use it instead
17646 // of the polyfill.
17647 IteratorPrototype = NativeIteratorPrototype;
17648 }
17649
17650 var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
17651 GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
17652 GeneratorFunctionPrototype.constructor = GeneratorFunction;
17653 GeneratorFunctionPrototype[toStringTagSymbol] = GeneratorFunction.displayName = "GeneratorFunction"; // Helper for defining the .next, .throw, and .return methods of the
17654 // Iterator interface in terms of a single ._invoke method.
17655
17656 function defineIteratorMethods(prototype) {
17657 ["next", "throw", "return"].forEach(function (method) {
17658 prototype[method] = function (arg) {
17659 return this._invoke(method, arg);
17660 };
17661 });
17662 }
17663
17664 exports.isGeneratorFunction = function (genFun) {
17665 var ctor = typeof genFun === "function" && genFun.constructor;
17666 return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
17667 // do is to check its .name property.
17668 (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
17669 };
17670
17671 exports.mark = function (genFun) {
17672 if (Object.setPrototypeOf) {
17673 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
17674 } else {
17675 genFun.__proto__ = GeneratorFunctionPrototype;
17676
17677 if (!(toStringTagSymbol in genFun)) {
17678 genFun[toStringTagSymbol] = "GeneratorFunction";
17679 }
17680 }
17681
17682 genFun.prototype = Object.create(Gp);
17683 return genFun;
17684 }; // Within the body of any async function, `await x` is transformed to
17685 // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
17686 // `hasOwn.call(value, "__await")` to determine if the yielded value is
17687 // meant to be awaited.
17688
17689
17690 exports.awrap = function (arg) {
17691 return {
17692 __await: arg
17693 };
17694 };
17695
17696 function AsyncIterator(generator) {
17697 function invoke(method, arg, resolve, reject) {
17698 var record = tryCatch(generator[method], generator, arg);
17699
17700 if (record.type === "throw") {
17701 reject(record.arg);
17702 } else {
17703 var result = record.arg;
17704 var value = result.value;
17705
17706 if (value && typeof value === "object" && hasOwn.call(value, "__await")) {
17707 return Promise.resolve(value.__await).then(function (value) {
17708 invoke("next", value, resolve, reject);
17709 }, function (err) {
17710 invoke("throw", err, resolve, reject);
17711 });
17712 }
17713
17714 return Promise.resolve(value).then(function (unwrapped) {
17715 // When a yielded Promise is resolved, its final value becomes
17716 // the .value of the Promise<{value,done}> result for the
17717 // current iteration.
17718 result.value = unwrapped;
17719 resolve(result);
17720 }, function (error) {
17721 // If a rejected Promise was yielded, throw the rejection back
17722 // into the async generator function so it can be handled there.
17723 return invoke("throw", error, resolve, reject);
17724 });
17725 }
17726 }
17727
17728 var previousPromise;
17729
17730 function enqueue(method, arg) {
17731 function callInvokeWithMethodAndArg() {
17732 return new Promise(function (resolve, reject) {
17733 invoke(method, arg, resolve, reject);
17734 });
17735 }
17736
17737 return previousPromise = // If enqueue has been called before, then we want to wait until
17738 // all previous Promises have been resolved before calling invoke,
17739 // so that results are always delivered in the correct order. If
17740 // enqueue has not been called before, then it is important to
17741 // call invoke immediately, without waiting on a callback to fire,
17742 // so that the async generator function has the opportunity to do
17743 // any necessary setup in a predictable way. This predictability
17744 // is why the Promise constructor synchronously invokes its
17745 // executor callback, and why async functions synchronously
17746 // execute code before the first await. Since we implement simple
17747 // async functions in terms of async generators, it is especially
17748 // important to get this right, even though it requires care.
17749 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
17750 // invocations of the iterator.
17751 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
17752 } // Define the unified helper method that is used to implement .next,
17753 // .throw, and .return (see defineIteratorMethods).
17754
17755
17756 this._invoke = enqueue;
17757 }
17758
17759 defineIteratorMethods(AsyncIterator.prototype);
17760
17761 AsyncIterator.prototype[asyncIteratorSymbol] = function () {
17762 return this;
17763 };
17764
17765 exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
17766 // AsyncIterator objects; they just return a Promise for the value of
17767 // the final result produced by the iterator.
17768
17769 exports.async = function (innerFn, outerFn, self, tryLocsList) {
17770 var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList));
17771 return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
17772 : iter.next().then(function (result) {
17773 return result.done ? result.value : iter.next();
17774 });
17775 };
17776
17777 function makeInvokeMethod(innerFn, self, context) {
17778 var state = GenStateSuspendedStart;
17779 return function invoke(method, arg) {
17780 if (state === GenStateExecuting) {
17781 throw new Error("Generator is already running");
17782 }
17783
17784 if (state === GenStateCompleted) {
17785 if (method === "throw") {
17786 throw arg;
17787 } // Be forgiving, per 25.3.3.3.3 of the spec:
17788 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
17789
17790
17791 return doneResult();
17792 }
17793
17794 context.method = method;
17795 context.arg = arg;
17796
17797 while (true) {
17798 var delegate = context.delegate;
17799
17800 if (delegate) {
17801 var delegateResult = maybeInvokeDelegate(delegate, context);
17802
17803 if (delegateResult) {
17804 if (delegateResult === ContinueSentinel) continue;
17805 return delegateResult;
17806 }
17807 }
17808
17809 if (context.method === "next") {
17810 // Setting context._sent for legacy support of Babel's
17811 // function.sent implementation.
17812 context.sent = context._sent = context.arg;
17813 } else if (context.method === "throw") {
17814 if (state === GenStateSuspendedStart) {
17815 state = GenStateCompleted;
17816 throw context.arg;
17817 }
17818
17819 context.dispatchException(context.arg);
17820 } else if (context.method === "return") {
17821 context.abrupt("return", context.arg);
17822 }
17823
17824 state = GenStateExecuting;
17825 var record = tryCatch(innerFn, self, context);
17826
17827 if (record.type === "normal") {
17828 // If an exception is thrown from innerFn, we leave state ===
17829 // GenStateExecuting and loop back for another invocation.
17830 state = context.done ? GenStateCompleted : GenStateSuspendedYield;
17831
17832 if (record.arg === ContinueSentinel) {
17833 continue;
17834 }
17835
17836 return {
17837 value: record.arg,
17838 done: context.done
17839 };
17840 } else if (record.type === "throw") {
17841 state = GenStateCompleted; // Dispatch the exception by looping back around to the
17842 // context.dispatchException(context.arg) call above.
17843
17844 context.method = "throw";
17845 context.arg = record.arg;
17846 }
17847 }
17848 };
17849 } // Call delegate.iterator[context.method](context.arg) and handle the
17850 // result, either by returning a { value, done } result from the
17851 // delegate iterator, or by modifying context.method and context.arg,
17852 // setting context.delegate to null, and returning the ContinueSentinel.
17853
17854
17855 function maybeInvokeDelegate(delegate, context) {
17856 var method = delegate.iterator[context.method];
17857
17858 if (method === undefined$1) {
17859 // A .throw or .return when the delegate iterator has no .throw
17860 // method always terminates the yield* loop.
17861 context.delegate = null;
17862
17863 if (context.method === "throw") {
17864 // Note: ["return"] must be used for ES3 parsing compatibility.
17865 if (delegate.iterator["return"]) {
17866 // If the delegate iterator has a return method, give it a
17867 // chance to clean up.
17868 context.method = "return";
17869 context.arg = undefined$1;
17870 maybeInvokeDelegate(delegate, context);
17871
17872 if (context.method === "throw") {
17873 // If maybeInvokeDelegate(context) changed context.method from
17874 // "return" to "throw", let that override the TypeError below.
17875 return ContinueSentinel;
17876 }
17877 }
17878
17879 context.method = "throw";
17880 context.arg = new TypeError("The iterator does not provide a 'throw' method");
17881 }
17882
17883 return ContinueSentinel;
17884 }
17885
17886 var record = tryCatch(method, delegate.iterator, context.arg);
17887
17888 if (record.type === "throw") {
17889 context.method = "throw";
17890 context.arg = record.arg;
17891 context.delegate = null;
17892 return ContinueSentinel;
17893 }
17894
17895 var info = record.arg;
17896
17897 if (!info) {
17898 context.method = "throw";
17899 context.arg = new TypeError("iterator result is not an object");
17900 context.delegate = null;
17901 return ContinueSentinel;
17902 }
17903
17904 if (info.done) {
17905 // Assign the result of the finished delegate to the temporary
17906 // variable specified by delegate.resultName (see delegateYield).
17907 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
17908
17909 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
17910 // exception, let the outer generator proceed normally. If
17911 // context.method was "next", forget context.arg since it has been
17912 // "consumed" by the delegate iterator. If context.method was
17913 // "return", allow the original .return call to continue in the
17914 // outer generator.
17915
17916 if (context.method !== "return") {
17917 context.method = "next";
17918 context.arg = undefined$1;
17919 }
17920 } else {
17921 // Re-yield the result returned by the delegate method.
17922 return info;
17923 } // The delegate iterator is finished, so forget it and continue with
17924 // the outer generator.
17925
17926
17927 context.delegate = null;
17928 return ContinueSentinel;
17929 } // Define Generator.prototype.{next,throw,return} in terms of the
17930 // unified ._invoke helper method.
17931
17932
17933 defineIteratorMethods(Gp);
17934 Gp[toStringTagSymbol] = "Generator"; // A Generator should always return itself as the iterator object when the
17935 // @@iterator function is called on it. Some browsers' implementations of the
17936 // iterator prototype chain incorrectly implement this, causing the Generator
17937 // object to not be returned from this call. This ensures that doesn't happen.
17938 // See https://github.com/facebook/regenerator/issues/274 for more details.
17939
17940 Gp[iteratorSymbol] = function () {
17941 return this;
17942 };
17943
17944 Gp.toString = function () {
17945 return "[object Generator]";
17946 };
17947
17948 function pushTryEntry(locs) {
17949 var entry = {
17950 tryLoc: locs[0]
17951 };
17952
17953 if (1 in locs) {
17954 entry.catchLoc = locs[1];
17955 }
17956
17957 if (2 in locs) {
17958 entry.finallyLoc = locs[2];
17959 entry.afterLoc = locs[3];
17960 }
17961
17962 this.tryEntries.push(entry);
17963 }
17964
17965 function resetTryEntry(entry) {
17966 var record = entry.completion || {};
17967 record.type = "normal";
17968 delete record.arg;
17969 entry.completion = record;
17970 }
17971
17972 function Context(tryLocsList) {
17973 // The root entry object (effectively a try statement without a catch
17974 // or a finally block) gives us a place to store values thrown from
17975 // locations where there is no enclosing try statement.
17976 this.tryEntries = [{
17977 tryLoc: "root"
17978 }];
17979 tryLocsList.forEach(pushTryEntry, this);
17980 this.reset(true);
17981 }
17982
17983 exports.keys = function (object) {
17984 var keys = [];
17985
17986 for (var key in object) {
17987 keys.push(key);
17988 }
17989
17990 keys.reverse(); // Rather than returning an object with a next method, we keep
17991 // things simple and return the next function itself.
17992
17993 return function next() {
17994 while (keys.length) {
17995 var key = keys.pop();
17996
17997 if (key in object) {
17998 next.value = key;
17999 next.done = false;
18000 return next;
18001 }
18002 } // To avoid creating an additional object, we just hang the .value
18003 // and .done properties off the next function object itself. This
18004 // also ensures that the minifier will not anonymize the function.
18005
18006
18007 next.done = true;
18008 return next;
18009 };
18010 };
18011
18012 function values(iterable) {
18013 if (iterable) {
18014 var iteratorMethod = iterable[iteratorSymbol];
18015
18016 if (iteratorMethod) {
18017 return iteratorMethod.call(iterable);
18018 }
18019
18020 if (typeof iterable.next === "function") {
18021 return iterable;
18022 }
18023
18024 if (!isNaN(iterable.length)) {
18025 var i = -1,
18026 next = function next() {
18027 while (++i < iterable.length) {
18028 if (hasOwn.call(iterable, i)) {
18029 next.value = iterable[i];
18030 next.done = false;
18031 return next;
18032 }
18033 }
18034
18035 next.value = undefined$1;
18036 next.done = true;
18037 return next;
18038 };
18039
18040 return next.next = next;
18041 }
18042 } // Return an iterator with no values.
18043
18044
18045 return {
18046 next: doneResult
18047 };
18048 }
18049
18050 exports.values = values;
18051
18052 function doneResult() {
18053 return {
18054 value: undefined$1,
18055 done: true
18056 };
18057 }
18058
18059 Context.prototype = {
18060 constructor: Context,
18061 reset: function (skipTempReset) {
18062 this.prev = 0;
18063 this.next = 0; // Resetting context._sent for legacy support of Babel's
18064 // function.sent implementation.
18065
18066 this.sent = this._sent = undefined$1;
18067 this.done = false;
18068 this.delegate = null;
18069 this.method = "next";
18070 this.arg = undefined$1;
18071 this.tryEntries.forEach(resetTryEntry);
18072
18073 if (!skipTempReset) {
18074 for (var name in this) {
18075 // Not sure about the optimal order of these conditions:
18076 if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
18077 this[name] = undefined$1;
18078 }
18079 }
18080 }
18081 },
18082 stop: function () {
18083 this.done = true;
18084 var rootEntry = this.tryEntries[0];
18085 var rootRecord = rootEntry.completion;
18086
18087 if (rootRecord.type === "throw") {
18088 throw rootRecord.arg;
18089 }
18090
18091 return this.rval;
18092 },
18093 dispatchException: function (exception) {
18094 if (this.done) {
18095 throw exception;
18096 }
18097
18098 var context = this;
18099
18100 function handle(loc, caught) {
18101 record.type = "throw";
18102 record.arg = exception;
18103 context.next = loc;
18104
18105 if (caught) {
18106 // If the dispatched exception was caught by a catch block,
18107 // then let that catch block handle the exception normally.
18108 context.method = "next";
18109 context.arg = undefined$1;
18110 }
18111
18112 return !!caught;
18113 }
18114
18115 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
18116 var entry = this.tryEntries[i];
18117 var record = entry.completion;
18118
18119 if (entry.tryLoc === "root") {
18120 // Exception thrown outside of any try block that could handle
18121 // it, so set the completion value of the entire function to
18122 // throw the exception.
18123 return handle("end");
18124 }
18125
18126 if (entry.tryLoc <= this.prev) {
18127 var hasCatch = hasOwn.call(entry, "catchLoc");
18128 var hasFinally = hasOwn.call(entry, "finallyLoc");
18129
18130 if (hasCatch && hasFinally) {
18131 if (this.prev < entry.catchLoc) {
18132 return handle(entry.catchLoc, true);
18133 } else if (this.prev < entry.finallyLoc) {
18134 return handle(entry.finallyLoc);
18135 }
18136 } else if (hasCatch) {
18137 if (this.prev < entry.catchLoc) {
18138 return handle(entry.catchLoc, true);
18139 }
18140 } else if (hasFinally) {
18141 if (this.prev < entry.finallyLoc) {
18142 return handle(entry.finallyLoc);
18143 }
18144 } else {
18145 throw new Error("try statement without catch or finally");
18146 }
18147 }
18148 }
18149 },
18150 abrupt: function (type, arg) {
18151 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
18152 var entry = this.tryEntries[i];
18153
18154 if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
18155 var finallyEntry = entry;
18156 break;
18157 }
18158 }
18159
18160 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
18161 // Ignore the finally entry if control is not jumping to a
18162 // location outside the try/catch block.
18163 finallyEntry = null;
18164 }
18165
18166 var record = finallyEntry ? finallyEntry.completion : {};
18167 record.type = type;
18168 record.arg = arg;
18169
18170 if (finallyEntry) {
18171 this.method = "next";
18172 this.next = finallyEntry.finallyLoc;
18173 return ContinueSentinel;
18174 }
18175
18176 return this.complete(record);
18177 },
18178 complete: function (record, afterLoc) {
18179 if (record.type === "throw") {
18180 throw record.arg;
18181 }
18182
18183 if (record.type === "break" || record.type === "continue") {
18184 this.next = record.arg;
18185 } else if (record.type === "return") {
18186 this.rval = this.arg = record.arg;
18187 this.method = "return";
18188 this.next = "end";
18189 } else if (record.type === "normal" && afterLoc) {
18190 this.next = afterLoc;
18191 }
18192
18193 return ContinueSentinel;
18194 },
18195 finish: function (finallyLoc) {
18196 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
18197 var entry = this.tryEntries[i];
18198
18199 if (entry.finallyLoc === finallyLoc) {
18200 this.complete(entry.completion, entry.afterLoc);
18201 resetTryEntry(entry);
18202 return ContinueSentinel;
18203 }
18204 }
18205 },
18206 "catch": function (tryLoc) {
18207 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
18208 var entry = this.tryEntries[i];
18209
18210 if (entry.tryLoc === tryLoc) {
18211 var record = entry.completion;
18212
18213 if (record.type === "throw") {
18214 var thrown = record.arg;
18215 resetTryEntry(entry);
18216 }
18217
18218 return thrown;
18219 }
18220 } // The context.catch method must only be called with a location
18221 // argument that corresponds to a known catch block.
18222
18223
18224 throw new Error("illegal catch attempt");
18225 },
18226 delegateYield: function (iterable, resultName, nextLoc) {
18227 this.delegate = {
18228 iterator: values(iterable),
18229 resultName: resultName,
18230 nextLoc: nextLoc
18231 };
18232
18233 if (this.method === "next") {
18234 // Deliberately forget the last sent value so that we don't
18235 // accidentally pass it on to the delegate.
18236 this.arg = undefined$1;
18237 }
18238
18239 return ContinueSentinel;
18240 }
18241 }; // Regardless of whether this script is executing as a CommonJS module
18242 // or not, return the runtime object so that we can declare the variable
18243 // regeneratorRuntime in the outer scope, which allows this module to be
18244 // injected easily by `bin/regenerator --include-runtime script.js`.
18245
18246 return exports;
18247 }( // If this script is executing as a CommonJS module, use module.exports
18248 // as the regeneratorRuntime namespace. Otherwise create a new empty
18249 // object. Either way, the resulting object will be used to initialize
18250 // the regeneratorRuntime variable at the top of this file.
18251 module.exports);
18252
18253 try {
18254 regeneratorRuntime = runtime;
18255 } catch (accidentalStrictMode) {
18256 // This module should not be running in strict mode, so the above
18257 // assignment should always work unless something is misconfigured. Just
18258 // in case runtime.js accidentally runs in strict mode, we can escape
18259 // strict mode using a global Function call. This could conceivably fail
18260 // if a Content Security Policy forbids using Function, but in that case
18261 // the proper solution is to fix the accidental strict mode problem. If
18262 // you've misconfigured your bundler to force strict mode and applied a
18263 // CSP to forbid Function, and you're not willing to fix either of those
18264 // problems, please detail your unique predicament in a GitHub issue.
18265 Function("r", "regeneratorRuntime = r")(runtime);
18266 }
18267 });
18268 var regenerator = runtime_1;
18269
18270 function _defineProperty$2(obj, key, value) {
18271 if (key in obj) {
18272 Object.defineProperty(obj, key, {
18273 value: value,
18274 enumerable: true,
18275 configurable: true,
18276 writable: true
18277 });
18278 } else {
18279 obj[key] = value;
18280 }
18281
18282 return obj;
18283 }
18284
18285 var defineProperty$6 = _defineProperty$2;
18286
18287 function _arrayWithoutHoles$1(arr) {
18288 if (Array.isArray(arr)) {
18289 for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) {
18290 arr2[i] = arr[i];
18291 }
18292
18293 return arr2;
18294 }
18295 }
18296
18297 var arrayWithoutHoles = _arrayWithoutHoles$1;
18298
18299 function _iterableToArray$1(iter) {
18300 if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
18301 }
18302
18303 var iterableToArray = _iterableToArray$1;
18304
18305 function _nonIterableSpread$1() {
18306 throw new TypeError("Invalid attempt to spread non-iterable instance");
18307 }
18308
18309 var nonIterableSpread = _nonIterableSpread$1;
18310
18311 function _toConsumableArray$1(arr) {
18312 return arrayWithoutHoles(arr) || iterableToArray(arr) || nonIterableSpread();
18313 }
18314
18315 var toConsumableArray = _toConsumableArray$1;
18316
18317 var _typeof_1 = createCommonjsModule$2(function (module) {
18318 function _typeof2(obj) {
18319 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
18320 _typeof2 = function _typeof2(obj) {
18321 return typeof obj;
18322 };
18323 } else {
18324 _typeof2 = function _typeof2(obj) {
18325 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
18326 };
18327 }
18328
18329 return _typeof2(obj);
18330 }
18331
18332 function _typeof(obj) {
18333 if (typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol") {
18334 module.exports = _typeof = function _typeof(obj) {
18335 return _typeof2(obj);
18336 };
18337 } else {
18338 module.exports = _typeof = function _typeof(obj) {
18339 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : _typeof2(obj);
18340 };
18341 }
18342
18343 return _typeof(obj);
18344 }
18345
18346 module.exports = _typeof;
18347 });
18348
18349 function _classCallCheck$1(instance, Constructor) {
18350 if (!(instance instanceof Constructor)) {
18351 throw new TypeError("Cannot call a class as a function");
18352 }
18353 }
18354
18355 var classCallCheck = _classCallCheck$1;
18356
18357 function _defineProperties$1(target, props) {
18358 for (var i = 0; i < props.length; i++) {
18359 var descriptor = props[i];
18360 descriptor.enumerable = descriptor.enumerable || false;
18361 descriptor.configurable = true;
18362 if ("value" in descriptor) descriptor.writable = true;
18363 Object.defineProperty(target, descriptor.key, descriptor);
18364 }
18365 }
18366
18367 function _createClass$1(Constructor, protoProps, staticProps) {
18368 if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
18369 if (staticProps) _defineProperties$1(Constructor, staticProps);
18370 return Constructor;
18371 }
18372
18373 var createClass = _createClass$1;
18374
18375 function _assertThisInitialized$2(self) {
18376 if (self === void 0) {
18377 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
18378 }
18379
18380 return self;
18381 }
18382
18383 var assertThisInitialized = _assertThisInitialized$2;
18384
18385 function _possibleConstructorReturn$1(self, call) {
18386 if (call && (_typeof_1(call) === "object" || typeof call === "function")) {
18387 return call;
18388 }
18389
18390 return assertThisInitialized(self);
18391 }
18392
18393 var possibleConstructorReturn = _possibleConstructorReturn$1;
18394 var getPrototypeOf = createCommonjsModule$2(function (module) {
18395 function _getPrototypeOf(o) {
18396 module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
18397 return o.__proto__ || Object.getPrototypeOf(o);
18398 };
18399 return _getPrototypeOf(o);
18400 }
18401
18402 module.exports = _getPrototypeOf;
18403 });
18404 var setPrototypeOf$1 = createCommonjsModule$2(function (module) {
18405 function _setPrototypeOf(o, p) {
18406 module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
18407 o.__proto__ = p;
18408 return o;
18409 };
18410
18411 return _setPrototypeOf(o, p);
18412 }
18413
18414 module.exports = _setPrototypeOf;
18415 });
18416
18417 function _inherits$1(subClass, superClass) {
18418 if (typeof superClass !== "function" && superClass !== null) {
18419 throw new TypeError("Super expression must either be null or a function");
18420 }
18421
18422 subClass.prototype = Object.create(superClass && superClass.prototype, {
18423 constructor: {
18424 value: subClass,
18425 writable: true,
18426 configurable: true
18427 }
18428 });
18429 if (superClass) setPrototypeOf$1(subClass, superClass);
18430 }
18431
18432 var inherits = _inherits$1; // Maps for number <-> hex string conversion
18433
18434 var byteToHex$2 = [];
18435
18436 for (var i$2 = 0; i$2 < 256; i$2++) {
18437 byteToHex$2[i$2] = (i$2 + 0x100).toString(16).substr(1);
18438 }
18439 /**
18440 * Represent binary UUID into it's string representation.
18441 *
18442 * @param buf - Buffer containing UUID bytes.
18443 * @param offset - Offset from the start of the buffer where the UUID is saved (not needed if the buffer starts with the UUID).
18444 *
18445 * @returns String representation of the UUID.
18446 */
18447
18448
18449 function stringifyUUID$1(buf, offset) {
18450 var i = offset || 0;
18451 var bth = byteToHex$2;
18452 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
18453 }
18454 /**
18455 * Generate 16 random bytes to be used as a base for UUID.
18456 *
18457 * @ignore
18458 */
18459
18460
18461 var random$1 = function () {
18462 if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
18463 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
18464 // Moderately fast, high quality
18465 var _rnds8 = new Uint8Array(16);
18466
18467 return function whatwgRNG() {
18468 crypto.getRandomValues(_rnds8);
18469 return _rnds8;
18470 };
18471 } // Math.random()-based (RNG)
18472 //
18473 // If all else fails, use Math.random().
18474 // It's fast, but is of unspecified quality.
18475
18476
18477 var _rnds = new Array(16);
18478
18479 return function () {
18480 for (var i = 0, r; i < 16; i++) {
18481 if ((i & 0x03) === 0) {
18482 r = Math.random() * 0x100000000;
18483 }
18484
18485 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
18486 }
18487
18488 return _rnds;
18489 }; // uuid.js
18490 //
18491 // Copyright (c) 2010-2012 Robert Kieffer
18492 // MIT License - http://opensource.org/licenses/mit-license.php
18493 // Unique ID creation requires a high quality random # generator. We feature
18494 // detect to determine the best RNG source, normalizing to a function that
18495 // returns 128-bits of randomness, since that's what's usually required
18496 // return require('./rng');
18497 }();
18498
18499 var byteToHex$1$1 = [];
18500
18501 for (var i$1$2 = 0; i$1$2 < 256; i$1$2++) {
18502 byteToHex$1$1[i$1$2] = (i$1$2 + 0x100).toString(16).substr(1);
18503 } // **`v1()` - Generate time-based UUID**
18504 //
18505 // Inspired by https://github.com/LiosK/UUID.js
18506 // and http://docs.python.org/library/uuid.html
18507 // random #'s we need to init node and clockseq
18508
18509
18510 var seedBytes$1 = random$1(); // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
18511
18512 var defaultNodeId$1 = [seedBytes$1[0] | 0x01, seedBytes$1[1], seedBytes$1[2], seedBytes$1[3], seedBytes$1[4], seedBytes$1[5]]; // Per 4.2.2, randomize (14 bit) clockseq
18513
18514 var defaultClockseq$1 = (seedBytes$1[6] << 8 | seedBytes$1[7]) & 0x3fff; // Previous uuid creation time
18515
18516 /**
18517 * UUIDv4 options.
18518 */
18519
18520 /**
18521 * Generate UUIDv4
18522 *
18523 * @param options - Options to be used instead of default generated values.
18524 * String 'binary' is a shorthand for uuid4({}, new Array(16)).
18525 * @param buf - If present the buffer will be filled with the generated UUID.
18526 * @param offset - Offset of the UUID from the start of the buffer.
18527 *
18528 * @returns UUIDv4
18529 */
18530
18531 function uuid4$1() {
18532 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
18533 var buf = arguments.length > 1 ? arguments[1] : undefined;
18534 var offset = arguments.length > 2 ? arguments[2] : undefined; // Deprecated - 'format' argument, as supported in v1.2
18535
18536 var i = buf && offset || 0;
18537
18538 if (typeof options === 'string') {
18539 buf = options === 'binary' ? new Array(16) : undefined;
18540 options = {};
18541 }
18542
18543 var rnds = options.random || (options.rng || random$1)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
18544
18545 rnds[6] = rnds[6] & 0x0f | 0x40;
18546 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
18547
18548 if (buf) {
18549 for (var ii = 0; ii < 16; ii++) {
18550 buf[i + ii] = rnds[ii];
18551 }
18552 }
18553
18554 return buf || stringifyUUID$1(rnds);
18555 } // Rollup will complain about mixing default and named exports in UMD build,
18556
18557
18558 function _typeof$2(obj) {
18559 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
18560 _typeof$2 = function (obj) {
18561 return typeof obj;
18562 };
18563 } else {
18564 _typeof$2 = function (obj) {
18565 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
18566 };
18567 }
18568
18569 return _typeof$2(obj);
18570 }
18571
18572 var commonjsGlobal$2 = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
18573
18574 function commonjsRequire$2() {
18575 throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
18576 }
18577
18578 function createCommonjsModule$1$1(fn, module) {
18579 return module = {
18580 exports: {}
18581 }, fn(module, module.exports), module.exports;
18582 }
18583
18584 var moment$1 = createCommonjsModule$1$1(function (module, exports) {
18585 (function (global, factory) {
18586 module.exports = factory();
18587 })(commonjsGlobal$2, function () {
18588 var hookCallback;
18589
18590 function hooks() {
18591 return hookCallback.apply(null, arguments);
18592 } // This is done to register the method called with moment()
18593 // without creating circular dependencies.
18594
18595
18596 function setHookCallback(callback) {
18597 hookCallback = callback;
18598 }
18599
18600 function isArray(input) {
18601 return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
18602 }
18603
18604 function isObject(input) {
18605 // IE8 will treat undefined and null as object if it wasn't for
18606 // input != null
18607 return input != null && Object.prototype.toString.call(input) === '[object Object]';
18608 }
18609
18610 function isObjectEmpty(obj) {
18611 if (Object.getOwnPropertyNames) {
18612 return Object.getOwnPropertyNames(obj).length === 0;
18613 } else {
18614 var k;
18615
18616 for (k in obj) {
18617 if (obj.hasOwnProperty(k)) {
18618 return false;
18619 }
18620 }
18621
18622 return true;
18623 }
18624 }
18625
18626 function isUndefined(input) {
18627 return input === void 0;
18628 }
18629
18630 function isNumber(input) {
18631 return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
18632 }
18633
18634 function isDate(input) {
18635 return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
18636 }
18637
18638 function map(arr, fn) {
18639 var res = [],
18640 i;
18641
18642 for (i = 0; i < arr.length; ++i) {
18643 res.push(fn(arr[i], i));
18644 }
18645
18646 return res;
18647 }
18648
18649 function hasOwnProp(a, b) {
18650 return Object.prototype.hasOwnProperty.call(a, b);
18651 }
18652
18653 function extend(a, b) {
18654 for (var i in b) {
18655 if (hasOwnProp(b, i)) {
18656 a[i] = b[i];
18657 }
18658 }
18659
18660 if (hasOwnProp(b, 'toString')) {
18661 a.toString = b.toString;
18662 }
18663
18664 if (hasOwnProp(b, 'valueOf')) {
18665 a.valueOf = b.valueOf;
18666 }
18667
18668 return a;
18669 }
18670
18671 function createUTC(input, format, locale, strict) {
18672 return createLocalOrUTC(input, format, locale, strict, true).utc();
18673 }
18674
18675 function defaultParsingFlags() {
18676 // We need to deep clone this object.
18677 return {
18678 empty: false,
18679 unusedTokens: [],
18680 unusedInput: [],
18681 overflow: -2,
18682 charsLeftOver: 0,
18683 nullInput: false,
18684 invalidMonth: null,
18685 invalidFormat: false,
18686 userInvalidated: false,
18687 iso: false,
18688 parsedDateParts: [],
18689 meridiem: null,
18690 rfc2822: false,
18691 weekdayMismatch: false
18692 };
18693 }
18694
18695 function getParsingFlags(m) {
18696 if (m._pf == null) {
18697 m._pf = defaultParsingFlags();
18698 }
18699
18700 return m._pf;
18701 }
18702
18703 var some;
18704
18705 if (Array.prototype.some) {
18706 some = Array.prototype.some;
18707 } else {
18708 some = function (fun) {
18709 var t = Object(this);
18710 var len = t.length >>> 0;
18711
18712 for (var i = 0; i < len; i++) {
18713 if (i in t && fun.call(this, t[i], i, t)) {
18714 return true;
18715 }
18716 }
18717
18718 return false;
18719 };
18720 }
18721
18722 function isValid(m) {
18723 if (m._isValid == null) {
18724 var flags = getParsingFlags(m);
18725 var parsedParts = some.call(flags.parsedDateParts, function (i) {
18726 return i != null;
18727 });
18728 var isNowValid = !isNaN(m._d.getTime()) && flags.overflow < 0 && !flags.empty && !flags.invalidMonth && !flags.invalidWeekday && !flags.weekdayMismatch && !flags.nullInput && !flags.invalidFormat && !flags.userInvalidated && (!flags.meridiem || flags.meridiem && parsedParts);
18729
18730 if (m._strict) {
18731 isNowValid = isNowValid && flags.charsLeftOver === 0 && flags.unusedTokens.length === 0 && flags.bigHour === undefined;
18732 }
18733
18734 if (Object.isFrozen == null || !Object.isFrozen(m)) {
18735 m._isValid = isNowValid;
18736 } else {
18737 return isNowValid;
18738 }
18739 }
18740
18741 return m._isValid;
18742 }
18743
18744 function createInvalid(flags) {
18745 var m = createUTC(NaN);
18746
18747 if (flags != null) {
18748 extend(getParsingFlags(m), flags);
18749 } else {
18750 getParsingFlags(m).userInvalidated = true;
18751 }
18752
18753 return m;
18754 } // Plugins that add properties should also add the key here (null value),
18755 // so we can properly clone ourselves.
18756
18757
18758 var momentProperties = hooks.momentProperties = [];
18759
18760 function copyConfig(to, from) {
18761 var i, prop, val;
18762
18763 if (!isUndefined(from._isAMomentObject)) {
18764 to._isAMomentObject = from._isAMomentObject;
18765 }
18766
18767 if (!isUndefined(from._i)) {
18768 to._i = from._i;
18769 }
18770
18771 if (!isUndefined(from._f)) {
18772 to._f = from._f;
18773 }
18774
18775 if (!isUndefined(from._l)) {
18776 to._l = from._l;
18777 }
18778
18779 if (!isUndefined(from._strict)) {
18780 to._strict = from._strict;
18781 }
18782
18783 if (!isUndefined(from._tzm)) {
18784 to._tzm = from._tzm;
18785 }
18786
18787 if (!isUndefined(from._isUTC)) {
18788 to._isUTC = from._isUTC;
18789 }
18790
18791 if (!isUndefined(from._offset)) {
18792 to._offset = from._offset;
18793 }
18794
18795 if (!isUndefined(from._pf)) {
18796 to._pf = getParsingFlags(from);
18797 }
18798
18799 if (!isUndefined(from._locale)) {
18800 to._locale = from._locale;
18801 }
18802
18803 if (momentProperties.length > 0) {
18804 for (i = 0; i < momentProperties.length; i++) {
18805 prop = momentProperties[i];
18806 val = from[prop];
18807
18808 if (!isUndefined(val)) {
18809 to[prop] = val;
18810 }
18811 }
18812 }
18813
18814 return to;
18815 }
18816
18817 var updateInProgress = false; // Moment prototype object
18818
18819 function Moment(config) {
18820 copyConfig(this, config);
18821 this._d = new Date(config._d != null ? config._d.getTime() : NaN);
18822
18823 if (!this.isValid()) {
18824 this._d = new Date(NaN);
18825 } // Prevent infinite loop in case updateOffset creates new moment
18826 // objects.
18827
18828
18829 if (updateInProgress === false) {
18830 updateInProgress = true;
18831 hooks.updateOffset(this);
18832 updateInProgress = false;
18833 }
18834 }
18835
18836 function isMoment(obj) {
18837 return obj instanceof Moment || obj != null && obj._isAMomentObject != null;
18838 }
18839
18840 function absFloor(number) {
18841 if (number < 0) {
18842 // -0 -> 0
18843 return Math.ceil(number) || 0;
18844 } else {
18845 return Math.floor(number);
18846 }
18847 }
18848
18849 function toInt(argumentForCoercion) {
18850 var coercedNumber = +argumentForCoercion,
18851 value = 0;
18852
18853 if (coercedNumber !== 0 && isFinite(coercedNumber)) {
18854 value = absFloor(coercedNumber);
18855 }
18856
18857 return value;
18858 } // compare two arrays, return the number of differences
18859
18860
18861 function compareArrays(array1, array2, dontConvert) {
18862 var len = Math.min(array1.length, array2.length),
18863 lengthDiff = Math.abs(array1.length - array2.length),
18864 diffs = 0,
18865 i;
18866
18867 for (i = 0; i < len; i++) {
18868 if (dontConvert && array1[i] !== array2[i] || !dontConvert && toInt(array1[i]) !== toInt(array2[i])) {
18869 diffs++;
18870 }
18871 }
18872
18873 return diffs + lengthDiff;
18874 }
18875
18876 function warn(msg) {
18877 if (hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) {
18878 console.warn('Deprecation warning: ' + msg);
18879 }
18880 }
18881
18882 function deprecate(msg, fn) {
18883 var firstTime = true;
18884 return extend(function () {
18885 if (hooks.deprecationHandler != null) {
18886 hooks.deprecationHandler(null, msg);
18887 }
18888
18889 if (firstTime) {
18890 var args = [];
18891 var arg;
18892
18893 for (var i = 0; i < arguments.length; i++) {
18894 arg = '';
18895
18896 if (typeof arguments[i] === 'object') {
18897 arg += '\n[' + i + '] ';
18898
18899 for (var key in arguments[0]) {
18900 arg += key + ': ' + arguments[0][key] + ', ';
18901 }
18902
18903 arg = arg.slice(0, -2); // Remove trailing comma and space
18904 } else {
18905 arg = arguments[i];
18906 }
18907
18908 args.push(arg);
18909 }
18910
18911 warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + new Error().stack);
18912 firstTime = false;
18913 }
18914
18915 return fn.apply(this, arguments);
18916 }, fn);
18917 }
18918
18919 var deprecations = {};
18920
18921 function deprecateSimple(name, msg) {
18922 if (hooks.deprecationHandler != null) {
18923 hooks.deprecationHandler(name, msg);
18924 }
18925
18926 if (!deprecations[name]) {
18927 warn(msg);
18928 deprecations[name] = true;
18929 }
18930 }
18931
18932 hooks.suppressDeprecationWarnings = false;
18933 hooks.deprecationHandler = null;
18934
18935 function isFunction(input) {
18936 return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
18937 }
18938
18939 function set(config) {
18940 var prop, i;
18941
18942 for (i in config) {
18943 prop = config[i];
18944
18945 if (isFunction(prop)) {
18946 this[i] = prop;
18947 } else {
18948 this['_' + i] = prop;
18949 }
18950 }
18951
18952 this._config = config; // Lenient ordinal parsing accepts just a number in addition to
18953 // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
18954 // TODO: Remove "ordinalParse" fallback in next major release.
18955
18956 this._dayOfMonthOrdinalParseLenient = new RegExp((this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + '|' + /\d{1,2}/.source);
18957 }
18958
18959 function mergeConfigs(parentConfig, childConfig) {
18960 var res = extend({}, parentConfig),
18961 prop;
18962
18963 for (prop in childConfig) {
18964 if (hasOwnProp(childConfig, prop)) {
18965 if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
18966 res[prop] = {};
18967 extend(res[prop], parentConfig[prop]);
18968 extend(res[prop], childConfig[prop]);
18969 } else if (childConfig[prop] != null) {
18970 res[prop] = childConfig[prop];
18971 } else {
18972 delete res[prop];
18973 }
18974 }
18975 }
18976
18977 for (prop in parentConfig) {
18978 if (hasOwnProp(parentConfig, prop) && !hasOwnProp(childConfig, prop) && isObject(parentConfig[prop])) {
18979 // make sure changes to properties don't modify parent config
18980 res[prop] = extend({}, res[prop]);
18981 }
18982 }
18983
18984 return res;
18985 }
18986
18987 function Locale(config) {
18988 if (config != null) {
18989 this.set(config);
18990 }
18991 }
18992
18993 var keys;
18994
18995 if (Object.keys) {
18996 keys = Object.keys;
18997 } else {
18998 keys = function (obj) {
18999 var i,
19000 res = [];
19001
19002 for (i in obj) {
19003 if (hasOwnProp(obj, i)) {
19004 res.push(i);
19005 }
19006 }
19007
19008 return res;
19009 };
19010 }
19011
19012 var defaultCalendar = {
19013 sameDay: '[Today at] LT',
19014 nextDay: '[Tomorrow at] LT',
19015 nextWeek: 'dddd [at] LT',
19016 lastDay: '[Yesterday at] LT',
19017 lastWeek: '[Last] dddd [at] LT',
19018 sameElse: 'L'
19019 };
19020
19021 function calendar(key, mom, now) {
19022 var output = this._calendar[key] || this._calendar['sameElse'];
19023 return isFunction(output) ? output.call(mom, now) : output;
19024 }
19025
19026 var defaultLongDateFormat = {
19027 LTS: 'h:mm:ss A',
19028 LT: 'h:mm A',
19029 L: 'MM/DD/YYYY',
19030 LL: 'MMMM D, YYYY',
19031 LLL: 'MMMM D, YYYY h:mm A',
19032 LLLL: 'dddd, MMMM D, YYYY h:mm A'
19033 };
19034
19035 function longDateFormat(key) {
19036 var format = this._longDateFormat[key],
19037 formatUpper = this._longDateFormat[key.toUpperCase()];
19038
19039 if (format || !formatUpper) {
19040 return format;
19041 }
19042
19043 this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
19044 return val.slice(1);
19045 });
19046 return this._longDateFormat[key];
19047 }
19048
19049 var defaultInvalidDate = 'Invalid date';
19050
19051 function invalidDate() {
19052 return this._invalidDate;
19053 }
19054
19055 var defaultOrdinal = '%d';
19056 var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
19057
19058 function ordinal(number) {
19059 return this._ordinal.replace('%d', number);
19060 }
19061
19062 var defaultRelativeTime = {
19063 future: 'in %s',
19064 past: '%s ago',
19065 s: 'a few seconds',
19066 ss: '%d seconds',
19067 m: 'a minute',
19068 mm: '%d minutes',
19069 h: 'an hour',
19070 hh: '%d hours',
19071 d: 'a day',
19072 dd: '%d days',
19073 M: 'a month',
19074 MM: '%d months',
19075 y: 'a year',
19076 yy: '%d years'
19077 };
19078
19079 function relativeTime(number, withoutSuffix, string, isFuture) {
19080 var output = this._relativeTime[string];
19081 return isFunction(output) ? output(number, withoutSuffix, string, isFuture) : output.replace(/%d/i, number);
19082 }
19083
19084 function pastFuture(diff, output) {
19085 var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
19086 return isFunction(format) ? format(output) : format.replace(/%s/i, output);
19087 }
19088
19089 var aliases = {};
19090
19091 function addUnitAlias(unit, shorthand) {
19092 var lowerCase = unit.toLowerCase();
19093 aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
19094 }
19095
19096 function normalizeUnits(units) {
19097 return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
19098 }
19099
19100 function normalizeObjectUnits(inputObject) {
19101 var normalizedInput = {},
19102 normalizedProp,
19103 prop;
19104
19105 for (prop in inputObject) {
19106 if (hasOwnProp(inputObject, prop)) {
19107 normalizedProp = normalizeUnits(prop);
19108
19109 if (normalizedProp) {
19110 normalizedInput[normalizedProp] = inputObject[prop];
19111 }
19112 }
19113 }
19114
19115 return normalizedInput;
19116 }
19117
19118 var priorities = {};
19119
19120 function addUnitPriority(unit, priority) {
19121 priorities[unit] = priority;
19122 }
19123
19124 function getPrioritizedUnits(unitsObj) {
19125 var units = [];
19126
19127 for (var u in unitsObj) {
19128 units.push({
19129 unit: u,
19130 priority: priorities[u]
19131 });
19132 }
19133
19134 units.sort(function (a, b) {
19135 return a.priority - b.priority;
19136 });
19137 return units;
19138 }
19139
19140 function zeroFill(number, targetLength, forceSign) {
19141 var absNumber = '' + Math.abs(number),
19142 zerosToFill = targetLength - absNumber.length,
19143 sign = number >= 0;
19144 return (sign ? forceSign ? '+' : '' : '-') + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
19145 }
19146
19147 var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
19148 var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
19149 var formatFunctions = {};
19150 var formatTokenFunctions = {}; // token: 'M'
19151 // padded: ['MM', 2]
19152 // ordinal: 'Mo'
19153 // callback: function () { this.month() + 1 }
19154
19155 function addFormatToken(token, padded, ordinal, callback) {
19156 var func = callback;
19157
19158 if (typeof callback === 'string') {
19159 func = function () {
19160 return this[callback]();
19161 };
19162 }
19163
19164 if (token) {
19165 formatTokenFunctions[token] = func;
19166 }
19167
19168 if (padded) {
19169 formatTokenFunctions[padded[0]] = function () {
19170 return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
19171 };
19172 }
19173
19174 if (ordinal) {
19175 formatTokenFunctions[ordinal] = function () {
19176 return this.localeData().ordinal(func.apply(this, arguments), token);
19177 };
19178 }
19179 }
19180
19181 function removeFormattingTokens(input) {
19182 if (input.match(/\[[\s\S]/)) {
19183 return input.replace(/^\[|\]$/g, '');
19184 }
19185
19186 return input.replace(/\\/g, '');
19187 }
19188
19189 function makeFormatFunction(format) {
19190 var array = format.match(formattingTokens),
19191 i,
19192 length;
19193
19194 for (i = 0, length = array.length; i < length; i++) {
19195 if (formatTokenFunctions[array[i]]) {
19196 array[i] = formatTokenFunctions[array[i]];
19197 } else {
19198 array[i] = removeFormattingTokens(array[i]);
19199 }
19200 }
19201
19202 return function (mom) {
19203 var output = '',
19204 i;
19205
19206 for (i = 0; i < length; i++) {
19207 output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
19208 }
19209
19210 return output;
19211 };
19212 } // format date using native date object
19213
19214
19215 function formatMoment(m, format) {
19216 if (!m.isValid()) {
19217 return m.localeData().invalidDate();
19218 }
19219
19220 format = expandFormat(format, m.localeData());
19221 formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
19222 return formatFunctions[format](m);
19223 }
19224
19225 function expandFormat(format, locale) {
19226 var i = 5;
19227
19228 function replaceLongDateFormatTokens(input) {
19229 return locale.longDateFormat(input) || input;
19230 }
19231
19232 localFormattingTokens.lastIndex = 0;
19233
19234 while (i >= 0 && localFormattingTokens.test(format)) {
19235 format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
19236 localFormattingTokens.lastIndex = 0;
19237 i -= 1;
19238 }
19239
19240 return format;
19241 }
19242
19243 var match1 = /\d/; // 0 - 9
19244
19245 var match2 = /\d\d/; // 00 - 99
19246
19247 var match3 = /\d{3}/; // 000 - 999
19248
19249 var match4 = /\d{4}/; // 0000 - 9999
19250
19251 var match6 = /[+-]?\d{6}/; // -999999 - 999999
19252
19253 var match1to2 = /\d\d?/; // 0 - 99
19254
19255 var match3to4 = /\d\d\d\d?/; // 999 - 9999
19256
19257 var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
19258
19259 var match1to3 = /\d{1,3}/; // 0 - 999
19260
19261 var match1to4 = /\d{1,4}/; // 0 - 9999
19262
19263 var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
19264
19265 var matchUnsigned = /\d+/; // 0 - inf
19266
19267 var matchSigned = /[+-]?\d+/; // -inf - inf
19268
19269 var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
19270
19271 var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
19272
19273 var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
19274 // any word (or two) characters or numbers including two/three word month in arabic.
19275 // includes scottish gaelic two word and hyphenated months
19276
19277 var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;
19278 var regexes = {};
19279
19280 function addRegexToken(token, regex, strictRegex) {
19281 regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
19282 return isStrict && strictRegex ? strictRegex : regex;
19283 };
19284 }
19285
19286 function getParseRegexForToken(token, config) {
19287 if (!hasOwnProp(regexes, token)) {
19288 return new RegExp(unescapeFormat(token));
19289 }
19290
19291 return regexes[token](config._strict, config._locale);
19292 } // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
19293
19294
19295 function unescapeFormat(s) {
19296 return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
19297 return p1 || p2 || p3 || p4;
19298 }));
19299 }
19300
19301 function regexEscape(s) {
19302 return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
19303 }
19304
19305 var tokens = {};
19306
19307 function addParseToken(token, callback) {
19308 var i,
19309 func = callback;
19310
19311 if (typeof token === 'string') {
19312 token = [token];
19313 }
19314
19315 if (isNumber(callback)) {
19316 func = function (input, array) {
19317 array[callback] = toInt(input);
19318 };
19319 }
19320
19321 for (i = 0; i < token.length; i++) {
19322 tokens[token[i]] = func;
19323 }
19324 }
19325
19326 function addWeekParseToken(token, callback) {
19327 addParseToken(token, function (input, array, config, token) {
19328 config._w = config._w || {};
19329 callback(input, config._w, config, token);
19330 });
19331 }
19332
19333 function addTimeToArrayFromToken(token, input, config) {
19334 if (input != null && hasOwnProp(tokens, token)) {
19335 tokens[token](input, config._a, config, token);
19336 }
19337 }
19338
19339 var YEAR = 0;
19340 var MONTH = 1;
19341 var DATE = 2;
19342 var HOUR = 3;
19343 var MINUTE = 4;
19344 var SECOND = 5;
19345 var MILLISECOND = 6;
19346 var WEEK = 7;
19347 var WEEKDAY = 8; // FORMATTING
19348
19349 addFormatToken('Y', 0, 0, function () {
19350 var y = this.year();
19351 return y <= 9999 ? '' + y : '+' + y;
19352 });
19353 addFormatToken(0, ['YY', 2], 0, function () {
19354 return this.year() % 100;
19355 });
19356 addFormatToken(0, ['YYYY', 4], 0, 'year');
19357 addFormatToken(0, ['YYYYY', 5], 0, 'year');
19358 addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); // ALIASES
19359
19360 addUnitAlias('year', 'y'); // PRIORITIES
19361
19362 addUnitPriority('year', 1); // PARSING
19363
19364 addRegexToken('Y', matchSigned);
19365 addRegexToken('YY', match1to2, match2);
19366 addRegexToken('YYYY', match1to4, match4);
19367 addRegexToken('YYYYY', match1to6, match6);
19368 addRegexToken('YYYYYY', match1to6, match6);
19369 addParseToken(['YYYYY', 'YYYYYY'], YEAR);
19370 addParseToken('YYYY', function (input, array) {
19371 array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
19372 });
19373 addParseToken('YY', function (input, array) {
19374 array[YEAR] = hooks.parseTwoDigitYear(input);
19375 });
19376 addParseToken('Y', function (input, array) {
19377 array[YEAR] = parseInt(input, 10);
19378 }); // HELPERS
19379
19380 function daysInYear(year) {
19381 return isLeapYear(year) ? 366 : 365;
19382 }
19383
19384 function isLeapYear(year) {
19385 return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
19386 } // HOOKS
19387
19388
19389 hooks.parseTwoDigitYear = function (input) {
19390 return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
19391 }; // MOMENTS
19392
19393
19394 var getSetYear = makeGetSet('FullYear', true);
19395
19396 function getIsLeapYear() {
19397 return isLeapYear(this.year());
19398 }
19399
19400 function makeGetSet(unit, keepTime) {
19401 return function (value) {
19402 if (value != null) {
19403 set$1(this, unit, value);
19404 hooks.updateOffset(this, keepTime);
19405 return this;
19406 } else {
19407 return get(this, unit);
19408 }
19409 };
19410 }
19411
19412 function get(mom, unit) {
19413 return mom.isValid() ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
19414 }
19415
19416 function set$1(mom, unit, value) {
19417 if (mom.isValid() && !isNaN(value)) {
19418 if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
19419 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
19420 } else {
19421 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
19422 }
19423 }
19424 } // MOMENTS
19425
19426
19427 function stringGet(units) {
19428 units = normalizeUnits(units);
19429
19430 if (isFunction(this[units])) {
19431 return this[units]();
19432 }
19433
19434 return this;
19435 }
19436
19437 function stringSet(units, value) {
19438 if (typeof units === 'object') {
19439 units = normalizeObjectUnits(units);
19440 var prioritized = getPrioritizedUnits(units);
19441
19442 for (var i = 0; i < prioritized.length; i++) {
19443 this[prioritized[i].unit](units[prioritized[i].unit]);
19444 }
19445 } else {
19446 units = normalizeUnits(units);
19447
19448 if (isFunction(this[units])) {
19449 return this[units](value);
19450 }
19451 }
19452
19453 return this;
19454 }
19455
19456 function mod(n, x) {
19457 return (n % x + x) % x;
19458 }
19459
19460 var indexOf;
19461
19462 if (Array.prototype.indexOf) {
19463 indexOf = Array.prototype.indexOf;
19464 } else {
19465 indexOf = function (o) {
19466 // I know
19467 var i;
19468
19469 for (i = 0; i < this.length; ++i) {
19470 if (this[i] === o) {
19471 return i;
19472 }
19473 }
19474
19475 return -1;
19476 };
19477 }
19478
19479 function daysInMonth(year, month) {
19480 if (isNaN(year) || isNaN(month)) {
19481 return NaN;
19482 }
19483
19484 var modMonth = mod(month, 12);
19485 year += (month - modMonth) / 12;
19486 return modMonth === 1 ? isLeapYear(year) ? 29 : 28 : 31 - modMonth % 7 % 2;
19487 } // FORMATTING
19488
19489
19490 addFormatToken('M', ['MM', 2], 'Mo', function () {
19491 return this.month() + 1;
19492 });
19493 addFormatToken('MMM', 0, 0, function (format) {
19494 return this.localeData().monthsShort(this, format);
19495 });
19496 addFormatToken('MMMM', 0, 0, function (format) {
19497 return this.localeData().months(this, format);
19498 }); // ALIASES
19499
19500 addUnitAlias('month', 'M'); // PRIORITY
19501
19502 addUnitPriority('month', 8); // PARSING
19503
19504 addRegexToken('M', match1to2);
19505 addRegexToken('MM', match1to2, match2);
19506 addRegexToken('MMM', function (isStrict, locale) {
19507 return locale.monthsShortRegex(isStrict);
19508 });
19509 addRegexToken('MMMM', function (isStrict, locale) {
19510 return locale.monthsRegex(isStrict);
19511 });
19512 addParseToken(['M', 'MM'], function (input, array) {
19513 array[MONTH] = toInt(input) - 1;
19514 });
19515 addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
19516 var month = config._locale.monthsParse(input, token, config._strict); // if we didn't find a month name, mark the date as invalid.
19517
19518
19519 if (month != null) {
19520 array[MONTH] = month;
19521 } else {
19522 getParsingFlags(config).invalidMonth = input;
19523 }
19524 }); // LOCALES
19525
19526 var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
19527 var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
19528
19529 function localeMonths(m, format) {
19530 if (!m) {
19531 return isArray(this._months) ? this._months : this._months['standalone'];
19532 }
19533
19534 return isArray(this._months) ? this._months[m.month()] : this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
19535 }
19536
19537 var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
19538
19539 function localeMonthsShort(m, format) {
19540 if (!m) {
19541 return isArray(this._monthsShort) ? this._monthsShort : this._monthsShort['standalone'];
19542 }
19543
19544 return isArray(this._monthsShort) ? this._monthsShort[m.month()] : this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
19545 }
19546
19547 function handleStrictParse(monthName, format, strict) {
19548 var i,
19549 ii,
19550 mom,
19551 llc = monthName.toLocaleLowerCase();
19552
19553 if (!this._monthsParse) {
19554 // this is not used
19555 this._monthsParse = [];
19556 this._longMonthsParse = [];
19557 this._shortMonthsParse = [];
19558
19559 for (i = 0; i < 12; ++i) {
19560 mom = createUTC([2000, i]);
19561 this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
19562 this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
19563 }
19564 }
19565
19566 if (strict) {
19567 if (format === 'MMM') {
19568 ii = indexOf.call(this._shortMonthsParse, llc);
19569 return ii !== -1 ? ii : null;
19570 } else {
19571 ii = indexOf.call(this._longMonthsParse, llc);
19572 return ii !== -1 ? ii : null;
19573 }
19574 } else {
19575 if (format === 'MMM') {
19576 ii = indexOf.call(this._shortMonthsParse, llc);
19577
19578 if (ii !== -1) {
19579 return ii;
19580 }
19581
19582 ii = indexOf.call(this._longMonthsParse, llc);
19583 return ii !== -1 ? ii : null;
19584 } else {
19585 ii = indexOf.call(this._longMonthsParse, llc);
19586
19587 if (ii !== -1) {
19588 return ii;
19589 }
19590
19591 ii = indexOf.call(this._shortMonthsParse, llc);
19592 return ii !== -1 ? ii : null;
19593 }
19594 }
19595 }
19596
19597 function localeMonthsParse(monthName, format, strict) {
19598 var i, mom, regex;
19599
19600 if (this._monthsParseExact) {
19601 return handleStrictParse.call(this, monthName, format, strict);
19602 }
19603
19604 if (!this._monthsParse) {
19605 this._monthsParse = [];
19606 this._longMonthsParse = [];
19607 this._shortMonthsParse = [];
19608 } // TODO: add sorting
19609 // Sorting makes sure if one month (or abbr) is a prefix of another
19610 // see sorting in computeMonthsParse
19611
19612
19613 for (i = 0; i < 12; i++) {
19614 // make the regex if we don't have it already
19615 mom = createUTC([2000, i]);
19616
19617 if (strict && !this._longMonthsParse[i]) {
19618 this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
19619 this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
19620 }
19621
19622 if (!strict && !this._monthsParse[i]) {
19623 regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
19624 this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
19625 } // test the regex
19626
19627
19628 if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
19629 return i;
19630 } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
19631 return i;
19632 } else if (!strict && this._monthsParse[i].test(monthName)) {
19633 return i;
19634 }
19635 }
19636 } // MOMENTS
19637
19638
19639 function setMonth(mom, value) {
19640 var dayOfMonth;
19641
19642 if (!mom.isValid()) {
19643 // No op
19644 return mom;
19645 }
19646
19647 if (typeof value === 'string') {
19648 if (/^\d+$/.test(value)) {
19649 value = toInt(value);
19650 } else {
19651 value = mom.localeData().monthsParse(value); // TODO: Another silent failure?
19652
19653 if (!isNumber(value)) {
19654 return mom;
19655 }
19656 }
19657 }
19658
19659 dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
19660
19661 mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
19662
19663 return mom;
19664 }
19665
19666 function getSetMonth(value) {
19667 if (value != null) {
19668 setMonth(this, value);
19669 hooks.updateOffset(this, true);
19670 return this;
19671 } else {
19672 return get(this, 'Month');
19673 }
19674 }
19675
19676 function getDaysInMonth() {
19677 return daysInMonth(this.year(), this.month());
19678 }
19679
19680 var defaultMonthsShortRegex = matchWord;
19681
19682 function monthsShortRegex(isStrict) {
19683 if (this._monthsParseExact) {
19684 if (!hasOwnProp(this, '_monthsRegex')) {
19685 computeMonthsParse.call(this);
19686 }
19687
19688 if (isStrict) {
19689 return this._monthsShortStrictRegex;
19690 } else {
19691 return this._monthsShortRegex;
19692 }
19693 } else {
19694 if (!hasOwnProp(this, '_monthsShortRegex')) {
19695 this._monthsShortRegex = defaultMonthsShortRegex;
19696 }
19697
19698 return this._monthsShortStrictRegex && isStrict ? this._monthsShortStrictRegex : this._monthsShortRegex;
19699 }
19700 }
19701
19702 var defaultMonthsRegex = matchWord;
19703
19704 function monthsRegex(isStrict) {
19705 if (this._monthsParseExact) {
19706 if (!hasOwnProp(this, '_monthsRegex')) {
19707 computeMonthsParse.call(this);
19708 }
19709
19710 if (isStrict) {
19711 return this._monthsStrictRegex;
19712 } else {
19713 return this._monthsRegex;
19714 }
19715 } else {
19716 if (!hasOwnProp(this, '_monthsRegex')) {
19717 this._monthsRegex = defaultMonthsRegex;
19718 }
19719
19720 return this._monthsStrictRegex && isStrict ? this._monthsStrictRegex : this._monthsRegex;
19721 }
19722 }
19723
19724 function computeMonthsParse() {
19725 function cmpLenRev(a, b) {
19726 return b.length - a.length;
19727 }
19728
19729 var shortPieces = [],
19730 longPieces = [],
19731 mixedPieces = [],
19732 i,
19733 mom;
19734
19735 for (i = 0; i < 12; i++) {
19736 // make the regex if we don't have it already
19737 mom = createUTC([2000, i]);
19738 shortPieces.push(this.monthsShort(mom, ''));
19739 longPieces.push(this.months(mom, ''));
19740 mixedPieces.push(this.months(mom, ''));
19741 mixedPieces.push(this.monthsShort(mom, ''));
19742 } // Sorting makes sure if one month (or abbr) is a prefix of another it
19743 // will match the longer piece.
19744
19745
19746 shortPieces.sort(cmpLenRev);
19747 longPieces.sort(cmpLenRev);
19748 mixedPieces.sort(cmpLenRev);
19749
19750 for (i = 0; i < 12; i++) {
19751 shortPieces[i] = regexEscape(shortPieces[i]);
19752 longPieces[i] = regexEscape(longPieces[i]);
19753 }
19754
19755 for (i = 0; i < 24; i++) {
19756 mixedPieces[i] = regexEscape(mixedPieces[i]);
19757 }
19758
19759 this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
19760 this._monthsShortRegex = this._monthsRegex;
19761 this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
19762 this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
19763 }
19764
19765 function createDate(y, m, d, h, M, s, ms) {
19766 // can't just apply() to create a date:
19767 // https://stackoverflow.com/q/181348
19768 var date; // the date constructor remaps years 0-99 to 1900-1999
19769
19770 if (y < 100 && y >= 0) {
19771 // preserve leap years using a full 400 year cycle, then reset
19772 date = new Date(y + 400, m, d, h, M, s, ms);
19773
19774 if (isFinite(date.getFullYear())) {
19775 date.setFullYear(y);
19776 }
19777 } else {
19778 date = new Date(y, m, d, h, M, s, ms);
19779 }
19780
19781 return date;
19782 }
19783
19784 function createUTCDate(y) {
19785 var date; // the Date.UTC function remaps years 0-99 to 1900-1999
19786
19787 if (y < 100 && y >= 0) {
19788 var args = Array.prototype.slice.call(arguments); // preserve leap years using a full 400 year cycle, then reset
19789
19790 args[0] = y + 400;
19791 date = new Date(Date.UTC.apply(null, args));
19792
19793 if (isFinite(date.getUTCFullYear())) {
19794 date.setUTCFullYear(y);
19795 }
19796 } else {
19797 date = new Date(Date.UTC.apply(null, arguments));
19798 }
19799
19800 return date;
19801 } // start-of-first-week - start-of-year
19802
19803
19804 function firstWeekOffset(year, dow, doy) {
19805 var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
19806 fwd = 7 + dow - doy,
19807 // first-week day local weekday -- which local weekday is fwd
19808 fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
19809 return -fwdlw + fwd - 1;
19810 } // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
19811
19812
19813 function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
19814 var localWeekday = (7 + weekday - dow) % 7,
19815 weekOffset = firstWeekOffset(year, dow, doy),
19816 dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
19817 resYear,
19818 resDayOfYear;
19819
19820 if (dayOfYear <= 0) {
19821 resYear = year - 1;
19822 resDayOfYear = daysInYear(resYear) + dayOfYear;
19823 } else if (dayOfYear > daysInYear(year)) {
19824 resYear = year + 1;
19825 resDayOfYear = dayOfYear - daysInYear(year);
19826 } else {
19827 resYear = year;
19828 resDayOfYear = dayOfYear;
19829 }
19830
19831 return {
19832 year: resYear,
19833 dayOfYear: resDayOfYear
19834 };
19835 }
19836
19837 function weekOfYear(mom, dow, doy) {
19838 var weekOffset = firstWeekOffset(mom.year(), dow, doy),
19839 week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
19840 resWeek,
19841 resYear;
19842
19843 if (week < 1) {
19844 resYear = mom.year() - 1;
19845 resWeek = week + weeksInYear(resYear, dow, doy);
19846 } else if (week > weeksInYear(mom.year(), dow, doy)) {
19847 resWeek = week - weeksInYear(mom.year(), dow, doy);
19848 resYear = mom.year() + 1;
19849 } else {
19850 resYear = mom.year();
19851 resWeek = week;
19852 }
19853
19854 return {
19855 week: resWeek,
19856 year: resYear
19857 };
19858 }
19859
19860 function weeksInYear(year, dow, doy) {
19861 var weekOffset = firstWeekOffset(year, dow, doy),
19862 weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
19863 return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
19864 } // FORMATTING
19865
19866
19867 addFormatToken('w', ['ww', 2], 'wo', 'week');
19868 addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); // ALIASES
19869
19870 addUnitAlias('week', 'w');
19871 addUnitAlias('isoWeek', 'W'); // PRIORITIES
19872
19873 addUnitPriority('week', 5);
19874 addUnitPriority('isoWeek', 5); // PARSING
19875
19876 addRegexToken('w', match1to2);
19877 addRegexToken('ww', match1to2, match2);
19878 addRegexToken('W', match1to2);
19879 addRegexToken('WW', match1to2, match2);
19880 addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
19881 week[token.substr(0, 1)] = toInt(input);
19882 }); // HELPERS
19883 // LOCALES
19884
19885 function localeWeek(mom) {
19886 return weekOfYear(mom, this._week.dow, this._week.doy).week;
19887 }
19888
19889 var defaultLocaleWeek = {
19890 dow: 0,
19891 // Sunday is the first day of the week.
19892 doy: 6 // The week that contains Jan 6th is the first week of the year.
19893
19894 };
19895
19896 function localeFirstDayOfWeek() {
19897 return this._week.dow;
19898 }
19899
19900 function localeFirstDayOfYear() {
19901 return this._week.doy;
19902 } // MOMENTS
19903
19904
19905 function getSetWeek(input) {
19906 var week = this.localeData().week(this);
19907 return input == null ? week : this.add((input - week) * 7, 'd');
19908 }
19909
19910 function getSetISOWeek(input) {
19911 var week = weekOfYear(this, 1, 4).week;
19912 return input == null ? week : this.add((input - week) * 7, 'd');
19913 } // FORMATTING
19914
19915
19916 addFormatToken('d', 0, 'do', 'day');
19917 addFormatToken('dd', 0, 0, function (format) {
19918 return this.localeData().weekdaysMin(this, format);
19919 });
19920 addFormatToken('ddd', 0, 0, function (format) {
19921 return this.localeData().weekdaysShort(this, format);
19922 });
19923 addFormatToken('dddd', 0, 0, function (format) {
19924 return this.localeData().weekdays(this, format);
19925 });
19926 addFormatToken('e', 0, 0, 'weekday');
19927 addFormatToken('E', 0, 0, 'isoWeekday'); // ALIASES
19928
19929 addUnitAlias('day', 'd');
19930 addUnitAlias('weekday', 'e');
19931 addUnitAlias('isoWeekday', 'E'); // PRIORITY
19932
19933 addUnitPriority('day', 11);
19934 addUnitPriority('weekday', 11);
19935 addUnitPriority('isoWeekday', 11); // PARSING
19936
19937 addRegexToken('d', match1to2);
19938 addRegexToken('e', match1to2);
19939 addRegexToken('E', match1to2);
19940 addRegexToken('dd', function (isStrict, locale) {
19941 return locale.weekdaysMinRegex(isStrict);
19942 });
19943 addRegexToken('ddd', function (isStrict, locale) {
19944 return locale.weekdaysShortRegex(isStrict);
19945 });
19946 addRegexToken('dddd', function (isStrict, locale) {
19947 return locale.weekdaysRegex(isStrict);
19948 });
19949 addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
19950 var weekday = config._locale.weekdaysParse(input, token, config._strict); // if we didn't get a weekday name, mark the date as invalid
19951
19952
19953 if (weekday != null) {
19954 week.d = weekday;
19955 } else {
19956 getParsingFlags(config).invalidWeekday = input;
19957 }
19958 });
19959 addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
19960 week[token] = toInt(input);
19961 }); // HELPERS
19962
19963 function parseWeekday(input, locale) {
19964 if (typeof input !== 'string') {
19965 return input;
19966 }
19967
19968 if (!isNaN(input)) {
19969 return parseInt(input, 10);
19970 }
19971
19972 input = locale.weekdaysParse(input);
19973
19974 if (typeof input === 'number') {
19975 return input;
19976 }
19977
19978 return null;
19979 }
19980
19981 function parseIsoWeekday(input, locale) {
19982 if (typeof input === 'string') {
19983 return locale.weekdaysParse(input) % 7 || 7;
19984 }
19985
19986 return isNaN(input) ? null : input;
19987 } // LOCALES
19988
19989
19990 function shiftWeekdays(ws, n) {
19991 return ws.slice(n, 7).concat(ws.slice(0, n));
19992 }
19993
19994 var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
19995
19996 function localeWeekdays(m, format) {
19997 var weekdays = isArray(this._weekdays) ? this._weekdays : this._weekdays[m && m !== true && this._weekdays.isFormat.test(format) ? 'format' : 'standalone'];
19998 return m === true ? shiftWeekdays(weekdays, this._week.dow) : m ? weekdays[m.day()] : weekdays;
19999 }
20000
20001 var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
20002
20003 function localeWeekdaysShort(m) {
20004 return m === true ? shiftWeekdays(this._weekdaysShort, this._week.dow) : m ? this._weekdaysShort[m.day()] : this._weekdaysShort;
20005 }
20006
20007 var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
20008
20009 function localeWeekdaysMin(m) {
20010 return m === true ? shiftWeekdays(this._weekdaysMin, this._week.dow) : m ? this._weekdaysMin[m.day()] : this._weekdaysMin;
20011 }
20012
20013 function handleStrictParse$1(weekdayName, format, strict) {
20014 var i,
20015 ii,
20016 mom,
20017 llc = weekdayName.toLocaleLowerCase();
20018
20019 if (!this._weekdaysParse) {
20020 this._weekdaysParse = [];
20021 this._shortWeekdaysParse = [];
20022 this._minWeekdaysParse = [];
20023
20024 for (i = 0; i < 7; ++i) {
20025 mom = createUTC([2000, 1]).day(i);
20026 this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
20027 this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
20028 this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
20029 }
20030 }
20031
20032 if (strict) {
20033 if (format === 'dddd') {
20034 ii = indexOf.call(this._weekdaysParse, llc);
20035 return ii !== -1 ? ii : null;
20036 } else if (format === 'ddd') {
20037 ii = indexOf.call(this._shortWeekdaysParse, llc);
20038 return ii !== -1 ? ii : null;
20039 } else {
20040 ii = indexOf.call(this._minWeekdaysParse, llc);
20041 return ii !== -1 ? ii : null;
20042 }
20043 } else {
20044 if (format === 'dddd') {
20045 ii = indexOf.call(this._weekdaysParse, llc);
20046
20047 if (ii !== -1) {
20048 return ii;
20049 }
20050
20051 ii = indexOf.call(this._shortWeekdaysParse, llc);
20052
20053 if (ii !== -1) {
20054 return ii;
20055 }
20056
20057 ii = indexOf.call(this._minWeekdaysParse, llc);
20058 return ii !== -1 ? ii : null;
20059 } else if (format === 'ddd') {
20060 ii = indexOf.call(this._shortWeekdaysParse, llc);
20061
20062 if (ii !== -1) {
20063 return ii;
20064 }
20065
20066 ii = indexOf.call(this._weekdaysParse, llc);
20067
20068 if (ii !== -1) {
20069 return ii;
20070 }
20071
20072 ii = indexOf.call(this._minWeekdaysParse, llc);
20073 return ii !== -1 ? ii : null;
20074 } else {
20075 ii = indexOf.call(this._minWeekdaysParse, llc);
20076
20077 if (ii !== -1) {
20078 return ii;
20079 }
20080
20081 ii = indexOf.call(this._weekdaysParse, llc);
20082
20083 if (ii !== -1) {
20084 return ii;
20085 }
20086
20087 ii = indexOf.call(this._shortWeekdaysParse, llc);
20088 return ii !== -1 ? ii : null;
20089 }
20090 }
20091 }
20092
20093 function localeWeekdaysParse(weekdayName, format, strict) {
20094 var i, mom, regex;
20095
20096 if (this._weekdaysParseExact) {
20097 return handleStrictParse$1.call(this, weekdayName, format, strict);
20098 }
20099
20100 if (!this._weekdaysParse) {
20101 this._weekdaysParse = [];
20102 this._minWeekdaysParse = [];
20103 this._shortWeekdaysParse = [];
20104 this._fullWeekdaysParse = [];
20105 }
20106
20107 for (i = 0; i < 7; i++) {
20108 // make the regex if we don't have it already
20109 mom = createUTC([2000, 1]).day(i);
20110
20111 if (strict && !this._fullWeekdaysParse[i]) {
20112 this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', 'i');
20113 this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', 'i');
20114 this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', 'i');
20115 }
20116
20117 if (!this._weekdaysParse[i]) {
20118 regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
20119 this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
20120 } // test the regex
20121
20122
20123 if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
20124 return i;
20125 } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
20126 return i;
20127 } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
20128 return i;
20129 } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
20130 return i;
20131 }
20132 }
20133 } // MOMENTS
20134
20135
20136 function getSetDayOfWeek(input) {
20137 if (!this.isValid()) {
20138 return input != null ? this : NaN;
20139 }
20140
20141 var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
20142
20143 if (input != null) {
20144 input = parseWeekday(input, this.localeData());
20145 return this.add(input - day, 'd');
20146 } else {
20147 return day;
20148 }
20149 }
20150
20151 function getSetLocaleDayOfWeek(input) {
20152 if (!this.isValid()) {
20153 return input != null ? this : NaN;
20154 }
20155
20156 var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
20157 return input == null ? weekday : this.add(input - weekday, 'd');
20158 }
20159
20160 function getSetISODayOfWeek(input) {
20161 if (!this.isValid()) {
20162 return input != null ? this : NaN;
20163 } // behaves the same as moment#day except
20164 // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
20165 // as a setter, sunday should belong to the previous week.
20166
20167
20168 if (input != null) {
20169 var weekday = parseIsoWeekday(input, this.localeData());
20170 return this.day(this.day() % 7 ? weekday : weekday - 7);
20171 } else {
20172 return this.day() || 7;
20173 }
20174 }
20175
20176 var defaultWeekdaysRegex = matchWord;
20177
20178 function weekdaysRegex(isStrict) {
20179 if (this._weekdaysParseExact) {
20180 if (!hasOwnProp(this, '_weekdaysRegex')) {
20181 computeWeekdaysParse.call(this);
20182 }
20183
20184 if (isStrict) {
20185 return this._weekdaysStrictRegex;
20186 } else {
20187 return this._weekdaysRegex;
20188 }
20189 } else {
20190 if (!hasOwnProp(this, '_weekdaysRegex')) {
20191 this._weekdaysRegex = defaultWeekdaysRegex;
20192 }
20193
20194 return this._weekdaysStrictRegex && isStrict ? this._weekdaysStrictRegex : this._weekdaysRegex;
20195 }
20196 }
20197
20198 var defaultWeekdaysShortRegex = matchWord;
20199
20200 function weekdaysShortRegex(isStrict) {
20201 if (this._weekdaysParseExact) {
20202 if (!hasOwnProp(this, '_weekdaysRegex')) {
20203 computeWeekdaysParse.call(this);
20204 }
20205
20206 if (isStrict) {
20207 return this._weekdaysShortStrictRegex;
20208 } else {
20209 return this._weekdaysShortRegex;
20210 }
20211 } else {
20212 if (!hasOwnProp(this, '_weekdaysShortRegex')) {
20213 this._weekdaysShortRegex = defaultWeekdaysShortRegex;
20214 }
20215
20216 return this._weekdaysShortStrictRegex && isStrict ? this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
20217 }
20218 }
20219
20220 var defaultWeekdaysMinRegex = matchWord;
20221
20222 function weekdaysMinRegex(isStrict) {
20223 if (this._weekdaysParseExact) {
20224 if (!hasOwnProp(this, '_weekdaysRegex')) {
20225 computeWeekdaysParse.call(this);
20226 }
20227
20228 if (isStrict) {
20229 return this._weekdaysMinStrictRegex;
20230 } else {
20231 return this._weekdaysMinRegex;
20232 }
20233 } else {
20234 if (!hasOwnProp(this, '_weekdaysMinRegex')) {
20235 this._weekdaysMinRegex = defaultWeekdaysMinRegex;
20236 }
20237
20238 return this._weekdaysMinStrictRegex && isStrict ? this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
20239 }
20240 }
20241
20242 function computeWeekdaysParse() {
20243 function cmpLenRev(a, b) {
20244 return b.length - a.length;
20245 }
20246
20247 var minPieces = [],
20248 shortPieces = [],
20249 longPieces = [],
20250 mixedPieces = [],
20251 i,
20252 mom,
20253 minp,
20254 shortp,
20255 longp;
20256
20257 for (i = 0; i < 7; i++) {
20258 // make the regex if we don't have it already
20259 mom = createUTC([2000, 1]).day(i);
20260 minp = this.weekdaysMin(mom, '');
20261 shortp = this.weekdaysShort(mom, '');
20262 longp = this.weekdays(mom, '');
20263 minPieces.push(minp);
20264 shortPieces.push(shortp);
20265 longPieces.push(longp);
20266 mixedPieces.push(minp);
20267 mixedPieces.push(shortp);
20268 mixedPieces.push(longp);
20269 } // Sorting makes sure if one weekday (or abbr) is a prefix of another it
20270 // will match the longer piece.
20271
20272
20273 minPieces.sort(cmpLenRev);
20274 shortPieces.sort(cmpLenRev);
20275 longPieces.sort(cmpLenRev);
20276 mixedPieces.sort(cmpLenRev);
20277
20278 for (i = 0; i < 7; i++) {
20279 shortPieces[i] = regexEscape(shortPieces[i]);
20280 longPieces[i] = regexEscape(longPieces[i]);
20281 mixedPieces[i] = regexEscape(mixedPieces[i]);
20282 }
20283
20284 this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
20285 this._weekdaysShortRegex = this._weekdaysRegex;
20286 this._weekdaysMinRegex = this._weekdaysRegex;
20287 this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
20288 this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
20289 this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
20290 } // FORMATTING
20291
20292
20293 function hFormat() {
20294 return this.hours() % 12 || 12;
20295 }
20296
20297 function kFormat() {
20298 return this.hours() || 24;
20299 }
20300
20301 addFormatToken('H', ['HH', 2], 0, 'hour');
20302 addFormatToken('h', ['hh', 2], 0, hFormat);
20303 addFormatToken('k', ['kk', 2], 0, kFormat);
20304 addFormatToken('hmm', 0, 0, function () {
20305 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
20306 });
20307 addFormatToken('hmmss', 0, 0, function () {
20308 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
20309 });
20310 addFormatToken('Hmm', 0, 0, function () {
20311 return '' + this.hours() + zeroFill(this.minutes(), 2);
20312 });
20313 addFormatToken('Hmmss', 0, 0, function () {
20314 return '' + this.hours() + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
20315 });
20316
20317 function meridiem(token, lowercase) {
20318 addFormatToken(token, 0, 0, function () {
20319 return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
20320 });
20321 }
20322
20323 meridiem('a', true);
20324 meridiem('A', false); // ALIASES
20325
20326 addUnitAlias('hour', 'h'); // PRIORITY
20327
20328 addUnitPriority('hour', 13); // PARSING
20329
20330 function matchMeridiem(isStrict, locale) {
20331 return locale._meridiemParse;
20332 }
20333
20334 addRegexToken('a', matchMeridiem);
20335 addRegexToken('A', matchMeridiem);
20336 addRegexToken('H', match1to2);
20337 addRegexToken('h', match1to2);
20338 addRegexToken('k', match1to2);
20339 addRegexToken('HH', match1to2, match2);
20340 addRegexToken('hh', match1to2, match2);
20341 addRegexToken('kk', match1to2, match2);
20342 addRegexToken('hmm', match3to4);
20343 addRegexToken('hmmss', match5to6);
20344 addRegexToken('Hmm', match3to4);
20345 addRegexToken('Hmmss', match5to6);
20346 addParseToken(['H', 'HH'], HOUR);
20347 addParseToken(['k', 'kk'], function (input, array, config) {
20348 var kInput = toInt(input);
20349 array[HOUR] = kInput === 24 ? 0 : kInput;
20350 });
20351 addParseToken(['a', 'A'], function (input, array, config) {
20352 config._isPm = config._locale.isPM(input);
20353 config._meridiem = input;
20354 });
20355 addParseToken(['h', 'hh'], function (input, array, config) {
20356 array[HOUR] = toInt(input);
20357 getParsingFlags(config).bigHour = true;
20358 });
20359 addParseToken('hmm', function (input, array, config) {
20360 var pos = input.length - 2;
20361 array[HOUR] = toInt(input.substr(0, pos));
20362 array[MINUTE] = toInt(input.substr(pos));
20363 getParsingFlags(config).bigHour = true;
20364 });
20365 addParseToken('hmmss', function (input, array, config) {
20366 var pos1 = input.length - 4;
20367 var pos2 = input.length - 2;
20368 array[HOUR] = toInt(input.substr(0, pos1));
20369 array[MINUTE] = toInt(input.substr(pos1, 2));
20370 array[SECOND] = toInt(input.substr(pos2));
20371 getParsingFlags(config).bigHour = true;
20372 });
20373 addParseToken('Hmm', function (input, array, config) {
20374 var pos = input.length - 2;
20375 array[HOUR] = toInt(input.substr(0, pos));
20376 array[MINUTE] = toInt(input.substr(pos));
20377 });
20378 addParseToken('Hmmss', function (input, array, config) {
20379 var pos1 = input.length - 4;
20380 var pos2 = input.length - 2;
20381 array[HOUR] = toInt(input.substr(0, pos1));
20382 array[MINUTE] = toInt(input.substr(pos1, 2));
20383 array[SECOND] = toInt(input.substr(pos2));
20384 }); // LOCALES
20385
20386 function localeIsPM(input) {
20387 // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
20388 // Using charAt should be more compatible.
20389 return (input + '').toLowerCase().charAt(0) === 'p';
20390 }
20391
20392 var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
20393
20394 function localeMeridiem(hours, minutes, isLower) {
20395 if (hours > 11) {
20396 return isLower ? 'pm' : 'PM';
20397 } else {
20398 return isLower ? 'am' : 'AM';
20399 }
20400 } // MOMENTS
20401 // Setting the hour should keep the time, because the user explicitly
20402 // specified which hour they want. So trying to maintain the same hour (in
20403 // a new timezone) makes sense. Adding/subtracting hours does not follow
20404 // this rule.
20405
20406
20407 var getSetHour = makeGetSet('Hours', true);
20408 var baseConfig = {
20409 calendar: defaultCalendar,
20410 longDateFormat: defaultLongDateFormat,
20411 invalidDate: defaultInvalidDate,
20412 ordinal: defaultOrdinal,
20413 dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
20414 relativeTime: defaultRelativeTime,
20415 months: defaultLocaleMonths,
20416 monthsShort: defaultLocaleMonthsShort,
20417 week: defaultLocaleWeek,
20418 weekdays: defaultLocaleWeekdays,
20419 weekdaysMin: defaultLocaleWeekdaysMin,
20420 weekdaysShort: defaultLocaleWeekdaysShort,
20421 meridiemParse: defaultLocaleMeridiemParse
20422 }; // internal storage for locale config files
20423
20424 var locales = {};
20425 var localeFamilies = {};
20426 var globalLocale;
20427
20428 function normalizeLocale(key) {
20429 return key ? key.toLowerCase().replace('_', '-') : key;
20430 } // pick the locale from the array
20431 // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
20432 // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
20433
20434
20435 function chooseLocale(names) {
20436 var i = 0,
20437 j,
20438 next,
20439 locale,
20440 split;
20441
20442 while (i < names.length) {
20443 split = normalizeLocale(names[i]).split('-');
20444 j = split.length;
20445 next = normalizeLocale(names[i + 1]);
20446 next = next ? next.split('-') : null;
20447
20448 while (j > 0) {
20449 locale = loadLocale(split.slice(0, j).join('-'));
20450
20451 if (locale) {
20452 return locale;
20453 }
20454
20455 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
20456 //the next array item is better than a shallower substring of this one
20457 break;
20458 }
20459
20460 j--;
20461 }
20462
20463 i++;
20464 }
20465
20466 return globalLocale;
20467 }
20468
20469 function loadLocale(name) {
20470 var oldLocale = null; // TODO: Find a better way to register and load all the locales in Node
20471
20472 if (!locales[name] && 'object' !== 'undefined' && module && module.exports) {
20473 try {
20474 oldLocale = globalLocale._abbr;
20475 var aliasedRequire = commonjsRequire$2;
20476 aliasedRequire('./locale/' + name);
20477 getSetGlobalLocale(oldLocale);
20478 } catch (e) {}
20479 }
20480
20481 return locales[name];
20482 } // This function will load locale and then set the global locale. If
20483 // no arguments are passed in, it will simply return the current global
20484 // locale key.
20485
20486
20487 function getSetGlobalLocale(key, values) {
20488 var data;
20489
20490 if (key) {
20491 if (isUndefined(values)) {
20492 data = getLocale(key);
20493 } else {
20494 data = defineLocale(key, values);
20495 }
20496
20497 if (data) {
20498 // moment.duration._locale = moment._locale = data;
20499 globalLocale = data;
20500 } else {
20501 if (typeof console !== 'undefined' && console.warn) {
20502 //warn user if arguments are passed but the locale could not be set
20503 console.warn('Locale ' + key + ' not found. Did you forget to load it?');
20504 }
20505 }
20506 }
20507
20508 return globalLocale._abbr;
20509 }
20510
20511 function defineLocale(name, config) {
20512 if (config !== null) {
20513 var locale,
20514 parentConfig = baseConfig;
20515 config.abbr = name;
20516
20517 if (locales[name] != null) {
20518 deprecateSimple('defineLocaleOverride', 'use moment.updateLocale(localeName, config) to change ' + 'an existing locale. moment.defineLocale(localeName, ' + 'config) should only be used for creating a new locale ' + 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
20519 parentConfig = locales[name]._config;
20520 } else if (config.parentLocale != null) {
20521 if (locales[config.parentLocale] != null) {
20522 parentConfig = locales[config.parentLocale]._config;
20523 } else {
20524 locale = loadLocale(config.parentLocale);
20525
20526 if (locale != null) {
20527 parentConfig = locale._config;
20528 } else {
20529 if (!localeFamilies[config.parentLocale]) {
20530 localeFamilies[config.parentLocale] = [];
20531 }
20532
20533 localeFamilies[config.parentLocale].push({
20534 name: name,
20535 config: config
20536 });
20537 return null;
20538 }
20539 }
20540 }
20541
20542 locales[name] = new Locale(mergeConfigs(parentConfig, config));
20543
20544 if (localeFamilies[name]) {
20545 localeFamilies[name].forEach(function (x) {
20546 defineLocale(x.name, x.config);
20547 });
20548 } // backwards compat for now: also set the locale
20549 // make sure we set the locale AFTER all child locales have been
20550 // created, so we won't end up with the child locale set.
20551
20552
20553 getSetGlobalLocale(name);
20554 return locales[name];
20555 } else {
20556 // useful for testing
20557 delete locales[name];
20558 return null;
20559 }
20560 }
20561
20562 function updateLocale(name, config) {
20563 if (config != null) {
20564 var locale,
20565 tmpLocale,
20566 parentConfig = baseConfig; // MERGE
20567
20568 tmpLocale = loadLocale(name);
20569
20570 if (tmpLocale != null) {
20571 parentConfig = tmpLocale._config;
20572 }
20573
20574 config = mergeConfigs(parentConfig, config);
20575 locale = new Locale(config);
20576 locale.parentLocale = locales[name];
20577 locales[name] = locale; // backwards compat for now: also set the locale
20578
20579 getSetGlobalLocale(name);
20580 } else {
20581 // pass null for config to unupdate, useful for tests
20582 if (locales[name] != null) {
20583 if (locales[name].parentLocale != null) {
20584 locales[name] = locales[name].parentLocale;
20585 } else if (locales[name] != null) {
20586 delete locales[name];
20587 }
20588 }
20589 }
20590
20591 return locales[name];
20592 } // returns locale data
20593
20594
20595 function getLocale(key) {
20596 var locale;
20597
20598 if (key && key._locale && key._locale._abbr) {
20599 key = key._locale._abbr;
20600 }
20601
20602 if (!key) {
20603 return globalLocale;
20604 }
20605
20606 if (!isArray(key)) {
20607 //short-circuit everything else
20608 locale = loadLocale(key);
20609
20610 if (locale) {
20611 return locale;
20612 }
20613
20614 key = [key];
20615 }
20616
20617 return chooseLocale(key);
20618 }
20619
20620 function listLocales() {
20621 return keys(locales);
20622 }
20623
20624 function checkOverflow(m) {
20625 var overflow;
20626 var a = m._a;
20627
20628 if (a && getParsingFlags(m).overflow === -2) {
20629 overflow = a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE : a[HOUR] < 0 || a[HOUR] > 24 || a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0) ? HOUR : a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE : a[SECOND] < 0 || a[SECOND] > 59 ? SECOND : a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND : -1;
20630
20631 if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
20632 overflow = DATE;
20633 }
20634
20635 if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
20636 overflow = WEEK;
20637 }
20638
20639 if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
20640 overflow = WEEKDAY;
20641 }
20642
20643 getParsingFlags(m).overflow = overflow;
20644 }
20645
20646 return m;
20647 } // Pick the first defined of two or three arguments.
20648
20649
20650 function defaults(a, b, c) {
20651 if (a != null) {
20652 return a;
20653 }
20654
20655 if (b != null) {
20656 return b;
20657 }
20658
20659 return c;
20660 }
20661
20662 function currentDateArray(config) {
20663 // hooks is actually the exported moment object
20664 var nowValue = new Date(hooks.now());
20665
20666 if (config._useUTC) {
20667 return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
20668 }
20669
20670 return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
20671 } // convert an array to a date.
20672 // the array should mirror the parameters below
20673 // note: all values past the year are optional and will default to the lowest possible value.
20674 // [year, month, day , hour, minute, second, millisecond]
20675
20676
20677 function configFromArray(config) {
20678 var i,
20679 date,
20680 input = [],
20681 currentDate,
20682 expectedWeekday,
20683 yearToUse;
20684
20685 if (config._d) {
20686 return;
20687 }
20688
20689 currentDate = currentDateArray(config); //compute day of the year from weeks and weekdays
20690
20691 if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
20692 dayOfYearFromWeekInfo(config);
20693 } //if the day of the year is set, figure out what it is
20694
20695
20696 if (config._dayOfYear != null) {
20697 yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
20698
20699 if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
20700 getParsingFlags(config)._overflowDayOfYear = true;
20701 }
20702
20703 date = createUTCDate(yearToUse, 0, config._dayOfYear);
20704 config._a[MONTH] = date.getUTCMonth();
20705 config._a[DATE] = date.getUTCDate();
20706 } // Default to current date.
20707 // * if no year, month, day of month are given, default to today
20708 // * if day of month is given, default month and year
20709 // * if month is given, default only year
20710 // * if year is given, don't default anything
20711
20712
20713 for (i = 0; i < 3 && config._a[i] == null; ++i) {
20714 config._a[i] = input[i] = currentDate[i];
20715 } // Zero out whatever was not defaulted, including time
20716
20717
20718 for (; i < 7; i++) {
20719 config._a[i] = input[i] = config._a[i] == null ? i === 2 ? 1 : 0 : config._a[i];
20720 } // Check for 24:00:00.000
20721
20722
20723 if (config._a[HOUR] === 24 && config._a[MINUTE] === 0 && config._a[SECOND] === 0 && config._a[MILLISECOND] === 0) {
20724 config._nextDay = true;
20725 config._a[HOUR] = 0;
20726 }
20727
20728 config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
20729 expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay(); // Apply timezone offset from input. The actual utcOffset can be changed
20730 // with parseZone.
20731
20732 if (config._tzm != null) {
20733 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
20734 }
20735
20736 if (config._nextDay) {
20737 config._a[HOUR] = 24;
20738 } // check for mismatching day of week
20739
20740
20741 if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
20742 getParsingFlags(config).weekdayMismatch = true;
20743 }
20744 }
20745
20746 function dayOfYearFromWeekInfo(config) {
20747 var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
20748 w = config._w;
20749
20750 if (w.GG != null || w.W != null || w.E != null) {
20751 dow = 1;
20752 doy = 4; // TODO: We need to take the current isoWeekYear, but that depends on
20753 // how we interpret now (local, utc, fixed offset). So create
20754 // a now version of current config (take local/utc/offset flags, and
20755 // create now).
20756
20757 weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
20758 week = defaults(w.W, 1);
20759 weekday = defaults(w.E, 1);
20760
20761 if (weekday < 1 || weekday > 7) {
20762 weekdayOverflow = true;
20763 }
20764 } else {
20765 dow = config._locale._week.dow;
20766 doy = config._locale._week.doy;
20767 var curWeek = weekOfYear(createLocal(), dow, doy);
20768 weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); // Default to current week.
20769
20770 week = defaults(w.w, curWeek.week);
20771
20772 if (w.d != null) {
20773 // weekday -- low day numbers are considered next week
20774 weekday = w.d;
20775
20776 if (weekday < 0 || weekday > 6) {
20777 weekdayOverflow = true;
20778 }
20779 } else if (w.e != null) {
20780 // local weekday -- counting starts from beginning of week
20781 weekday = w.e + dow;
20782
20783 if (w.e < 0 || w.e > 6) {
20784 weekdayOverflow = true;
20785 }
20786 } else {
20787 // default to beginning of week
20788 weekday = dow;
20789 }
20790 }
20791
20792 if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
20793 getParsingFlags(config)._overflowWeeks = true;
20794 } else if (weekdayOverflow != null) {
20795 getParsingFlags(config)._overflowWeekday = true;
20796 } else {
20797 temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
20798 config._a[YEAR] = temp.year;
20799 config._dayOfYear = temp.dayOfYear;
20800 }
20801 } // iso 8601 regex
20802 // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
20803
20804
20805 var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
20806 var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
20807 var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
20808 var isoDates = [['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], ['GGGG-[W]WW', /\d{4}-W\d\d/, false], ['YYYY-DDD', /\d{4}-\d{3}/], ['YYYY-MM', /\d{4}-\d\d/, false], ['YYYYYYMMDD', /[+-]\d{10}/], ['YYYYMMDD', /\d{8}/], // YYYYMM is NOT allowed by the standard
20809 ['GGGG[W]WWE', /\d{4}W\d{3}/], ['GGGG[W]WW', /\d{4}W\d{2}/, false], ['YYYYDDD', /\d{7}/]]; // iso time formats and regexes
20810
20811 var isoTimes = [['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], ['HH:mm:ss', /\d\d:\d\d:\d\d/], ['HH:mm', /\d\d:\d\d/], ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], ['HHmmss', /\d\d\d\d\d\d/], ['HHmm', /\d\d\d\d/], ['HH', /\d\d/]];
20812 var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; // date from iso format
20813
20814 function configFromISO(config) {
20815 var i,
20816 l,
20817 string = config._i,
20818 match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
20819 allowTime,
20820 dateFormat,
20821 timeFormat,
20822 tzFormat;
20823
20824 if (match) {
20825 getParsingFlags(config).iso = true;
20826
20827 for (i = 0, l = isoDates.length; i < l; i++) {
20828 if (isoDates[i][1].exec(match[1])) {
20829 dateFormat = isoDates[i][0];
20830 allowTime = isoDates[i][2] !== false;
20831 break;
20832 }
20833 }
20834
20835 if (dateFormat == null) {
20836 config._isValid = false;
20837 return;
20838 }
20839
20840 if (match[3]) {
20841 for (i = 0, l = isoTimes.length; i < l; i++) {
20842 if (isoTimes[i][1].exec(match[3])) {
20843 // match[2] should be 'T' or space
20844 timeFormat = (match[2] || ' ') + isoTimes[i][0];
20845 break;
20846 }
20847 }
20848
20849 if (timeFormat == null) {
20850 config._isValid = false;
20851 return;
20852 }
20853 }
20854
20855 if (!allowTime && timeFormat != null) {
20856 config._isValid = false;
20857 return;
20858 }
20859
20860 if (match[4]) {
20861 if (tzRegex.exec(match[4])) {
20862 tzFormat = 'Z';
20863 } else {
20864 config._isValid = false;
20865 return;
20866 }
20867 }
20868
20869 config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
20870 configFromStringAndFormat(config);
20871 } else {
20872 config._isValid = false;
20873 }
20874 } // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
20875
20876
20877 var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
20878
20879 function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
20880 var result = [untruncateYear(yearStr), defaultLocaleMonthsShort.indexOf(monthStr), parseInt(dayStr, 10), parseInt(hourStr, 10), parseInt(minuteStr, 10)];
20881
20882 if (secondStr) {
20883 result.push(parseInt(secondStr, 10));
20884 }
20885
20886 return result;
20887 }
20888
20889 function untruncateYear(yearStr) {
20890 var year = parseInt(yearStr, 10);
20891
20892 if (year <= 49) {
20893 return 2000 + year;
20894 } else if (year <= 999) {
20895 return 1900 + year;
20896 }
20897
20898 return year;
20899 }
20900
20901 function preprocessRFC2822(s) {
20902 // Remove comments and folding whitespace and replace multiple-spaces with a single space
20903 return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
20904 }
20905
20906 function checkWeekday(weekdayStr, parsedInput, config) {
20907 if (weekdayStr) {
20908 // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
20909 var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
20910 weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
20911
20912 if (weekdayProvided !== weekdayActual) {
20913 getParsingFlags(config).weekdayMismatch = true;
20914 config._isValid = false;
20915 return false;
20916 }
20917 }
20918
20919 return true;
20920 }
20921
20922 var obsOffsets = {
20923 UT: 0,
20924 GMT: 0,
20925 EDT: -4 * 60,
20926 EST: -5 * 60,
20927 CDT: -5 * 60,
20928 CST: -6 * 60,
20929 MDT: -6 * 60,
20930 MST: -7 * 60,
20931 PDT: -7 * 60,
20932 PST: -8 * 60
20933 };
20934
20935 function calculateOffset(obsOffset, militaryOffset, numOffset) {
20936 if (obsOffset) {
20937 return obsOffsets[obsOffset];
20938 } else if (militaryOffset) {
20939 // the only allowed military tz is Z
20940 return 0;
20941 } else {
20942 var hm = parseInt(numOffset, 10);
20943 var m = hm % 100,
20944 h = (hm - m) / 100;
20945 return h * 60 + m;
20946 }
20947 } // date and time from ref 2822 format
20948
20949
20950 function configFromRFC2822(config) {
20951 var match = rfc2822.exec(preprocessRFC2822(config._i));
20952
20953 if (match) {
20954 var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
20955
20956 if (!checkWeekday(match[1], parsedArray, config)) {
20957 return;
20958 }
20959
20960 config._a = parsedArray;
20961 config._tzm = calculateOffset(match[8], match[9], match[10]);
20962 config._d = createUTCDate.apply(null, config._a);
20963
20964 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
20965
20966 getParsingFlags(config).rfc2822 = true;
20967 } else {
20968 config._isValid = false;
20969 }
20970 } // date from iso format or fallback
20971
20972
20973 function configFromString(config) {
20974 var matched = aspNetJsonRegex.exec(config._i);
20975
20976 if (matched !== null) {
20977 config._d = new Date(+matched[1]);
20978 return;
20979 }
20980
20981 configFromISO(config);
20982
20983 if (config._isValid === false) {
20984 delete config._isValid;
20985 } else {
20986 return;
20987 }
20988
20989 configFromRFC2822(config);
20990
20991 if (config._isValid === false) {
20992 delete config._isValid;
20993 } else {
20994 return;
20995 } // Final attempt, use Input Fallback
20996
20997
20998 hooks.createFromInputFallback(config);
20999 }
21000
21001 hooks.createFromInputFallback = deprecate('value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + 'discouraged and will be removed in an upcoming major release. Please refer to ' + 'http://momentjs.com/guides/#/warnings/js-date/ for more info.', function (config) {
21002 config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
21003 }); // constant that refers to the ISO standard
21004
21005 hooks.ISO_8601 = function () {}; // constant that refers to the RFC 2822 form
21006
21007
21008 hooks.RFC_2822 = function () {}; // date from string and format string
21009
21010
21011 function configFromStringAndFormat(config) {
21012 // TODO: Move this to another part of the creation flow to prevent circular deps
21013 if (config._f === hooks.ISO_8601) {
21014 configFromISO(config);
21015 return;
21016 }
21017
21018 if (config._f === hooks.RFC_2822) {
21019 configFromRFC2822(config);
21020 return;
21021 }
21022
21023 config._a = [];
21024 getParsingFlags(config).empty = true; // This array is used to make a Date, either with `new Date` or `Date.UTC`
21025
21026 var string = '' + config._i,
21027 i,
21028 parsedInput,
21029 tokens,
21030 token,
21031 skipped,
21032 stringLength = string.length,
21033 totalParsedInputLength = 0;
21034 tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
21035
21036 for (i = 0; i < tokens.length; i++) {
21037 token = tokens[i];
21038 parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; // console.log('token', token, 'parsedInput', parsedInput,
21039 // 'regex', getParseRegexForToken(token, config));
21040
21041 if (parsedInput) {
21042 skipped = string.substr(0, string.indexOf(parsedInput));
21043
21044 if (skipped.length > 0) {
21045 getParsingFlags(config).unusedInput.push(skipped);
21046 }
21047
21048 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
21049 totalParsedInputLength += parsedInput.length;
21050 } // don't parse if it's not a known token
21051
21052
21053 if (formatTokenFunctions[token]) {
21054 if (parsedInput) {
21055 getParsingFlags(config).empty = false;
21056 } else {
21057 getParsingFlags(config).unusedTokens.push(token);
21058 }
21059
21060 addTimeToArrayFromToken(token, parsedInput, config);
21061 } else if (config._strict && !parsedInput) {
21062 getParsingFlags(config).unusedTokens.push(token);
21063 }
21064 } // add remaining unparsed input length to the string
21065
21066
21067 getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
21068
21069 if (string.length > 0) {
21070 getParsingFlags(config).unusedInput.push(string);
21071 } // clear _12h flag if hour is <= 12
21072
21073
21074 if (config._a[HOUR] <= 12 && getParsingFlags(config).bigHour === true && config._a[HOUR] > 0) {
21075 getParsingFlags(config).bigHour = undefined;
21076 }
21077
21078 getParsingFlags(config).parsedDateParts = config._a.slice(0);
21079 getParsingFlags(config).meridiem = config._meridiem; // handle meridiem
21080
21081 config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
21082 configFromArray(config);
21083 checkOverflow(config);
21084 }
21085
21086 function meridiemFixWrap(locale, hour, meridiem) {
21087 var isPm;
21088
21089 if (meridiem == null) {
21090 // nothing to do
21091 return hour;
21092 }
21093
21094 if (locale.meridiemHour != null) {
21095 return locale.meridiemHour(hour, meridiem);
21096 } else if (locale.isPM != null) {
21097 // Fallback
21098 isPm = locale.isPM(meridiem);
21099
21100 if (isPm && hour < 12) {
21101 hour += 12;
21102 }
21103
21104 if (!isPm && hour === 12) {
21105 hour = 0;
21106 }
21107
21108 return hour;
21109 } else {
21110 // this is not supposed to happen
21111 return hour;
21112 }
21113 } // date from string and array of format strings
21114
21115
21116 function configFromStringAndArray(config) {
21117 var tempConfig, bestMoment, scoreToBeat, i, currentScore;
21118
21119 if (config._f.length === 0) {
21120 getParsingFlags(config).invalidFormat = true;
21121 config._d = new Date(NaN);
21122 return;
21123 }
21124
21125 for (i = 0; i < config._f.length; i++) {
21126 currentScore = 0;
21127 tempConfig = copyConfig({}, config);
21128
21129 if (config._useUTC != null) {
21130 tempConfig._useUTC = config._useUTC;
21131 }
21132
21133 tempConfig._f = config._f[i];
21134 configFromStringAndFormat(tempConfig);
21135
21136 if (!isValid(tempConfig)) {
21137 continue;
21138 } // if there is any input that was not parsed add a penalty for that format
21139
21140
21141 currentScore += getParsingFlags(tempConfig).charsLeftOver; //or tokens
21142
21143 currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
21144 getParsingFlags(tempConfig).score = currentScore;
21145
21146 if (scoreToBeat == null || currentScore < scoreToBeat) {
21147 scoreToBeat = currentScore;
21148 bestMoment = tempConfig;
21149 }
21150 }
21151
21152 extend(config, bestMoment || tempConfig);
21153 }
21154
21155 function configFromObject(config) {
21156 if (config._d) {
21157 return;
21158 }
21159
21160 var i = normalizeObjectUnits(config._i);
21161 config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
21162 return obj && parseInt(obj, 10);
21163 });
21164 configFromArray(config);
21165 }
21166
21167 function createFromConfig(config) {
21168 var res = new Moment(checkOverflow(prepareConfig(config)));
21169
21170 if (res._nextDay) {
21171 // Adding is smart enough around DST
21172 res.add(1, 'd');
21173 res._nextDay = undefined;
21174 }
21175
21176 return res;
21177 }
21178
21179 function prepareConfig(config) {
21180 var input = config._i,
21181 format = config._f;
21182 config._locale = config._locale || getLocale(config._l);
21183
21184 if (input === null || format === undefined && input === '') {
21185 return createInvalid({
21186 nullInput: true
21187 });
21188 }
21189
21190 if (typeof input === 'string') {
21191 config._i = input = config._locale.preparse(input);
21192 }
21193
21194 if (isMoment(input)) {
21195 return new Moment(checkOverflow(input));
21196 } else if (isDate(input)) {
21197 config._d = input;
21198 } else if (isArray(format)) {
21199 configFromStringAndArray(config);
21200 } else if (format) {
21201 configFromStringAndFormat(config);
21202 } else {
21203 configFromInput(config);
21204 }
21205
21206 if (!isValid(config)) {
21207 config._d = null;
21208 }
21209
21210 return config;
21211 }
21212
21213 function configFromInput(config) {
21214 var input = config._i;
21215
21216 if (isUndefined(input)) {
21217 config._d = new Date(hooks.now());
21218 } else if (isDate(input)) {
21219 config._d = new Date(input.valueOf());
21220 } else if (typeof input === 'string') {
21221 configFromString(config);
21222 } else if (isArray(input)) {
21223 config._a = map(input.slice(0), function (obj) {
21224 return parseInt(obj, 10);
21225 });
21226 configFromArray(config);
21227 } else if (isObject(input)) {
21228 configFromObject(config);
21229 } else if (isNumber(input)) {
21230 // from milliseconds
21231 config._d = new Date(input);
21232 } else {
21233 hooks.createFromInputFallback(config);
21234 }
21235 }
21236
21237 function createLocalOrUTC(input, format, locale, strict, isUTC) {
21238 var c = {};
21239
21240 if (locale === true || locale === false) {
21241 strict = locale;
21242 locale = undefined;
21243 }
21244
21245 if (isObject(input) && isObjectEmpty(input) || isArray(input) && input.length === 0) {
21246 input = undefined;
21247 } // object construction must be done this way.
21248 // https://github.com/moment/moment/issues/1423
21249
21250
21251 c._isAMomentObject = true;
21252 c._useUTC = c._isUTC = isUTC;
21253 c._l = locale;
21254 c._i = input;
21255 c._f = format;
21256 c._strict = strict;
21257 return createFromConfig(c);
21258 }
21259
21260 function createLocal(input, format, locale, strict) {
21261 return createLocalOrUTC(input, format, locale, strict, false);
21262 }
21263
21264 var prototypeMin = deprecate('moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
21265 var other = createLocal.apply(null, arguments);
21266
21267 if (this.isValid() && other.isValid()) {
21268 return other < this ? this : other;
21269 } else {
21270 return createInvalid();
21271 }
21272 });
21273 var prototypeMax = deprecate('moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
21274 var other = createLocal.apply(null, arguments);
21275
21276 if (this.isValid() && other.isValid()) {
21277 return other > this ? this : other;
21278 } else {
21279 return createInvalid();
21280 }
21281 }); // Pick a moment m from moments so that m[fn](other) is true for all
21282 // other. This relies on the function fn to be transitive.
21283 //
21284 // moments should either be an array of moment objects or an array, whose
21285 // first element is an array of moment objects.
21286
21287 function pickBy(fn, moments) {
21288 var res, i;
21289
21290 if (moments.length === 1 && isArray(moments[0])) {
21291 moments = moments[0];
21292 }
21293
21294 if (!moments.length) {
21295 return createLocal();
21296 }
21297
21298 res = moments[0];
21299
21300 for (i = 1; i < moments.length; ++i) {
21301 if (!moments[i].isValid() || moments[i][fn](res)) {
21302 res = moments[i];
21303 }
21304 }
21305
21306 return res;
21307 } // TODO: Use [].sort instead?
21308
21309
21310 function min() {
21311 var args = [].slice.call(arguments, 0);
21312 return pickBy('isBefore', args);
21313 }
21314
21315 function max() {
21316 var args = [].slice.call(arguments, 0);
21317 return pickBy('isAfter', args);
21318 }
21319
21320 var now = function () {
21321 return Date.now ? Date.now() : +new Date();
21322 };
21323
21324 var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
21325
21326 function isDurationValid(m) {
21327 for (var key in m) {
21328 if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
21329 return false;
21330 }
21331 }
21332
21333 var unitHasDecimal = false;
21334
21335 for (var i = 0; i < ordering.length; ++i) {
21336 if (m[ordering[i]]) {
21337 if (unitHasDecimal) {
21338 return false; // only allow non-integers for smallest unit
21339 }
21340
21341 if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
21342 unitHasDecimal = true;
21343 }
21344 }
21345 }
21346
21347 return true;
21348 }
21349
21350 function isValid$1() {
21351 return this._isValid;
21352 }
21353
21354 function createInvalid$1() {
21355 return createDuration(NaN);
21356 }
21357
21358 function Duration(duration) {
21359 var normalizedInput = normalizeObjectUnits(duration),
21360 years = normalizedInput.year || 0,
21361 quarters = normalizedInput.quarter || 0,
21362 months = normalizedInput.month || 0,
21363 weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
21364 days = normalizedInput.day || 0,
21365 hours = normalizedInput.hour || 0,
21366 minutes = normalizedInput.minute || 0,
21367 seconds = normalizedInput.second || 0,
21368 milliseconds = normalizedInput.millisecond || 0;
21369 this._isValid = isDurationValid(normalizedInput); // representation for dateAddRemove
21370
21371 this._milliseconds = +milliseconds + seconds * 1e3 + // 1000
21372 minutes * 6e4 + // 1000 * 60
21373 hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
21374 // Because of dateAddRemove treats 24 hours as different from a
21375 // day when working around DST, we need to store them separately
21376
21377 this._days = +days + weeks * 7; // It is impossible to translate months into days without knowing
21378 // which months you are are talking about, so we have to store
21379 // it separately.
21380
21381 this._months = +months + quarters * 3 + years * 12;
21382 this._data = {};
21383 this._locale = getLocale();
21384
21385 this._bubble();
21386 }
21387
21388 function isDuration(obj) {
21389 return obj instanceof Duration;
21390 }
21391
21392 function absRound(number) {
21393 if (number < 0) {
21394 return Math.round(-1 * number) * -1;
21395 } else {
21396 return Math.round(number);
21397 }
21398 } // FORMATTING
21399
21400
21401 function offset(token, separator) {
21402 addFormatToken(token, 0, 0, function () {
21403 var offset = this.utcOffset();
21404 var sign = '+';
21405
21406 if (offset < 0) {
21407 offset = -offset;
21408 sign = '-';
21409 }
21410
21411 return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~offset % 60, 2);
21412 });
21413 }
21414
21415 offset('Z', ':');
21416 offset('ZZ', ''); // PARSING
21417
21418 addRegexToken('Z', matchShortOffset);
21419 addRegexToken('ZZ', matchShortOffset);
21420 addParseToken(['Z', 'ZZ'], function (input, array, config) {
21421 config._useUTC = true;
21422 config._tzm = offsetFromString(matchShortOffset, input);
21423 }); // HELPERS
21424 // timezone chunker
21425 // '+10:00' > ['10', '00']
21426 // '-1530' > ['-15', '30']
21427
21428 var chunkOffset = /([\+\-]|\d\d)/gi;
21429
21430 function offsetFromString(matcher, string) {
21431 var matches = (string || '').match(matcher);
21432
21433 if (matches === null) {
21434 return null;
21435 }
21436
21437 var chunk = matches[matches.length - 1] || [];
21438 var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
21439 var minutes = +(parts[1] * 60) + toInt(parts[2]);
21440 return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
21441 } // Return a moment from input, that is local/utc/zone equivalent to model.
21442
21443
21444 function cloneWithOffset(input, model) {
21445 var res, diff;
21446
21447 if (model._isUTC) {
21448 res = model.clone();
21449 diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf(); // Use low-level api, because this fn is low-level api.
21450
21451 res._d.setTime(res._d.valueOf() + diff);
21452
21453 hooks.updateOffset(res, false);
21454 return res;
21455 } else {
21456 return createLocal(input).local();
21457 }
21458 }
21459
21460 function getDateOffset(m) {
21461 // On Firefox.24 Date#getTimezoneOffset returns a floating point.
21462 // https://github.com/moment/moment/pull/1871
21463 return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
21464 } // HOOKS
21465 // This function will be called whenever a moment is mutated.
21466 // It is intended to keep the offset in sync with the timezone.
21467
21468
21469 hooks.updateOffset = function () {}; // MOMENTS
21470 // keepLocalTime = true means only change the timezone, without
21471 // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
21472 // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
21473 // +0200, so we adjust the time as needed, to be valid.
21474 //
21475 // Keeping the time actually adds/subtracts (one hour)
21476 // from the actual represented time. That is why we call updateOffset
21477 // a second time. In case it wants us to change the offset again
21478 // _changeInProgress == true case, then we have to adjust, because
21479 // there is no such time in the given timezone.
21480
21481
21482 function getSetOffset(input, keepLocalTime, keepMinutes) {
21483 var offset = this._offset || 0,
21484 localAdjust;
21485
21486 if (!this.isValid()) {
21487 return input != null ? this : NaN;
21488 }
21489
21490 if (input != null) {
21491 if (typeof input === 'string') {
21492 input = offsetFromString(matchShortOffset, input);
21493
21494 if (input === null) {
21495 return this;
21496 }
21497 } else if (Math.abs(input) < 16 && !keepMinutes) {
21498 input = input * 60;
21499 }
21500
21501 if (!this._isUTC && keepLocalTime) {
21502 localAdjust = getDateOffset(this);
21503 }
21504
21505 this._offset = input;
21506 this._isUTC = true;
21507
21508 if (localAdjust != null) {
21509 this.add(localAdjust, 'm');
21510 }
21511
21512 if (offset !== input) {
21513 if (!keepLocalTime || this._changeInProgress) {
21514 addSubtract(this, createDuration(input - offset, 'm'), 1, false);
21515 } else if (!this._changeInProgress) {
21516 this._changeInProgress = true;
21517 hooks.updateOffset(this, true);
21518 this._changeInProgress = null;
21519 }
21520 }
21521
21522 return this;
21523 } else {
21524 return this._isUTC ? offset : getDateOffset(this);
21525 }
21526 }
21527
21528 function getSetZone(input, keepLocalTime) {
21529 if (input != null) {
21530 if (typeof input !== 'string') {
21531 input = -input;
21532 }
21533
21534 this.utcOffset(input, keepLocalTime);
21535 return this;
21536 } else {
21537 return -this.utcOffset();
21538 }
21539 }
21540
21541 function setOffsetToUTC(keepLocalTime) {
21542 return this.utcOffset(0, keepLocalTime);
21543 }
21544
21545 function setOffsetToLocal(keepLocalTime) {
21546 if (this._isUTC) {
21547 this.utcOffset(0, keepLocalTime);
21548 this._isUTC = false;
21549
21550 if (keepLocalTime) {
21551 this.subtract(getDateOffset(this), 'm');
21552 }
21553 }
21554
21555 return this;
21556 }
21557
21558 function setOffsetToParsedOffset() {
21559 if (this._tzm != null) {
21560 this.utcOffset(this._tzm, false, true);
21561 } else if (typeof this._i === 'string') {
21562 var tZone = offsetFromString(matchOffset, this._i);
21563
21564 if (tZone != null) {
21565 this.utcOffset(tZone);
21566 } else {
21567 this.utcOffset(0, true);
21568 }
21569 }
21570
21571 return this;
21572 }
21573
21574 function hasAlignedHourOffset(input) {
21575 if (!this.isValid()) {
21576 return false;
21577 }
21578
21579 input = input ? createLocal(input).utcOffset() : 0;
21580 return (this.utcOffset() - input) % 60 === 0;
21581 }
21582
21583 function isDaylightSavingTime() {
21584 return this.utcOffset() > this.clone().month(0).utcOffset() || this.utcOffset() > this.clone().month(5).utcOffset();
21585 }
21586
21587 function isDaylightSavingTimeShifted() {
21588 if (!isUndefined(this._isDSTShifted)) {
21589 return this._isDSTShifted;
21590 }
21591
21592 var c = {};
21593 copyConfig(c, this);
21594 c = prepareConfig(c);
21595
21596 if (c._a) {
21597 var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
21598 this._isDSTShifted = this.isValid() && compareArrays(c._a, other.toArray()) > 0;
21599 } else {
21600 this._isDSTShifted = false;
21601 }
21602
21603 return this._isDSTShifted;
21604 }
21605
21606 function isLocal() {
21607 return this.isValid() ? !this._isUTC : false;
21608 }
21609
21610 function isUtcOffset() {
21611 return this.isValid() ? this._isUTC : false;
21612 }
21613
21614 function isUtc() {
21615 return this.isValid() ? this._isUTC && this._offset === 0 : false;
21616 } // ASP.NET json date format regex
21617
21618
21619 var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/; // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
21620 // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
21621 // and further modified to allow for strings containing both week and day
21622
21623 var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
21624
21625 function createDuration(input, key) {
21626 var duration = input,
21627 // matching against regexp is expensive, do it on demand
21628 match = null,
21629 sign,
21630 ret,
21631 diffRes;
21632
21633 if (isDuration(input)) {
21634 duration = {
21635 ms: input._milliseconds,
21636 d: input._days,
21637 M: input._months
21638 };
21639 } else if (isNumber(input)) {
21640 duration = {};
21641
21642 if (key) {
21643 duration[key] = input;
21644 } else {
21645 duration.milliseconds = input;
21646 }
21647 } else if (!!(match = aspNetRegex.exec(input))) {
21648 sign = match[1] === '-' ? -1 : 1;
21649 duration = {
21650 y: 0,
21651 d: toInt(match[DATE]) * sign,
21652 h: toInt(match[HOUR]) * sign,
21653 m: toInt(match[MINUTE]) * sign,
21654 s: toInt(match[SECOND]) * sign,
21655 ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
21656
21657 };
21658 } else if (!!(match = isoRegex.exec(input))) {
21659 sign = match[1] === '-' ? -1 : 1;
21660 duration = {
21661 y: parseIso(match[2], sign),
21662 M: parseIso(match[3], sign),
21663 w: parseIso(match[4], sign),
21664 d: parseIso(match[5], sign),
21665 h: parseIso(match[6], sign),
21666 m: parseIso(match[7], sign),
21667 s: parseIso(match[8], sign)
21668 };
21669 } else if (duration == null) {
21670 // checks for null or undefined
21671 duration = {};
21672 } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
21673 diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
21674 duration = {};
21675 duration.ms = diffRes.milliseconds;
21676 duration.M = diffRes.months;
21677 }
21678
21679 ret = new Duration(duration);
21680
21681 if (isDuration(input) && hasOwnProp(input, '_locale')) {
21682 ret._locale = input._locale;
21683 }
21684
21685 return ret;
21686 }
21687
21688 createDuration.fn = Duration.prototype;
21689 createDuration.invalid = createInvalid$1;
21690
21691 function parseIso(inp, sign) {
21692 // We'd normally use ~~inp for this, but unfortunately it also
21693 // converts floats to ints.
21694 // inp may be undefined, so careful calling replace on it.
21695 var res = inp && parseFloat(inp.replace(',', '.')); // apply sign while we're at it
21696
21697 return (isNaN(res) ? 0 : res) * sign;
21698 }
21699
21700 function positiveMomentsDifference(base, other) {
21701 var res = {};
21702 res.months = other.month() - base.month() + (other.year() - base.year()) * 12;
21703
21704 if (base.clone().add(res.months, 'M').isAfter(other)) {
21705 --res.months;
21706 }
21707
21708 res.milliseconds = +other - +base.clone().add(res.months, 'M');
21709 return res;
21710 }
21711
21712 function momentsDifference(base, other) {
21713 var res;
21714
21715 if (!(base.isValid() && other.isValid())) {
21716 return {
21717 milliseconds: 0,
21718 months: 0
21719 };
21720 }
21721
21722 other = cloneWithOffset(other, base);
21723
21724 if (base.isBefore(other)) {
21725 res = positiveMomentsDifference(base, other);
21726 } else {
21727 res = positiveMomentsDifference(other, base);
21728 res.milliseconds = -res.milliseconds;
21729 res.months = -res.months;
21730 }
21731
21732 return res;
21733 } // TODO: remove 'name' arg after deprecation is removed
21734
21735
21736 function createAdder(direction, name) {
21737 return function (val, period) {
21738 var dur, tmp; //invert the arguments, but complain about it
21739
21740 if (period !== null && !isNaN(+period)) {
21741 deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' + 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
21742 tmp = val;
21743 val = period;
21744 period = tmp;
21745 }
21746
21747 val = typeof val === 'string' ? +val : val;
21748 dur = createDuration(val, period);
21749 addSubtract(this, dur, direction);
21750 return this;
21751 };
21752 }
21753
21754 function addSubtract(mom, duration, isAdding, updateOffset) {
21755 var milliseconds = duration._milliseconds,
21756 days = absRound(duration._days),
21757 months = absRound(duration._months);
21758
21759 if (!mom.isValid()) {
21760 // No op
21761 return;
21762 }
21763
21764 updateOffset = updateOffset == null ? true : updateOffset;
21765
21766 if (months) {
21767 setMonth(mom, get(mom, 'Month') + months * isAdding);
21768 }
21769
21770 if (days) {
21771 set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
21772 }
21773
21774 if (milliseconds) {
21775 mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
21776 }
21777
21778 if (updateOffset) {
21779 hooks.updateOffset(mom, days || months);
21780 }
21781 }
21782
21783 var add = createAdder(1, 'add');
21784 var subtract = createAdder(-1, 'subtract');
21785
21786 function getCalendarFormat(myMoment, now) {
21787 var diff = myMoment.diff(now, 'days', true);
21788 return diff < -6 ? 'sameElse' : diff < -1 ? 'lastWeek' : diff < 0 ? 'lastDay' : diff < 1 ? 'sameDay' : diff < 2 ? 'nextDay' : diff < 7 ? 'nextWeek' : 'sameElse';
21789 }
21790
21791 function calendar$1(time, formats) {
21792 // We want to compare the start of today, vs this.
21793 // Getting start-of-today depends on whether we're local/utc/offset or not.
21794 var now = time || createLocal(),
21795 sod = cloneWithOffset(now, this).startOf('day'),
21796 format = hooks.calendarFormat(this, sod) || 'sameElse';
21797 var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
21798 return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
21799 }
21800
21801 function clone() {
21802 return new Moment(this);
21803 }
21804
21805 function isAfter(input, units) {
21806 var localInput = isMoment(input) ? input : createLocal(input);
21807
21808 if (!(this.isValid() && localInput.isValid())) {
21809 return false;
21810 }
21811
21812 units = normalizeUnits(units) || 'millisecond';
21813
21814 if (units === 'millisecond') {
21815 return this.valueOf() > localInput.valueOf();
21816 } else {
21817 return localInput.valueOf() < this.clone().startOf(units).valueOf();
21818 }
21819 }
21820
21821 function isBefore(input, units) {
21822 var localInput = isMoment(input) ? input : createLocal(input);
21823
21824 if (!(this.isValid() && localInput.isValid())) {
21825 return false;
21826 }
21827
21828 units = normalizeUnits(units) || 'millisecond';
21829
21830 if (units === 'millisecond') {
21831 return this.valueOf() < localInput.valueOf();
21832 } else {
21833 return this.clone().endOf(units).valueOf() < localInput.valueOf();
21834 }
21835 }
21836
21837 function isBetween(from, to, units, inclusivity) {
21838 var localFrom = isMoment(from) ? from : createLocal(from),
21839 localTo = isMoment(to) ? to : createLocal(to);
21840
21841 if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
21842 return false;
21843 }
21844
21845 inclusivity = inclusivity || '()';
21846 return (inclusivity[0] === '(' ? this.isAfter(localFrom, units) : !this.isBefore(localFrom, units)) && (inclusivity[1] === ')' ? this.isBefore(localTo, units) : !this.isAfter(localTo, units));
21847 }
21848
21849 function isSame(input, units) {
21850 var localInput = isMoment(input) ? input : createLocal(input),
21851 inputMs;
21852
21853 if (!(this.isValid() && localInput.isValid())) {
21854 return false;
21855 }
21856
21857 units = normalizeUnits(units) || 'millisecond';
21858
21859 if (units === 'millisecond') {
21860 return this.valueOf() === localInput.valueOf();
21861 } else {
21862 inputMs = localInput.valueOf();
21863 return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
21864 }
21865 }
21866
21867 function isSameOrAfter(input, units) {
21868 return this.isSame(input, units) || this.isAfter(input, units);
21869 }
21870
21871 function isSameOrBefore(input, units) {
21872 return this.isSame(input, units) || this.isBefore(input, units);
21873 }
21874
21875 function diff(input, units, asFloat) {
21876 var that, zoneDelta, output;
21877
21878 if (!this.isValid()) {
21879 return NaN;
21880 }
21881
21882 that = cloneWithOffset(input, this);
21883
21884 if (!that.isValid()) {
21885 return NaN;
21886 }
21887
21888 zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
21889 units = normalizeUnits(units);
21890
21891 switch (units) {
21892 case 'year':
21893 output = monthDiff(this, that) / 12;
21894 break;
21895
21896 case 'month':
21897 output = monthDiff(this, that);
21898 break;
21899
21900 case 'quarter':
21901 output = monthDiff(this, that) / 3;
21902 break;
21903
21904 case 'second':
21905 output = (this - that) / 1e3;
21906 break;
21907 // 1000
21908
21909 case 'minute':
21910 output = (this - that) / 6e4;
21911 break;
21912 // 1000 * 60
21913
21914 case 'hour':
21915 output = (this - that) / 36e5;
21916 break;
21917 // 1000 * 60 * 60
21918
21919 case 'day':
21920 output = (this - that - zoneDelta) / 864e5;
21921 break;
21922 // 1000 * 60 * 60 * 24, negate dst
21923
21924 case 'week':
21925 output = (this - that - zoneDelta) / 6048e5;
21926 break;
21927 // 1000 * 60 * 60 * 24 * 7, negate dst
21928
21929 default:
21930 output = this - that;
21931 }
21932
21933 return asFloat ? output : absFloor(output);
21934 }
21935
21936 function monthDiff(a, b) {
21937 // difference in months
21938 var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()),
21939 // b is in (anchor - 1 month, anchor + 1 month)
21940 anchor = a.clone().add(wholeMonthDiff, 'months'),
21941 anchor2,
21942 adjust;
21943
21944 if (b - anchor < 0) {
21945 anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); // linear across the month
21946
21947 adjust = (b - anchor) / (anchor - anchor2);
21948 } else {
21949 anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); // linear across the month
21950
21951 adjust = (b - anchor) / (anchor2 - anchor);
21952 } //check for negative zero, return zero if negative zero
21953
21954
21955 return -(wholeMonthDiff + adjust) || 0;
21956 }
21957
21958 hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
21959 hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
21960
21961 function toString() {
21962 return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
21963 }
21964
21965 function toISOString(keepOffset) {
21966 if (!this.isValid()) {
21967 return null;
21968 }
21969
21970 var utc = keepOffset !== true;
21971 var m = utc ? this.clone().utc() : this;
21972
21973 if (m.year() < 0 || m.year() > 9999) {
21974 return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
21975 }
21976
21977 if (isFunction(Date.prototype.toISOString)) {
21978 // native implementation is ~50x faster, use it when we can
21979 if (utc) {
21980 return this.toDate().toISOString();
21981 } else {
21982 return new Date(this.valueOf() + this.utcOffset() * 60 * 1000).toISOString().replace('Z', formatMoment(m, 'Z'));
21983 }
21984 }
21985
21986 return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
21987 }
21988 /**
21989 * Return a human readable representation of a moment that can
21990 * also be evaluated to get a new moment which is the same
21991 *
21992 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
21993 */
21994
21995
21996 function inspect() {
21997 if (!this.isValid()) {
21998 return 'moment.invalid(/* ' + this._i + ' */)';
21999 }
22000
22001 var func = 'moment';
22002 var zone = '';
22003
22004 if (!this.isLocal()) {
22005 func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
22006 zone = 'Z';
22007 }
22008
22009 var prefix = '[' + func + '("]';
22010 var year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
22011 var datetime = '-MM-DD[T]HH:mm:ss.SSS';
22012 var suffix = zone + '[")]';
22013 return this.format(prefix + year + datetime + suffix);
22014 }
22015
22016 function format(inputString) {
22017 if (!inputString) {
22018 inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
22019 }
22020
22021 var output = formatMoment(this, inputString);
22022 return this.localeData().postformat(output);
22023 }
22024
22025 function from(time, withoutSuffix) {
22026 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
22027 return createDuration({
22028 to: this,
22029 from: time
22030 }).locale(this.locale()).humanize(!withoutSuffix);
22031 } else {
22032 return this.localeData().invalidDate();
22033 }
22034 }
22035
22036 function fromNow(withoutSuffix) {
22037 return this.from(createLocal(), withoutSuffix);
22038 }
22039
22040 function to(time, withoutSuffix) {
22041 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
22042 return createDuration({
22043 from: this,
22044 to: time
22045 }).locale(this.locale()).humanize(!withoutSuffix);
22046 } else {
22047 return this.localeData().invalidDate();
22048 }
22049 }
22050
22051 function toNow(withoutSuffix) {
22052 return this.to(createLocal(), withoutSuffix);
22053 } // If passed a locale key, it will set the locale for this
22054 // instance. Otherwise, it will return the locale configuration
22055 // variables for this instance.
22056
22057
22058 function locale(key) {
22059 var newLocaleData;
22060
22061 if (key === undefined) {
22062 return this._locale._abbr;
22063 } else {
22064 newLocaleData = getLocale(key);
22065
22066 if (newLocaleData != null) {
22067 this._locale = newLocaleData;
22068 }
22069
22070 return this;
22071 }
22072 }
22073
22074 var lang = deprecate('moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', function (key) {
22075 if (key === undefined) {
22076 return this.localeData();
22077 } else {
22078 return this.locale(key);
22079 }
22080 });
22081
22082 function localeData() {
22083 return this._locale;
22084 }
22085
22086 var MS_PER_SECOND = 1000;
22087 var MS_PER_MINUTE = 60 * MS_PER_SECOND;
22088 var MS_PER_HOUR = 60 * MS_PER_MINUTE;
22089 var MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; // actual modulo - handles negative numbers (for dates before 1970):
22090
22091 function mod$1(dividend, divisor) {
22092 return (dividend % divisor + divisor) % divisor;
22093 }
22094
22095 function localStartOfDate(y, m, d) {
22096 // the date constructor remaps years 0-99 to 1900-1999
22097 if (y < 100 && y >= 0) {
22098 // preserve leap years using a full 400 year cycle, then reset
22099 return new Date(y + 400, m, d) - MS_PER_400_YEARS;
22100 } else {
22101 return new Date(y, m, d).valueOf();
22102 }
22103 }
22104
22105 function utcStartOfDate(y, m, d) {
22106 // Date.UTC remaps years 0-99 to 1900-1999
22107 if (y < 100 && y >= 0) {
22108 // preserve leap years using a full 400 year cycle, then reset
22109 return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
22110 } else {
22111 return Date.UTC(y, m, d);
22112 }
22113 }
22114
22115 function startOf(units) {
22116 var time;
22117 units = normalizeUnits(units);
22118
22119 if (units === undefined || units === 'millisecond' || !this.isValid()) {
22120 return this;
22121 }
22122
22123 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
22124
22125 switch (units) {
22126 case 'year':
22127 time = startOfDate(this.year(), 0, 1);
22128 break;
22129
22130 case 'quarter':
22131 time = startOfDate(this.year(), this.month() - this.month() % 3, 1);
22132 break;
22133
22134 case 'month':
22135 time = startOfDate(this.year(), this.month(), 1);
22136 break;
22137
22138 case 'week':
22139 time = startOfDate(this.year(), this.month(), this.date() - this.weekday());
22140 break;
22141
22142 case 'isoWeek':
22143 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1));
22144 break;
22145
22146 case 'day':
22147 case 'date':
22148 time = startOfDate(this.year(), this.month(), this.date());
22149 break;
22150
22151 case 'hour':
22152 time = this._d.valueOf();
22153 time -= mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR);
22154 break;
22155
22156 case 'minute':
22157 time = this._d.valueOf();
22158 time -= mod$1(time, MS_PER_MINUTE);
22159 break;
22160
22161 case 'second':
22162 time = this._d.valueOf();
22163 time -= mod$1(time, MS_PER_SECOND);
22164 break;
22165 }
22166
22167 this._d.setTime(time);
22168
22169 hooks.updateOffset(this, true);
22170 return this;
22171 }
22172
22173 function endOf(units) {
22174 var time;
22175 units = normalizeUnits(units);
22176
22177 if (units === undefined || units === 'millisecond' || !this.isValid()) {
22178 return this;
22179 }
22180
22181 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
22182
22183 switch (units) {
22184 case 'year':
22185 time = startOfDate(this.year() + 1, 0, 1) - 1;
22186 break;
22187
22188 case 'quarter':
22189 time = startOfDate(this.year(), this.month() - this.month() % 3 + 3, 1) - 1;
22190 break;
22191
22192 case 'month':
22193 time = startOfDate(this.year(), this.month() + 1, 1) - 1;
22194 break;
22195
22196 case 'week':
22197 time = startOfDate(this.year(), this.month(), this.date() - this.weekday() + 7) - 1;
22198 break;
22199
22200 case 'isoWeek':
22201 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1) + 7) - 1;
22202 break;
22203
22204 case 'day':
22205 case 'date':
22206 time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
22207 break;
22208
22209 case 'hour':
22210 time = this._d.valueOf();
22211 time += MS_PER_HOUR - mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR) - 1;
22212 break;
22213
22214 case 'minute':
22215 time = this._d.valueOf();
22216 time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
22217 break;
22218
22219 case 'second':
22220 time = this._d.valueOf();
22221 time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
22222 break;
22223 }
22224
22225 this._d.setTime(time);
22226
22227 hooks.updateOffset(this, true);
22228 return this;
22229 }
22230
22231 function valueOf() {
22232 return this._d.valueOf() - (this._offset || 0) * 60000;
22233 }
22234
22235 function unix() {
22236 return Math.floor(this.valueOf() / 1000);
22237 }
22238
22239 function toDate() {
22240 return new Date(this.valueOf());
22241 }
22242
22243 function toArray() {
22244 var m = this;
22245 return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
22246 }
22247
22248 function toObject() {
22249 var m = this;
22250 return {
22251 years: m.year(),
22252 months: m.month(),
22253 date: m.date(),
22254 hours: m.hours(),
22255 minutes: m.minutes(),
22256 seconds: m.seconds(),
22257 milliseconds: m.milliseconds()
22258 };
22259 }
22260
22261 function toJSON() {
22262 // new Date(NaN).toJSON() === null
22263 return this.isValid() ? this.toISOString() : null;
22264 }
22265
22266 function isValid$2() {
22267 return isValid(this);
22268 }
22269
22270 function parsingFlags() {
22271 return extend({}, getParsingFlags(this));
22272 }
22273
22274 function invalidAt() {
22275 return getParsingFlags(this).overflow;
22276 }
22277
22278 function creationData() {
22279 return {
22280 input: this._i,
22281 format: this._f,
22282 locale: this._locale,
22283 isUTC: this._isUTC,
22284 strict: this._strict
22285 };
22286 } // FORMATTING
22287
22288
22289 addFormatToken(0, ['gg', 2], 0, function () {
22290 return this.weekYear() % 100;
22291 });
22292 addFormatToken(0, ['GG', 2], 0, function () {
22293 return this.isoWeekYear() % 100;
22294 });
22295
22296 function addWeekYearFormatToken(token, getter) {
22297 addFormatToken(0, [token, token.length], 0, getter);
22298 }
22299
22300 addWeekYearFormatToken('gggg', 'weekYear');
22301 addWeekYearFormatToken('ggggg', 'weekYear');
22302 addWeekYearFormatToken('GGGG', 'isoWeekYear');
22303 addWeekYearFormatToken('GGGGG', 'isoWeekYear'); // ALIASES
22304
22305 addUnitAlias('weekYear', 'gg');
22306 addUnitAlias('isoWeekYear', 'GG'); // PRIORITY
22307
22308 addUnitPriority('weekYear', 1);
22309 addUnitPriority('isoWeekYear', 1); // PARSING
22310
22311 addRegexToken('G', matchSigned);
22312 addRegexToken('g', matchSigned);
22313 addRegexToken('GG', match1to2, match2);
22314 addRegexToken('gg', match1to2, match2);
22315 addRegexToken('GGGG', match1to4, match4);
22316 addRegexToken('gggg', match1to4, match4);
22317 addRegexToken('GGGGG', match1to6, match6);
22318 addRegexToken('ggggg', match1to6, match6);
22319 addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
22320 week[token.substr(0, 2)] = toInt(input);
22321 });
22322 addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
22323 week[token] = hooks.parseTwoDigitYear(input);
22324 }); // MOMENTS
22325
22326 function getSetWeekYear(input) {
22327 return getSetWeekYearHelper.call(this, input, this.week(), this.weekday(), this.localeData()._week.dow, this.localeData()._week.doy);
22328 }
22329
22330 function getSetISOWeekYear(input) {
22331 return getSetWeekYearHelper.call(this, input, this.isoWeek(), this.isoWeekday(), 1, 4);
22332 }
22333
22334 function getISOWeeksInYear() {
22335 return weeksInYear(this.year(), 1, 4);
22336 }
22337
22338 function getWeeksInYear() {
22339 var weekInfo = this.localeData()._week;
22340
22341 return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
22342 }
22343
22344 function getSetWeekYearHelper(input, week, weekday, dow, doy) {
22345 var weeksTarget;
22346
22347 if (input == null) {
22348 return weekOfYear(this, dow, doy).year;
22349 } else {
22350 weeksTarget = weeksInYear(input, dow, doy);
22351
22352 if (week > weeksTarget) {
22353 week = weeksTarget;
22354 }
22355
22356 return setWeekAll.call(this, input, week, weekday, dow, doy);
22357 }
22358 }
22359
22360 function setWeekAll(weekYear, week, weekday, dow, doy) {
22361 var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
22362 date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
22363 this.year(date.getUTCFullYear());
22364 this.month(date.getUTCMonth());
22365 this.date(date.getUTCDate());
22366 return this;
22367 } // FORMATTING
22368
22369
22370 addFormatToken('Q', 0, 'Qo', 'quarter'); // ALIASES
22371
22372 addUnitAlias('quarter', 'Q'); // PRIORITY
22373
22374 addUnitPriority('quarter', 7); // PARSING
22375
22376 addRegexToken('Q', match1);
22377 addParseToken('Q', function (input, array) {
22378 array[MONTH] = (toInt(input) - 1) * 3;
22379 }); // MOMENTS
22380
22381 function getSetQuarter(input) {
22382 return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
22383 } // FORMATTING
22384
22385
22386 addFormatToken('D', ['DD', 2], 'Do', 'date'); // ALIASES
22387
22388 addUnitAlias('date', 'D'); // PRIORITY
22389
22390 addUnitPriority('date', 9); // PARSING
22391
22392 addRegexToken('D', match1to2);
22393 addRegexToken('DD', match1to2, match2);
22394 addRegexToken('Do', function (isStrict, locale) {
22395 // TODO: Remove "ordinalParse" fallback in next major release.
22396 return isStrict ? locale._dayOfMonthOrdinalParse || locale._ordinalParse : locale._dayOfMonthOrdinalParseLenient;
22397 });
22398 addParseToken(['D', 'DD'], DATE);
22399 addParseToken('Do', function (input, array) {
22400 array[DATE] = toInt(input.match(match1to2)[0]);
22401 }); // MOMENTS
22402
22403 var getSetDayOfMonth = makeGetSet('Date', true); // FORMATTING
22404
22405 addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); // ALIASES
22406
22407 addUnitAlias('dayOfYear', 'DDD'); // PRIORITY
22408
22409 addUnitPriority('dayOfYear', 4); // PARSING
22410
22411 addRegexToken('DDD', match1to3);
22412 addRegexToken('DDDD', match3);
22413 addParseToken(['DDD', 'DDDD'], function (input, array, config) {
22414 config._dayOfYear = toInt(input);
22415 }); // HELPERS
22416 // MOMENTS
22417
22418 function getSetDayOfYear(input) {
22419 var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
22420 return input == null ? dayOfYear : this.add(input - dayOfYear, 'd');
22421 } // FORMATTING
22422
22423
22424 addFormatToken('m', ['mm', 2], 0, 'minute'); // ALIASES
22425
22426 addUnitAlias('minute', 'm'); // PRIORITY
22427
22428 addUnitPriority('minute', 14); // PARSING
22429
22430 addRegexToken('m', match1to2);
22431 addRegexToken('mm', match1to2, match2);
22432 addParseToken(['m', 'mm'], MINUTE); // MOMENTS
22433
22434 var getSetMinute = makeGetSet('Minutes', false); // FORMATTING
22435
22436 addFormatToken('s', ['ss', 2], 0, 'second'); // ALIASES
22437
22438 addUnitAlias('second', 's'); // PRIORITY
22439
22440 addUnitPriority('second', 15); // PARSING
22441
22442 addRegexToken('s', match1to2);
22443 addRegexToken('ss', match1to2, match2);
22444 addParseToken(['s', 'ss'], SECOND); // MOMENTS
22445
22446 var getSetSecond = makeGetSet('Seconds', false); // FORMATTING
22447
22448 addFormatToken('S', 0, 0, function () {
22449 return ~~(this.millisecond() / 100);
22450 });
22451 addFormatToken(0, ['SS', 2], 0, function () {
22452 return ~~(this.millisecond() / 10);
22453 });
22454 addFormatToken(0, ['SSS', 3], 0, 'millisecond');
22455 addFormatToken(0, ['SSSS', 4], 0, function () {
22456 return this.millisecond() * 10;
22457 });
22458 addFormatToken(0, ['SSSSS', 5], 0, function () {
22459 return this.millisecond() * 100;
22460 });
22461 addFormatToken(0, ['SSSSSS', 6], 0, function () {
22462 return this.millisecond() * 1000;
22463 });
22464 addFormatToken(0, ['SSSSSSS', 7], 0, function () {
22465 return this.millisecond() * 10000;
22466 });
22467 addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
22468 return this.millisecond() * 100000;
22469 });
22470 addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
22471 return this.millisecond() * 1000000;
22472 }); // ALIASES
22473
22474 addUnitAlias('millisecond', 'ms'); // PRIORITY
22475
22476 addUnitPriority('millisecond', 16); // PARSING
22477
22478 addRegexToken('S', match1to3, match1);
22479 addRegexToken('SS', match1to3, match2);
22480 addRegexToken('SSS', match1to3, match3);
22481 var token;
22482
22483 for (token = 'SSSS'; token.length <= 9; token += 'S') {
22484 addRegexToken(token, matchUnsigned);
22485 }
22486
22487 function parseMs(input, array) {
22488 array[MILLISECOND] = toInt(('0.' + input) * 1000);
22489 }
22490
22491 for (token = 'S'; token.length <= 9; token += 'S') {
22492 addParseToken(token, parseMs);
22493 } // MOMENTS
22494
22495
22496 var getSetMillisecond = makeGetSet('Milliseconds', false); // FORMATTING
22497
22498 addFormatToken('z', 0, 0, 'zoneAbbr');
22499 addFormatToken('zz', 0, 0, 'zoneName'); // MOMENTS
22500
22501 function getZoneAbbr() {
22502 return this._isUTC ? 'UTC' : '';
22503 }
22504
22505 function getZoneName() {
22506 return this._isUTC ? 'Coordinated Universal Time' : '';
22507 }
22508
22509 var proto = Moment.prototype;
22510 proto.add = add;
22511 proto.calendar = calendar$1;
22512 proto.clone = clone;
22513 proto.diff = diff;
22514 proto.endOf = endOf;
22515 proto.format = format;
22516 proto.from = from;
22517 proto.fromNow = fromNow;
22518 proto.to = to;
22519 proto.toNow = toNow;
22520 proto.get = stringGet;
22521 proto.invalidAt = invalidAt;
22522 proto.isAfter = isAfter;
22523 proto.isBefore = isBefore;
22524 proto.isBetween = isBetween;
22525 proto.isSame = isSame;
22526 proto.isSameOrAfter = isSameOrAfter;
22527 proto.isSameOrBefore = isSameOrBefore;
22528 proto.isValid = isValid$2;
22529 proto.lang = lang;
22530 proto.locale = locale;
22531 proto.localeData = localeData;
22532 proto.max = prototypeMax;
22533 proto.min = prototypeMin;
22534 proto.parsingFlags = parsingFlags;
22535 proto.set = stringSet;
22536 proto.startOf = startOf;
22537 proto.subtract = subtract;
22538 proto.toArray = toArray;
22539 proto.toObject = toObject;
22540 proto.toDate = toDate;
22541 proto.toISOString = toISOString;
22542 proto.inspect = inspect;
22543 proto.toJSON = toJSON;
22544 proto.toString = toString;
22545 proto.unix = unix;
22546 proto.valueOf = valueOf;
22547 proto.creationData = creationData;
22548 proto.year = getSetYear;
22549 proto.isLeapYear = getIsLeapYear;
22550 proto.weekYear = getSetWeekYear;
22551 proto.isoWeekYear = getSetISOWeekYear;
22552 proto.quarter = proto.quarters = getSetQuarter;
22553 proto.month = getSetMonth;
22554 proto.daysInMonth = getDaysInMonth;
22555 proto.week = proto.weeks = getSetWeek;
22556 proto.isoWeek = proto.isoWeeks = getSetISOWeek;
22557 proto.weeksInYear = getWeeksInYear;
22558 proto.isoWeeksInYear = getISOWeeksInYear;
22559 proto.date = getSetDayOfMonth;
22560 proto.day = proto.days = getSetDayOfWeek;
22561 proto.weekday = getSetLocaleDayOfWeek;
22562 proto.isoWeekday = getSetISODayOfWeek;
22563 proto.dayOfYear = getSetDayOfYear;
22564 proto.hour = proto.hours = getSetHour;
22565 proto.minute = proto.minutes = getSetMinute;
22566 proto.second = proto.seconds = getSetSecond;
22567 proto.millisecond = proto.milliseconds = getSetMillisecond;
22568 proto.utcOffset = getSetOffset;
22569 proto.utc = setOffsetToUTC;
22570 proto.local = setOffsetToLocal;
22571 proto.parseZone = setOffsetToParsedOffset;
22572 proto.hasAlignedHourOffset = hasAlignedHourOffset;
22573 proto.isDST = isDaylightSavingTime;
22574 proto.isLocal = isLocal;
22575 proto.isUtcOffset = isUtcOffset;
22576 proto.isUtc = isUtc;
22577 proto.isUTC = isUtc;
22578 proto.zoneAbbr = getZoneAbbr;
22579 proto.zoneName = getZoneName;
22580 proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
22581 proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
22582 proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
22583 proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
22584 proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
22585
22586 function createUnix(input) {
22587 return createLocal(input * 1000);
22588 }
22589
22590 function createInZone() {
22591 return createLocal.apply(null, arguments).parseZone();
22592 }
22593
22594 function preParsePostFormat(string) {
22595 return string;
22596 }
22597
22598 var proto$1 = Locale.prototype;
22599 proto$1.calendar = calendar;
22600 proto$1.longDateFormat = longDateFormat;
22601 proto$1.invalidDate = invalidDate;
22602 proto$1.ordinal = ordinal;
22603 proto$1.preparse = preParsePostFormat;
22604 proto$1.postformat = preParsePostFormat;
22605 proto$1.relativeTime = relativeTime;
22606 proto$1.pastFuture = pastFuture;
22607 proto$1.set = set;
22608 proto$1.months = localeMonths;
22609 proto$1.monthsShort = localeMonthsShort;
22610 proto$1.monthsParse = localeMonthsParse;
22611 proto$1.monthsRegex = monthsRegex;
22612 proto$1.monthsShortRegex = monthsShortRegex;
22613 proto$1.week = localeWeek;
22614 proto$1.firstDayOfYear = localeFirstDayOfYear;
22615 proto$1.firstDayOfWeek = localeFirstDayOfWeek;
22616 proto$1.weekdays = localeWeekdays;
22617 proto$1.weekdaysMin = localeWeekdaysMin;
22618 proto$1.weekdaysShort = localeWeekdaysShort;
22619 proto$1.weekdaysParse = localeWeekdaysParse;
22620 proto$1.weekdaysRegex = weekdaysRegex;
22621 proto$1.weekdaysShortRegex = weekdaysShortRegex;
22622 proto$1.weekdaysMinRegex = weekdaysMinRegex;
22623 proto$1.isPM = localeIsPM;
22624 proto$1.meridiem = localeMeridiem;
22625
22626 function get$1(format, index, field, setter) {
22627 var locale = getLocale();
22628 var utc = createUTC().set(setter, index);
22629 return locale[field](utc, format);
22630 }
22631
22632 function listMonthsImpl(format, index, field) {
22633 if (isNumber(format)) {
22634 index = format;
22635 format = undefined;
22636 }
22637
22638 format = format || '';
22639
22640 if (index != null) {
22641 return get$1(format, index, field, 'month');
22642 }
22643
22644 var i;
22645 var out = [];
22646
22647 for (i = 0; i < 12; i++) {
22648 out[i] = get$1(format, i, field, 'month');
22649 }
22650
22651 return out;
22652 } // ()
22653 // (5)
22654 // (fmt, 5)
22655 // (fmt)
22656 // (true)
22657 // (true, 5)
22658 // (true, fmt, 5)
22659 // (true, fmt)
22660
22661
22662 function listWeekdaysImpl(localeSorted, format, index, field) {
22663 if (typeof localeSorted === 'boolean') {
22664 if (isNumber(format)) {
22665 index = format;
22666 format = undefined;
22667 }
22668
22669 format = format || '';
22670 } else {
22671 format = localeSorted;
22672 index = format;
22673 localeSorted = false;
22674
22675 if (isNumber(format)) {
22676 index = format;
22677 format = undefined;
22678 }
22679
22680 format = format || '';
22681 }
22682
22683 var locale = getLocale(),
22684 shift = localeSorted ? locale._week.dow : 0;
22685
22686 if (index != null) {
22687 return get$1(format, (index + shift) % 7, field, 'day');
22688 }
22689
22690 var i;
22691 var out = [];
22692
22693 for (i = 0; i < 7; i++) {
22694 out[i] = get$1(format, (i + shift) % 7, field, 'day');
22695 }
22696
22697 return out;
22698 }
22699
22700 function listMonths(format, index) {
22701 return listMonthsImpl(format, index, 'months');
22702 }
22703
22704 function listMonthsShort(format, index) {
22705 return listMonthsImpl(format, index, 'monthsShort');
22706 }
22707
22708 function listWeekdays(localeSorted, format, index) {
22709 return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
22710 }
22711
22712 function listWeekdaysShort(localeSorted, format, index) {
22713 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
22714 }
22715
22716 function listWeekdaysMin(localeSorted, format, index) {
22717 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
22718 }
22719
22720 getSetGlobalLocale('en', {
22721 dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
22722 ordinal: function (number) {
22723 var b = number % 10,
22724 output = toInt(number % 100 / 10) === 1 ? 'th' : b === 1 ? 'st' : b === 2 ? 'nd' : b === 3 ? 'rd' : 'th';
22725 return number + output;
22726 }
22727 }); // Side effect imports
22728
22729 hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
22730 hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
22731 var mathAbs = Math.abs;
22732
22733 function abs() {
22734 var data = this._data;
22735 this._milliseconds = mathAbs(this._milliseconds);
22736 this._days = mathAbs(this._days);
22737 this._months = mathAbs(this._months);
22738 data.milliseconds = mathAbs(data.milliseconds);
22739 data.seconds = mathAbs(data.seconds);
22740 data.minutes = mathAbs(data.minutes);
22741 data.hours = mathAbs(data.hours);
22742 data.months = mathAbs(data.months);
22743 data.years = mathAbs(data.years);
22744 return this;
22745 }
22746
22747 function addSubtract$1(duration, input, value, direction) {
22748 var other = createDuration(input, value);
22749 duration._milliseconds += direction * other._milliseconds;
22750 duration._days += direction * other._days;
22751 duration._months += direction * other._months;
22752 return duration._bubble();
22753 } // supports only 2.0-style add(1, 's') or add(duration)
22754
22755
22756 function add$1(input, value) {
22757 return addSubtract$1(this, input, value, 1);
22758 } // supports only 2.0-style subtract(1, 's') or subtract(duration)
22759
22760
22761 function subtract$1(input, value) {
22762 return addSubtract$1(this, input, value, -1);
22763 }
22764
22765 function absCeil(number) {
22766 if (number < 0) {
22767 return Math.floor(number);
22768 } else {
22769 return Math.ceil(number);
22770 }
22771 }
22772
22773 function bubble() {
22774 var milliseconds = this._milliseconds;
22775 var days = this._days;
22776 var months = this._months;
22777 var data = this._data;
22778 var seconds, minutes, hours, years, monthsFromDays; // if we have a mix of positive and negative values, bubble down first
22779 // check: https://github.com/moment/moment/issues/2166
22780
22781 if (!(milliseconds >= 0 && days >= 0 && months >= 0 || milliseconds <= 0 && days <= 0 && months <= 0)) {
22782 milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
22783 days = 0;
22784 months = 0;
22785 } // The following code bubbles up values, see the tests for
22786 // examples of what that means.
22787
22788
22789 data.milliseconds = milliseconds % 1000;
22790 seconds = absFloor(milliseconds / 1000);
22791 data.seconds = seconds % 60;
22792 minutes = absFloor(seconds / 60);
22793 data.minutes = minutes % 60;
22794 hours = absFloor(minutes / 60);
22795 data.hours = hours % 24;
22796 days += absFloor(hours / 24); // convert days to months
22797
22798 monthsFromDays = absFloor(daysToMonths(days));
22799 months += monthsFromDays;
22800 days -= absCeil(monthsToDays(monthsFromDays)); // 12 months -> 1 year
22801
22802 years = absFloor(months / 12);
22803 months %= 12;
22804 data.days = days;
22805 data.months = months;
22806 data.years = years;
22807 return this;
22808 }
22809
22810 function daysToMonths(days) {
22811 // 400 years have 146097 days (taking into account leap year rules)
22812 // 400 years have 12 months === 4800
22813 return days * 4800 / 146097;
22814 }
22815
22816 function monthsToDays(months) {
22817 // the reverse of daysToMonths
22818 return months * 146097 / 4800;
22819 }
22820
22821 function as(units) {
22822 if (!this.isValid()) {
22823 return NaN;
22824 }
22825
22826 var days;
22827 var months;
22828 var milliseconds = this._milliseconds;
22829 units = normalizeUnits(units);
22830
22831 if (units === 'month' || units === 'quarter' || units === 'year') {
22832 days = this._days + milliseconds / 864e5;
22833 months = this._months + daysToMonths(days);
22834
22835 switch (units) {
22836 case 'month':
22837 return months;
22838
22839 case 'quarter':
22840 return months / 3;
22841
22842 case 'year':
22843 return months / 12;
22844 }
22845 } else {
22846 // handle milliseconds separately because of floating point math errors (issue #1867)
22847 days = this._days + Math.round(monthsToDays(this._months));
22848
22849 switch (units) {
22850 case 'week':
22851 return days / 7 + milliseconds / 6048e5;
22852
22853 case 'day':
22854 return days + milliseconds / 864e5;
22855
22856 case 'hour':
22857 return days * 24 + milliseconds / 36e5;
22858
22859 case 'minute':
22860 return days * 1440 + milliseconds / 6e4;
22861
22862 case 'second':
22863 return days * 86400 + milliseconds / 1000;
22864 // Math.floor prevents floating point math errors here
22865
22866 case 'millisecond':
22867 return Math.floor(days * 864e5) + milliseconds;
22868
22869 default:
22870 throw new Error('Unknown unit ' + units);
22871 }
22872 }
22873 } // TODO: Use this.as('ms')?
22874
22875
22876 function valueOf$1() {
22877 if (!this.isValid()) {
22878 return NaN;
22879 }
22880
22881 return this._milliseconds + this._days * 864e5 + this._months % 12 * 2592e6 + toInt(this._months / 12) * 31536e6;
22882 }
22883
22884 function makeAs(alias) {
22885 return function () {
22886 return this.as(alias);
22887 };
22888 }
22889
22890 var asMilliseconds = makeAs('ms');
22891 var asSeconds = makeAs('s');
22892 var asMinutes = makeAs('m');
22893 var asHours = makeAs('h');
22894 var asDays = makeAs('d');
22895 var asWeeks = makeAs('w');
22896 var asMonths = makeAs('M');
22897 var asQuarters = makeAs('Q');
22898 var asYears = makeAs('y');
22899
22900 function clone$1() {
22901 return createDuration(this);
22902 }
22903
22904 function get$2(units) {
22905 units = normalizeUnits(units);
22906 return this.isValid() ? this[units + 's']() : NaN;
22907 }
22908
22909 function makeGetter(name) {
22910 return function () {
22911 return this.isValid() ? this._data[name] : NaN;
22912 };
22913 }
22914
22915 var milliseconds = makeGetter('milliseconds');
22916 var seconds = makeGetter('seconds');
22917 var minutes = makeGetter('minutes');
22918 var hours = makeGetter('hours');
22919 var days = makeGetter('days');
22920 var months = makeGetter('months');
22921 var years = makeGetter('years');
22922
22923 function weeks() {
22924 return absFloor(this.days() / 7);
22925 }
22926
22927 var round = Math.round;
22928 var thresholds = {
22929 ss: 44,
22930 // a few seconds to seconds
22931 s: 45,
22932 // seconds to minute
22933 m: 45,
22934 // minutes to hour
22935 h: 22,
22936 // hours to day
22937 d: 26,
22938 // days to month
22939 M: 11 // months to year
22940
22941 }; // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
22942
22943 function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
22944 return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
22945 }
22946
22947 function relativeTime$1(posNegDuration, withoutSuffix, locale) {
22948 var duration = createDuration(posNegDuration).abs();
22949 var seconds = round(duration.as('s'));
22950 var minutes = round(duration.as('m'));
22951 var hours = round(duration.as('h'));
22952 var days = round(duration.as('d'));
22953 var months = round(duration.as('M'));
22954 var years = round(duration.as('y'));
22955 var a = seconds <= thresholds.ss && ['s', seconds] || seconds < thresholds.s && ['ss', seconds] || minutes <= 1 && ['m'] || minutes < thresholds.m && ['mm', minutes] || hours <= 1 && ['h'] || hours < thresholds.h && ['hh', hours] || days <= 1 && ['d'] || days < thresholds.d && ['dd', days] || months <= 1 && ['M'] || months < thresholds.M && ['MM', months] || years <= 1 && ['y'] || ['yy', years];
22956 a[2] = withoutSuffix;
22957 a[3] = +posNegDuration > 0;
22958 a[4] = locale;
22959 return substituteTimeAgo.apply(null, a);
22960 } // This function allows you to set the rounding function for relative time strings
22961
22962
22963 function getSetRelativeTimeRounding(roundingFunction) {
22964 if (roundingFunction === undefined) {
22965 return round;
22966 }
22967
22968 if (typeof roundingFunction === 'function') {
22969 round = roundingFunction;
22970 return true;
22971 }
22972
22973 return false;
22974 } // This function allows you to set a threshold for relative time strings
22975
22976
22977 function getSetRelativeTimeThreshold(threshold, limit) {
22978 if (thresholds[threshold] === undefined) {
22979 return false;
22980 }
22981
22982 if (limit === undefined) {
22983 return thresholds[threshold];
22984 }
22985
22986 thresholds[threshold] = limit;
22987
22988 if (threshold === 's') {
22989 thresholds.ss = limit - 1;
22990 }
22991
22992 return true;
22993 }
22994
22995 function humanize(withSuffix) {
22996 if (!this.isValid()) {
22997 return this.localeData().invalidDate();
22998 }
22999
23000 var locale = this.localeData();
23001 var output = relativeTime$1(this, !withSuffix, locale);
23002
23003 if (withSuffix) {
23004 output = locale.pastFuture(+this, output);
23005 }
23006
23007 return locale.postformat(output);
23008 }
23009
23010 var abs$1 = Math.abs;
23011
23012 function sign(x) {
23013 return (x > 0) - (x < 0) || +x;
23014 }
23015
23016 function toISOString$1() {
23017 // for ISO strings we do not use the normal bubbling rules:
23018 // * milliseconds bubble up until they become hours
23019 // * days do not bubble at all
23020 // * months bubble up until they become years
23021 // This is because there is no context-free conversion between hours and days
23022 // (think of clock changes)
23023 // and also not between days and months (28-31 days per month)
23024 if (!this.isValid()) {
23025 return this.localeData().invalidDate();
23026 }
23027
23028 var seconds = abs$1(this._milliseconds) / 1000;
23029 var days = abs$1(this._days);
23030 var months = abs$1(this._months);
23031 var minutes, hours, years; // 3600 seconds -> 60 minutes -> 1 hour
23032
23033 minutes = absFloor(seconds / 60);
23034 hours = absFloor(minutes / 60);
23035 seconds %= 60;
23036 minutes %= 60; // 12 months -> 1 year
23037
23038 years = absFloor(months / 12);
23039 months %= 12; // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
23040
23041 var Y = years;
23042 var M = months;
23043 var D = days;
23044 var h = hours;
23045 var m = minutes;
23046 var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
23047 var total = this.asSeconds();
23048
23049 if (!total) {
23050 // this is the same as C#'s (Noda) and python (isodate)...
23051 // but not other JS (goog.date)
23052 return 'P0D';
23053 }
23054
23055 var totalSign = total < 0 ? '-' : '';
23056 var ymSign = sign(this._months) !== sign(total) ? '-' : '';
23057 var daysSign = sign(this._days) !== sign(total) ? '-' : '';
23058 var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
23059 return totalSign + 'P' + (Y ? ymSign + Y + 'Y' : '') + (M ? ymSign + M + 'M' : '') + (D ? daysSign + D + 'D' : '') + (h || m || s ? 'T' : '') + (h ? hmsSign + h + 'H' : '') + (m ? hmsSign + m + 'M' : '') + (s ? hmsSign + s + 'S' : '');
23060 }
23061
23062 var proto$2 = Duration.prototype;
23063 proto$2.isValid = isValid$1;
23064 proto$2.abs = abs;
23065 proto$2.add = add$1;
23066 proto$2.subtract = subtract$1;
23067 proto$2.as = as;
23068 proto$2.asMilliseconds = asMilliseconds;
23069 proto$2.asSeconds = asSeconds;
23070 proto$2.asMinutes = asMinutes;
23071 proto$2.asHours = asHours;
23072 proto$2.asDays = asDays;
23073 proto$2.asWeeks = asWeeks;
23074 proto$2.asMonths = asMonths;
23075 proto$2.asQuarters = asQuarters;
23076 proto$2.asYears = asYears;
23077 proto$2.valueOf = valueOf$1;
23078 proto$2._bubble = bubble;
23079 proto$2.clone = clone$1;
23080 proto$2.get = get$2;
23081 proto$2.milliseconds = milliseconds;
23082 proto$2.seconds = seconds;
23083 proto$2.minutes = minutes;
23084 proto$2.hours = hours;
23085 proto$2.days = days;
23086 proto$2.weeks = weeks;
23087 proto$2.months = months;
23088 proto$2.years = years;
23089 proto$2.humanize = humanize;
23090 proto$2.toISOString = toISOString$1;
23091 proto$2.toString = toISOString$1;
23092 proto$2.toJSON = toISOString$1;
23093 proto$2.locale = locale;
23094 proto$2.localeData = localeData;
23095 proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
23096 proto$2.lang = lang; // Side effect imports
23097 // FORMATTING
23098
23099 addFormatToken('X', 0, 0, 'unix');
23100 addFormatToken('x', 0, 0, 'valueOf'); // PARSING
23101
23102 addRegexToken('x', matchSigned);
23103 addRegexToken('X', matchTimestamp);
23104 addParseToken('X', function (input, array, config) {
23105 config._d = new Date(parseFloat(input, 10) * 1000);
23106 });
23107 addParseToken('x', function (input, array, config) {
23108 config._d = new Date(toInt(input));
23109 }); // Side effect imports
23110
23111 hooks.version = '2.24.0';
23112 setHookCallback(createLocal);
23113 hooks.fn = proto;
23114 hooks.min = min;
23115 hooks.max = max;
23116 hooks.now = now;
23117 hooks.utc = createUTC;
23118 hooks.unix = createUnix;
23119 hooks.months = listMonths;
23120 hooks.isDate = isDate;
23121 hooks.locale = getSetGlobalLocale;
23122 hooks.invalid = createInvalid;
23123 hooks.duration = createDuration;
23124 hooks.isMoment = isMoment;
23125 hooks.weekdays = listWeekdays;
23126 hooks.parseZone = createInZone;
23127 hooks.localeData = getLocale;
23128 hooks.isDuration = isDuration;
23129 hooks.monthsShort = listMonthsShort;
23130 hooks.weekdaysMin = listWeekdaysMin;
23131 hooks.defineLocale = defineLocale;
23132 hooks.updateLocale = updateLocale;
23133 hooks.locales = listLocales;
23134 hooks.weekdaysShort = listWeekdaysShort;
23135 hooks.normalizeUnits = normalizeUnits;
23136 hooks.relativeTimeRounding = getSetRelativeTimeRounding;
23137 hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
23138 hooks.calendarFormat = getCalendarFormat;
23139 hooks.prototype = proto; // currently HTML5 input type only supports 24-hour formats
23140
23141 hooks.HTML5_FMT = {
23142 DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',
23143 // <input type="datetime-local" />
23144 DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',
23145 // <input type="datetime-local" step="1" />
23146 DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',
23147 // <input type="datetime-local" step="0.001" />
23148 DATE: 'YYYY-MM-DD',
23149 // <input type="date" />
23150 TIME: 'HH:mm',
23151 // <input type="time" />
23152 TIME_SECONDS: 'HH:mm:ss',
23153 // <input type="time" step="1" />
23154 TIME_MS: 'HH:mm:ss.SSS',
23155 // <input type="time" step="0.001" />
23156 WEEK: 'GGGG-[W]WW',
23157 // <input type="week" />
23158 MONTH: 'YYYY-MM' // <input type="month" />
23159
23160 };
23161 return hooks;
23162 });
23163 }); // Maps for number <-> hex string conversion
23164
23165 var byteToHex$2$1 = [];
23166
23167 for (var i$2$1 = 0; i$2$1 < 256; i$2$1++) {
23168 byteToHex$2$1[i$2$1] = (i$2$1 + 0x100).toString(16).substr(1);
23169 }
23170 /**
23171 * Generate 16 random bytes to be used as a base for UUID.
23172 *
23173 * @ignore
23174 */
23175
23176
23177 var random$1$1 = function () {
23178 if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
23179 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
23180 // Moderately fast, high quality
23181 var _rnds8 = new Uint8Array(16);
23182
23183 return function whatwgRNG() {
23184 crypto.getRandomValues(_rnds8);
23185 return _rnds8;
23186 };
23187 } // Math.random()-based (RNG)
23188 //
23189 // If all else fails, use Math.random().
23190 // It's fast, but is of unspecified quality.
23191
23192
23193 var _rnds = new Array(16);
23194
23195 return function () {
23196 for (var i = 0, r; i < 16; i++) {
23197 if ((i & 0x03) === 0) {
23198 r = Math.random() * 0x100000000;
23199 }
23200
23201 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
23202 }
23203
23204 return _rnds;
23205 }; // uuid.js
23206 //
23207 // Copyright (c) 2010-2012 Robert Kieffer
23208 // MIT License - http://opensource.org/licenses/mit-license.php
23209 // Unique ID creation requires a high quality random # generator. We feature
23210 // detect to determine the best RNG source, normalizing to a function that
23211 // returns 128-bits of randomness, since that's what's usually required
23212 // return require('./rng');
23213 }();
23214
23215 var byteToHex$1$1$1 = [];
23216
23217 for (var i$1$1$1 = 0; i$1$1$1 < 256; i$1$1$1++) {
23218 byteToHex$1$1$1[i$1$1$1] = (i$1$1$1 + 0x100).toString(16).substr(1);
23219 } // **`v1()` - Generate time-based UUID**
23220 //
23221 // Inspired by https://github.com/LiosK/UUID.js
23222 // and http://docs.python.org/library/uuid.html
23223 // random #'s we need to init node and clockseq
23224
23225
23226 var seedBytes$1$1 = random$1$1(); // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
23227
23228 var defaultNodeId$1$1 = [seedBytes$1$1[0] | 0x01, seedBytes$1$1[1], seedBytes$1$1[2], seedBytes$1$1[3], seedBytes$1$1[4], seedBytes$1$1[5]]; // Per 4.2.2, randomize (14 bit) clockseq
23229
23230 var defaultClockseq$1$1 = (seedBytes$1$1[6] << 8 | seedBytes$1$1[7]) & 0x3fff; // Previous uuid creation time
23231 // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/'
23232 // code from http://momentjs.com/
23233
23234 var ASPDateRegex$1 = /^\/?Date\((-?\d+)/i; // Hex color
23235
23236 /**
23237 * Hue, Saturation, Value.
23238 */
23239
23240 /**
23241 * Test whether given object is a number
23242 *
23243 * @param value - Input value of unknown type.
23244 *
23245 * @returns True if number, false otherwise.
23246 */
23247
23248 function isNumber$1(value) {
23249 return value instanceof Number || typeof value === 'number';
23250 }
23251 /**
23252 * Test whether given object is a string
23253 *
23254 * @param value - Input value of unknown type.
23255 *
23256 * @returns True if string, false otherwise.
23257 */
23258
23259
23260 function isString$1(value) {
23261 return value instanceof String || typeof value === 'string';
23262 }
23263 /**
23264 * Test whether given object is a Moment date.
23265 * @TODO: This is basically a workaround, if Moment was imported property it wouldn't necessary as moment.isMoment is a TS type guard.
23266 *
23267 * @param value - Input value of unknown type.
23268 *
23269 * @returns True if Moment instance, false otherwise.
23270 */
23271
23272
23273 function isMoment$1(value) {
23274 return moment$1.isMoment(value);
23275 }
23276 /**
23277 * Copy property from b to a if property present in a.
23278 * If property in b explicitly set to null, delete it if `allowDeletion` set.
23279 *
23280 * Internal helper routine, should not be exported. Not added to `exports` for that reason.
23281 *
23282 * @param a - Target object.
23283 * @param b - Source object.
23284 * @param prop - Name of property to copy from b to a.
23285 * @param allowDeletion if true, delete property in a if explicitly set to null in b
23286 */
23287
23288
23289 function copyOrDelete$1(a, b, prop, allowDeletion) {
23290 var doDeletion = false;
23291
23292 if (allowDeletion === true) {
23293 doDeletion = b[prop] === null && a[prop] !== undefined;
23294 }
23295
23296 if (doDeletion) {
23297 delete a[prop];
23298 } else {
23299 a[prop] = b[prop]; // Remember, this is a reference copy!
23300 }
23301 }
23302 /**
23303 * Deep extend an object a with the properties of object b
23304 *
23305 * @param a - Target object.
23306 * @param b - Source object.
23307 * @param protoExtend - If true, the prototype values will also be extended
23308 * (ie. the options objects that inherit from others will also get the inherited options).
23309 * @param allowDeletion - If true, the values of fields that are null will be deleted.
23310 *
23311 * @returns Argument a.
23312 */
23313
23314
23315 function deepExtend$1(a, b) {
23316 var protoExtend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
23317 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
23318
23319 for (var prop in b) {
23320 if (Object.prototype.hasOwnProperty.call(b, prop) || protoExtend === true) {
23321 if (b[prop] && b[prop].constructor === Object) {
23322 if (a[prop] === undefined) {
23323 a[prop] = {};
23324 }
23325
23326 if (a[prop].constructor === Object) {
23327 deepExtend$1(a[prop], b[prop], protoExtend); // NOTE: allowDeletion not propagated!
23328 } else {
23329 copyOrDelete$1(a, b, prop, allowDeletion);
23330 }
23331 } else if (Array.isArray(b[prop])) {
23332 a[prop] = [];
23333
23334 for (var i = 0; i < b[prop].length; i++) {
23335 a[prop].push(b[prop][i]);
23336 }
23337 } else {
23338 copyOrDelete$1(a, b, prop, allowDeletion);
23339 }
23340 }
23341 }
23342
23343 return a;
23344 }
23345 /**
23346 * Convert an object into another type
23347 *
23348 * @param object - Value of unknown type.
23349 * @param type - Name of the desired type.
23350 *
23351 * @returns Object in the desired type.
23352 * @throws Error
23353 */
23354
23355
23356 function convert$1(object, type) {
23357 var match;
23358
23359 if (object === undefined) {
23360 return undefined;
23361 }
23362
23363 if (object === null) {
23364 return null;
23365 }
23366
23367 if (!type) {
23368 return object;
23369 }
23370
23371 if (!(typeof type === 'string') && !(type instanceof String)) {
23372 throw new Error('Type must be a string');
23373 } //noinspection FallthroughInSwitchStatementJS
23374
23375
23376 switch (type) {
23377 case 'boolean':
23378 case 'Boolean':
23379 return Boolean(object);
23380
23381 case 'number':
23382 case 'Number':
23383 if (isString$1(object) && !isNaN(Date.parse(object))) {
23384 return moment$1(object).valueOf();
23385 } else {
23386 // @TODO: I don't think that Number and String constructors are a good idea.
23387 // This could also fail if the object doesn't have valueOf method or if it's redefined.
23388 // For example: Object.create(null) or { valueOf: 7 }.
23389 return Number(object.valueOf());
23390 }
23391
23392 case 'string':
23393 case 'String':
23394 return String(object);
23395
23396 case 'Date':
23397 if (isNumber$1(object)) {
23398 return new Date(object);
23399 }
23400
23401 if (object instanceof Date) {
23402 return new Date(object.valueOf());
23403 } else if (isMoment$1(object)) {
23404 return new Date(object.valueOf());
23405 }
23406
23407 if (isString$1(object)) {
23408 match = ASPDateRegex$1.exec(object);
23409
23410 if (match) {
23411 // object is an ASP date
23412 return new Date(Number(match[1])); // parse number
23413 } else {
23414 return moment$1(new Date(object)).toDate(); // parse string
23415 }
23416 } else {
23417 throw new Error('Cannot convert object of type ' + getType$1(object) + ' to type Date');
23418 }
23419
23420 case 'Moment':
23421 if (isNumber$1(object)) {
23422 return moment$1(object);
23423 }
23424
23425 if (object instanceof Date) {
23426 return moment$1(object.valueOf());
23427 } else if (isMoment$1(object)) {
23428 return moment$1(object);
23429 }
23430
23431 if (isString$1(object)) {
23432 match = ASPDateRegex$1.exec(object);
23433
23434 if (match) {
23435 // object is an ASP date
23436 return moment$1(Number(match[1])); // parse number
23437 } else {
23438 return moment$1(object); // parse string
23439 }
23440 } else {
23441 throw new Error('Cannot convert object of type ' + getType$1(object) + ' to type Date');
23442 }
23443
23444 case 'ISODate':
23445 if (isNumber$1(object)) {
23446 return new Date(object);
23447 } else if (object instanceof Date) {
23448 return object.toISOString();
23449 } else if (isMoment$1(object)) {
23450 return object.toDate().toISOString();
23451 } else if (isString$1(object)) {
23452 match = ASPDateRegex$1.exec(object);
23453
23454 if (match) {
23455 // object is an ASP date
23456 return new Date(Number(match[1])).toISOString(); // parse number
23457 } else {
23458 return moment$1(object).format(); // ISO 8601
23459 }
23460 } else {
23461 throw new Error('Cannot convert object of type ' + getType$1(object) + ' to type ISODate');
23462 }
23463
23464 case 'ASPDate':
23465 if (isNumber$1(object)) {
23466 return '/Date(' + object + ')/';
23467 } else if (object instanceof Date) {
23468 return '/Date(' + object.valueOf() + ')/';
23469 } else if (isString$1(object)) {
23470 match = ASPDateRegex$1.exec(object);
23471
23472 var _value;
23473
23474 if (match) {
23475 // object is an ASP date
23476 _value = new Date(Number(match[1])).valueOf(); // parse number
23477 } else {
23478 _value = new Date(object).valueOf(); // parse string
23479 }
23480
23481 return '/Date(' + _value + ')/';
23482 } else {
23483 throw new Error('Cannot convert object of type ' + getType$1(object) + ' to type ASPDate');
23484 }
23485
23486 default:
23487 var never = type;
23488 throw new Error("Unknown type ".concat(never));
23489 }
23490 }
23491 /**
23492 * Get the type of an object, for example exports.getType([]) returns 'Array'
23493 *
23494 * @param object - Input value of unknown type.
23495 *
23496 * @returns Detected type.
23497 */
23498
23499
23500 function getType$1(object) {
23501 var type = _typeof$2(object);
23502
23503 if (type === 'object') {
23504 if (object === null) {
23505 return 'null';
23506 }
23507
23508 if (object instanceof Boolean) {
23509 return 'Boolean';
23510 }
23511
23512 if (object instanceof Number) {
23513 return 'Number';
23514 }
23515
23516 if (object instanceof String) {
23517 return 'String';
23518 }
23519
23520 if (Array.isArray(object)) {
23521 return 'Array';
23522 }
23523
23524 if (object instanceof Date) {
23525 return 'Date';
23526 }
23527
23528 return 'Object';
23529 }
23530
23531 if (type === 'number') {
23532 return 'Number';
23533 }
23534
23535 if (type === 'boolean') {
23536 return 'Boolean';
23537 }
23538
23539 if (type === 'string') {
23540 return 'String';
23541 }
23542
23543 if (type === undefined) {
23544 return 'undefined';
23545 }
23546
23547 return type;
23548 }
23549 /**
23550 * Determine whether a value can be used as an id.
23551 *
23552 * @param value - Input value of unknown type.
23553 *
23554 * @returns True if the value is valid id, false otherwise.
23555 */
23556
23557
23558 function isId(value) {
23559 return typeof value === "string" || typeof value === "number";
23560 }
23561 /* eslint @typescript-eslint/member-ordering: ["error", { "classes": ["field", "constructor", "method"] }] */
23562
23563 /**
23564 * A queue.
23565 *
23566 * @typeParam T - The type of method names to be replaced by queued versions.
23567 */
23568
23569
23570 var Queue =
23571 /*#__PURE__*/
23572 function () {
23573 /**
23574 * Construct a new Queue.
23575 *
23576 * @param options - Queue configuration.
23577 */
23578 function Queue(options) {
23579 classCallCheck(this, Queue);
23580 this._queue = [];
23581 this._timeout = null;
23582 this._extended = null; // options
23583
23584 this.delay = null;
23585 this.max = Infinity;
23586 this.setOptions(options);
23587 }
23588 /**
23589 * Update the configuration of the queue.
23590 *
23591 * @param options - Queue configuration.
23592 */
23593
23594
23595 createClass(Queue, [{
23596 key: "setOptions",
23597 value: function setOptions(options) {
23598 if (options && typeof options.delay !== "undefined") {
23599 this.delay = options.delay;
23600 }
23601
23602 if (options && typeof options.max !== "undefined") {
23603 this.max = options.max;
23604 }
23605
23606 this._flushIfNeeded();
23607 }
23608 /**
23609 * Extend an object with queuing functionality.
23610 * The object will be extended with a function flush, and the methods provided in options.replace will be replaced with queued ones.
23611 *
23612 * @param object - The object to be extended.
23613 * @param options - Additional options.
23614 *
23615 * @returns The created queue.
23616 */
23617
23618 }, {
23619 key: "destroy",
23620
23621 /**
23622 * Destroy the queue. The queue will first flush all queued actions, and in case it has extended an object, will restore the original object.
23623 */
23624 value: function destroy() {
23625 this.flush();
23626
23627 if (this._extended) {
23628 var object = this._extended.object;
23629 var methods = this._extended.methods;
23630
23631 for (var i = 0; i < methods.length; i++) {
23632 var method = methods[i];
23633
23634 if (method.original) {
23635 // @TODO: better solution?
23636 object[method.name] = method.original;
23637 } else {
23638 // @TODO: better solution?
23639 delete object[method.name];
23640 }
23641 }
23642
23643 this._extended = null;
23644 }
23645 }
23646 /**
23647 * Replace a method on an object with a queued version.
23648 *
23649 * @param object - Object having the method.
23650 * @param method - The method name.
23651 */
23652
23653 }, {
23654 key: "replace",
23655 value: function replace(object, method) {
23656 /* eslint-disable-next-line @typescript-eslint/no-this-alias */
23657 var me = this;
23658 var original = object[method];
23659
23660 if (!original) {
23661 throw new Error("Method " + method + " undefined");
23662 }
23663
23664 object[method] = function () {
23665 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
23666 args[_key] = arguments[_key];
23667 } // add this call to the queue
23668
23669
23670 me.queue({
23671 args: args,
23672 fn: original,
23673 context: this
23674 });
23675 };
23676 }
23677 /**
23678 * Queue a call.
23679 *
23680 * @param entry - The function or entry to be queued.
23681 */
23682
23683 }, {
23684 key: "queue",
23685 value: function queue(entry) {
23686 if (typeof entry === "function") {
23687 this._queue.push({
23688 fn: entry
23689 });
23690 } else {
23691 this._queue.push(entry);
23692 }
23693
23694 this._flushIfNeeded();
23695 }
23696 /**
23697 * Check whether the queue needs to be flushed.
23698 */
23699
23700 }, {
23701 key: "_flushIfNeeded",
23702 value: function _flushIfNeeded() {
23703 var _this = this; // flush when the maximum is exceeded.
23704
23705
23706 if (this._queue.length > this.max) {
23707 this.flush();
23708 } // flush after a period of inactivity when a delay is configured
23709
23710
23711 if (this._timeout != null) {
23712 clearTimeout(this._timeout);
23713 this._timeout = null;
23714 }
23715
23716 if (this.queue.length > 0 && typeof this.delay === "number") {
23717 this._timeout = setTimeout(function () {
23718 _this.flush();
23719 }, this.delay);
23720 }
23721 }
23722 /**
23723 * Flush all queued calls
23724 */
23725
23726 }, {
23727 key: "flush",
23728 value: function flush() {
23729 this._queue.splice(0).forEach(function (entry) {
23730 entry.fn.apply(entry.context || entry.fn, entry.args || []);
23731 });
23732 }
23733 }], [{
23734 key: "extend",
23735 value: function extend(object, options) {
23736 var queue = new Queue(options);
23737
23738 if (object.flush !== undefined) {
23739 throw new Error("Target object already has a property flush");
23740 }
23741
23742 object.flush = function () {
23743 queue.flush();
23744 };
23745
23746 var methods = [{
23747 name: "flush",
23748 original: undefined
23749 }];
23750
23751 if (options && options.replace) {
23752 for (var i = 0; i < options.replace.length; i++) {
23753 var name = options.replace[i];
23754 methods.push({
23755 name: name,
23756 // @TODO: better solution?
23757 original: object[name]
23758 }); // @TODO: better solution?
23759
23760 queue.replace(object, name);
23761 }
23762 }
23763
23764 queue._extended = {
23765 object: object,
23766 methods: methods
23767 };
23768 return queue;
23769 }
23770 }]);
23771 return Queue;
23772 }();
23773 /* eslint-disable @typescript-eslint/member-ordering */
23774
23775 /**
23776 * [[DataSet]] code that can be reused in [[DataView]] or other similar implementations of [[DataInterface]].
23777 *
23778 * @typeParam Item - Item type that may or may not have an id.
23779 * @typeParam IdProp - Name of the property that contains the id.
23780 */
23781
23782
23783 var DataSetPart =
23784 /*#__PURE__*/
23785 function () {
23786 function DataSetPart() {
23787 classCallCheck(this, DataSetPart);
23788 this._subscribers = {
23789 "*": [],
23790 add: [],
23791 remove: [],
23792 update: []
23793 };
23794 /**
23795 * @deprecated Use on instead (PS: DataView.subscribe === DataView.on).
23796 */
23797
23798 this.subscribe = DataSetPart.prototype.on;
23799 /**
23800 * @deprecated Use off instead (PS: DataView.unsubscribe === DataView.off).
23801 */
23802
23803 this.unsubscribe = DataSetPart.prototype.off;
23804 }
23805 /**
23806 * Trigger an event
23807 *
23808 * @param event - Event name.
23809 * @param payload - Event payload.
23810 * @param senderId - Id of the sender.
23811 */
23812
23813
23814 createClass(DataSetPart, [{
23815 key: "_trigger",
23816 value: function _trigger(event, payload, senderId) {
23817 if (event === "*") {
23818 throw new Error("Cannot trigger event *");
23819 }
23820
23821 [].concat(toConsumableArray(this._subscribers[event]), toConsumableArray(this._subscribers["*"])).forEach(function (subscriber) {
23822 subscriber(event, payload, senderId != null ? senderId : null);
23823 });
23824 }
23825 /**
23826 * Subscribe to an event, add an event listener.
23827 *
23828 * @remarks Non-function callbacks are ignored.
23829 *
23830 * @param event - Event name.
23831 * @param callback - Callback method.
23832 */
23833
23834 }, {
23835 key: "on",
23836 value: function on(event, callback) {
23837 if (typeof callback === "function") {
23838 this._subscribers[event].push(callback);
23839 } // @TODO: Maybe throw for invalid callbacks?
23840
23841 }
23842 /**
23843 * Unsubscribe from an event, remove an event listener.
23844 *
23845 * @remarks If the same callback was subscribed more than once **all** occurences will be removed.
23846 *
23847 * @param event - Event name.
23848 * @param callback - Callback method.
23849 */
23850
23851 }, {
23852 key: "off",
23853 value: function off(event, callback) {
23854 this._subscribers[event] = this._subscribers[event].filter(function (subscriber) {
23855 return subscriber !== callback;
23856 });
23857 }
23858 }]);
23859 return DataSetPart;
23860 }();
23861
23862 function _arrayWithHoles$1(arr) {
23863 if (Array.isArray(arr)) return arr;
23864 }
23865
23866 var arrayWithHoles = _arrayWithHoles$1;
23867
23868 function _iterableToArrayLimit$1(arr, i) {
23869 var _arr = [];
23870 var _n = true;
23871 var _d = false;
23872 var _e = undefined;
23873
23874 try {
23875 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
23876 _arr.push(_s.value);
23877
23878 if (i && _arr.length === i) break;
23879 }
23880 } catch (err) {
23881 _d = true;
23882 _e = err;
23883 } finally {
23884 try {
23885 if (!_n && _i["return"] != null) _i["return"]();
23886 } finally {
23887 if (_d) throw _e;
23888 }
23889 }
23890
23891 return _arr;
23892 }
23893
23894 var iterableToArrayLimit = _iterableToArrayLimit$1;
23895
23896 function _nonIterableRest$1() {
23897 throw new TypeError("Invalid attempt to destructure non-iterable instance");
23898 }
23899
23900 var nonIterableRest = _nonIterableRest$1;
23901
23902 function _slicedToArray$1(arr, i) {
23903 return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || nonIterableRest();
23904 }
23905
23906 var slicedToArray = _slicedToArray$1;
23907 /**
23908 * Data stream
23909 *
23910 * @remarks
23911 * [[DataStream]] offers an always up to date stream of items from a [[DataSet]] or [[DataView]].
23912 * That means that the stream is evaluated at the time of iteration, conversion to another data type or when [[cache]] is called, not when the [[DataStream]] was created.
23913 * Multiple invocations of for example [[toItemArray]] may yield different results (if the data source like for example [[DataSet]] gets modified).
23914 *
23915 * @typeparam Item - The item type this stream is going to work with.
23916 */
23917
23918 var DataStream =
23919 /*#__PURE__*/
23920 function () {
23921 /**
23922 * Create a new data stream.
23923 *
23924 * @param _pairs - The id, item pairs.
23925 */
23926 function DataStream(_pairs) {
23927 classCallCheck(this, DataStream);
23928 this._pairs = _pairs;
23929 }
23930 /**
23931 * Return an iterable of key, value pairs for every entry in the stream.
23932 */
23933
23934
23935 createClass(DataStream, [{
23936 key: Symbol.iterator,
23937 value:
23938 /*#__PURE__*/
23939 regenerator.mark(function value() {
23940 var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _step$value, id, item;
23941
23942 return regenerator.wrap(function value$(_context) {
23943 while (1) {
23944 switch (_context.prev = _context.next) {
23945 case 0:
23946 _iteratorNormalCompletion = true;
23947 _didIteratorError = false;
23948 _iteratorError = undefined;
23949 _context.prev = 3;
23950 _iterator = this._pairs[Symbol.iterator]();
23951
23952 case 5:
23953 if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
23954 _context.next = 12;
23955 break;
23956 }
23957
23958 _step$value = slicedToArray(_step.value, 2), id = _step$value[0], item = _step$value[1];
23959 _context.next = 9;
23960 return [id, item];
23961
23962 case 9:
23963 _iteratorNormalCompletion = true;
23964 _context.next = 5;
23965 break;
23966
23967 case 12:
23968 _context.next = 18;
23969 break;
23970
23971 case 14:
23972 _context.prev = 14;
23973 _context.t0 = _context["catch"](3);
23974 _didIteratorError = true;
23975 _iteratorError = _context.t0;
23976
23977 case 18:
23978 _context.prev = 18;
23979 _context.prev = 19;
23980
23981 if (!_iteratorNormalCompletion && _iterator.return != null) {
23982 _iterator.return();
23983 }
23984
23985 case 21:
23986 _context.prev = 21;
23987
23988 if (!_didIteratorError) {
23989 _context.next = 24;
23990 break;
23991 }
23992
23993 throw _iteratorError;
23994
23995 case 24:
23996 return _context.finish(21);
23997
23998 case 25:
23999 return _context.finish(18);
24000
24001 case 26:
24002 case "end":
24003 return _context.stop();
24004 }
24005 }
24006 }, value, this, [[3, 14, 18, 26], [19,, 21, 25]]);
24007 })
24008 /**
24009 * Return an iterable of key, value pairs for every entry in the stream.
24010 */
24011
24012 }, {
24013 key: "entries",
24014 value:
24015 /*#__PURE__*/
24016 regenerator.mark(function entries() {
24017 var _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _step2$value, id, item;
24018
24019 return regenerator.wrap(function entries$(_context2) {
24020 while (1) {
24021 switch (_context2.prev = _context2.next) {
24022 case 0:
24023 _iteratorNormalCompletion2 = true;
24024 _didIteratorError2 = false;
24025 _iteratorError2 = undefined;
24026 _context2.prev = 3;
24027 _iterator2 = this._pairs[Symbol.iterator]();
24028
24029 case 5:
24030 if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
24031 _context2.next = 12;
24032 break;
24033 }
24034
24035 _step2$value = slicedToArray(_step2.value, 2), id = _step2$value[0], item = _step2$value[1];
24036 _context2.next = 9;
24037 return [id, item];
24038
24039 case 9:
24040 _iteratorNormalCompletion2 = true;
24041 _context2.next = 5;
24042 break;
24043
24044 case 12:
24045 _context2.next = 18;
24046 break;
24047
24048 case 14:
24049 _context2.prev = 14;
24050 _context2.t0 = _context2["catch"](3);
24051 _didIteratorError2 = true;
24052 _iteratorError2 = _context2.t0;
24053
24054 case 18:
24055 _context2.prev = 18;
24056 _context2.prev = 19;
24057
24058 if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
24059 _iterator2.return();
24060 }
24061
24062 case 21:
24063 _context2.prev = 21;
24064
24065 if (!_didIteratorError2) {
24066 _context2.next = 24;
24067 break;
24068 }
24069
24070 throw _iteratorError2;
24071
24072 case 24:
24073 return _context2.finish(21);
24074
24075 case 25:
24076 return _context2.finish(18);
24077
24078 case 26:
24079 case "end":
24080 return _context2.stop();
24081 }
24082 }
24083 }, entries, this, [[3, 14, 18, 26], [19,, 21, 25]]);
24084 })
24085 /**
24086 * Return an iterable of keys in the stream.
24087 */
24088
24089 }, {
24090 key: "keys",
24091 value:
24092 /*#__PURE__*/
24093 regenerator.mark(function keys() {
24094 var _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, _step3$value, id;
24095
24096 return regenerator.wrap(function keys$(_context3) {
24097 while (1) {
24098 switch (_context3.prev = _context3.next) {
24099 case 0:
24100 _iteratorNormalCompletion3 = true;
24101 _didIteratorError3 = false;
24102 _iteratorError3 = undefined;
24103 _context3.prev = 3;
24104 _iterator3 = this._pairs[Symbol.iterator]();
24105
24106 case 5:
24107 if (_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done) {
24108 _context3.next = 12;
24109 break;
24110 }
24111
24112 _step3$value = slicedToArray(_step3.value, 1), id = _step3$value[0];
24113 _context3.next = 9;
24114 return id;
24115
24116 case 9:
24117 _iteratorNormalCompletion3 = true;
24118 _context3.next = 5;
24119 break;
24120
24121 case 12:
24122 _context3.next = 18;
24123 break;
24124
24125 case 14:
24126 _context3.prev = 14;
24127 _context3.t0 = _context3["catch"](3);
24128 _didIteratorError3 = true;
24129 _iteratorError3 = _context3.t0;
24130
24131 case 18:
24132 _context3.prev = 18;
24133 _context3.prev = 19;
24134
24135 if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
24136 _iterator3.return();
24137 }
24138
24139 case 21:
24140 _context3.prev = 21;
24141
24142 if (!_didIteratorError3) {
24143 _context3.next = 24;
24144 break;
24145 }
24146
24147 throw _iteratorError3;
24148
24149 case 24:
24150 return _context3.finish(21);
24151
24152 case 25:
24153 return _context3.finish(18);
24154
24155 case 26:
24156 case "end":
24157 return _context3.stop();
24158 }
24159 }
24160 }, keys, this, [[3, 14, 18, 26], [19,, 21, 25]]);
24161 })
24162 /**
24163 * Return an iterable of values in the stream.
24164 */
24165
24166 }, {
24167 key: "values",
24168 value:
24169 /*#__PURE__*/
24170 regenerator.mark(function values() {
24171 var _iteratorNormalCompletion4, _didIteratorError4, _iteratorError4, _iterator4, _step4, _step4$value, item;
24172
24173 return regenerator.wrap(function values$(_context4) {
24174 while (1) {
24175 switch (_context4.prev = _context4.next) {
24176 case 0:
24177 _iteratorNormalCompletion4 = true;
24178 _didIteratorError4 = false;
24179 _iteratorError4 = undefined;
24180 _context4.prev = 3;
24181 _iterator4 = this._pairs[Symbol.iterator]();
24182
24183 case 5:
24184 if (_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done) {
24185 _context4.next = 12;
24186 break;
24187 }
24188
24189 _step4$value = slicedToArray(_step4.value, 2), item = _step4$value[1];
24190 _context4.next = 9;
24191 return item;
24192
24193 case 9:
24194 _iteratorNormalCompletion4 = true;
24195 _context4.next = 5;
24196 break;
24197
24198 case 12:
24199 _context4.next = 18;
24200 break;
24201
24202 case 14:
24203 _context4.prev = 14;
24204 _context4.t0 = _context4["catch"](3);
24205 _didIteratorError4 = true;
24206 _iteratorError4 = _context4.t0;
24207
24208 case 18:
24209 _context4.prev = 18;
24210 _context4.prev = 19;
24211
24212 if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
24213 _iterator4.return();
24214 }
24215
24216 case 21:
24217 _context4.prev = 21;
24218
24219 if (!_didIteratorError4) {
24220 _context4.next = 24;
24221 break;
24222 }
24223
24224 throw _iteratorError4;
24225
24226 case 24:
24227 return _context4.finish(21);
24228
24229 case 25:
24230 return _context4.finish(18);
24231
24232 case 26:
24233 case "end":
24234 return _context4.stop();
24235 }
24236 }
24237 }, values, this, [[3, 14, 18, 26], [19,, 21, 25]]);
24238 })
24239 /**
24240 * Return an array containing all the ids in this stream.
24241 *
24242 * @remarks
24243 * The array may contain duplicities.
24244 *
24245 * @returns The array with all ids from this stream.
24246 */
24247
24248 }, {
24249 key: "toIdArray",
24250 value: function toIdArray() {
24251 return toConsumableArray(this._pairs).map(function (pair) {
24252 return pair[0];
24253 });
24254 }
24255 /**
24256 * Return an array containing all the items in this stream.
24257 *
24258 * @remarks
24259 * The array may contain duplicities.
24260 *
24261 * @returns The array with all items from this stream.
24262 */
24263
24264 }, {
24265 key: "toItemArray",
24266 value: function toItemArray() {
24267 return toConsumableArray(this._pairs).map(function (pair) {
24268 return pair[1];
24269 });
24270 }
24271 /**
24272 * Return an array containing all the entries in this stream.
24273 *
24274 * @remarks
24275 * The array may contain duplicities.
24276 *
24277 * @returns The array with all entries from this stream.
24278 */
24279
24280 }, {
24281 key: "toEntryArray",
24282 value: function toEntryArray() {
24283 return toConsumableArray(this._pairs);
24284 }
24285 /**
24286 * Return an object map containing all the items in this stream accessible by ids.
24287 *
24288 * @remarks
24289 * In case of duplicate ids (coerced to string so `7 == '7'`) the last encoutered appears in the returned object.
24290 *
24291 * @returns The object map of all id → item pairs from this stream.
24292 */
24293
24294 }, {
24295 key: "toObjectMap",
24296 value: function toObjectMap() {
24297 var map = Object.create(null);
24298 var _iteratorNormalCompletion5 = true;
24299 var _didIteratorError5 = false;
24300 var _iteratorError5 = undefined;
24301
24302 try {
24303 for (var _iterator5 = this._pairs[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
24304 var _step5$value = slicedToArray(_step5.value, 2),
24305 id = _step5$value[0],
24306 item = _step5$value[1];
24307
24308 map[id] = item;
24309 }
24310 } catch (err) {
24311 _didIteratorError5 = true;
24312 _iteratorError5 = err;
24313 } finally {
24314 try {
24315 if (!_iteratorNormalCompletion5 && _iterator5.return != null) {
24316 _iterator5.return();
24317 }
24318 } finally {
24319 if (_didIteratorError5) {
24320 throw _iteratorError5;
24321 }
24322 }
24323 }
24324
24325 return map;
24326 }
24327 /**
24328 * Return a map containing all the items in this stream accessible by ids.
24329 *
24330 * @returns The map of all id → item pairs from this stream.
24331 */
24332
24333 }, {
24334 key: "toMap",
24335 value: function toMap() {
24336 return new Map(this._pairs);
24337 }
24338 /**
24339 * Return a set containing all the (unique) ids in this stream.
24340 *
24341 * @returns The set of all ids from this stream.
24342 */
24343
24344 }, {
24345 key: "toIdSet",
24346 value: function toIdSet() {
24347 return new Set(this.toIdArray());
24348 }
24349 /**
24350 * Return a set containing all the (unique) items in this stream.
24351 *
24352 * @returns The set of all items from this stream.
24353 */
24354
24355 }, {
24356 key: "toItemSet",
24357 value: function toItemSet() {
24358 return new Set(this.toItemArray());
24359 }
24360 /**
24361 * Cache the items from this stream.
24362 *
24363 * @remarks
24364 * This method allows for items to be fetched immediatelly and used (possibly multiple times) later.
24365 * It can also be used to optimize performance as [[DataStream]] would otherwise reevaluate everything upon each iteration.
24366 *
24367 * ## Example
24368 * ```javascript
24369 * const ds = new DataSet([…])
24370 *
24371 * const cachedStream = ds.stream()
24372 * .filter(…)
24373 * .sort(…)
24374 * .map(…)
24375 * .cached(…) // Data are fetched, processed and cached here.
24376 *
24377 * ds.clear()
24378 * chachedStream // Still has all the items.
24379 * ```
24380 *
24381 * @returns A new [[DataStream]] with cached items (detached from the original [[DataSet]]).
24382 */
24383
24384 }, {
24385 key: "cache",
24386 value: function cache() {
24387 return new DataStream(toConsumableArray(this._pairs));
24388 }
24389 /**
24390 * Get the distinct values of given property.
24391 *
24392 * @param callback - The function that picks and possibly converts the property.
24393 *
24394 * @typeparam T - The type of the distinct value.
24395 *
24396 * @returns A set of all distinct properties.
24397 */
24398
24399 }, {
24400 key: "distinct",
24401 value: function distinct(callback) {
24402 var set = new Set();
24403 var _iteratorNormalCompletion6 = true;
24404 var _didIteratorError6 = false;
24405 var _iteratorError6 = undefined;
24406
24407 try {
24408 for (var _iterator6 = this._pairs[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
24409 var _step6$value = slicedToArray(_step6.value, 2),
24410 id = _step6$value[0],
24411 item = _step6$value[1];
24412
24413 set.add(callback(item, id));
24414 }
24415 } catch (err) {
24416 _didIteratorError6 = true;
24417 _iteratorError6 = err;
24418 } finally {
24419 try {
24420 if (!_iteratorNormalCompletion6 && _iterator6.return != null) {
24421 _iterator6.return();
24422 }
24423 } finally {
24424 if (_didIteratorError6) {
24425 throw _iteratorError6;
24426 }
24427 }
24428 }
24429
24430 return set;
24431 }
24432 /**
24433 * Filter the items of the stream.
24434 *
24435 * @param callback - The function that decides whether an item will be included.
24436 *
24437 * @returns A new data stream with the filtered items.
24438 */
24439
24440 }, {
24441 key: "filter",
24442 value: function filter(callback) {
24443 var pairs = this._pairs;
24444 return new DataStream(defineProperty$6({}, Symbol.iterator,
24445 /*#__PURE__*/
24446 regenerator.mark(function _callee() {
24447 var _iteratorNormalCompletion7, _didIteratorError7, _iteratorError7, _iterator7, _step7, _step7$value, id, item;
24448
24449 return regenerator.wrap(function _callee$(_context5) {
24450 while (1) {
24451 switch (_context5.prev = _context5.next) {
24452 case 0:
24453 _iteratorNormalCompletion7 = true;
24454 _didIteratorError7 = false;
24455 _iteratorError7 = undefined;
24456 _context5.prev = 3;
24457 _iterator7 = pairs[Symbol.iterator]();
24458
24459 case 5:
24460 if (_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done) {
24461 _context5.next = 13;
24462 break;
24463 }
24464
24465 _step7$value = slicedToArray(_step7.value, 2), id = _step7$value[0], item = _step7$value[1];
24466
24467 if (!callback(item, id)) {
24468 _context5.next = 10;
24469 break;
24470 }
24471
24472 _context5.next = 10;
24473 return [id, item];
24474
24475 case 10:
24476 _iteratorNormalCompletion7 = true;
24477 _context5.next = 5;
24478 break;
24479
24480 case 13:
24481 _context5.next = 19;
24482 break;
24483
24484 case 15:
24485 _context5.prev = 15;
24486 _context5.t0 = _context5["catch"](3);
24487 _didIteratorError7 = true;
24488 _iteratorError7 = _context5.t0;
24489
24490 case 19:
24491 _context5.prev = 19;
24492 _context5.prev = 20;
24493
24494 if (!_iteratorNormalCompletion7 && _iterator7.return != null) {
24495 _iterator7.return();
24496 }
24497
24498 case 22:
24499 _context5.prev = 22;
24500
24501 if (!_didIteratorError7) {
24502 _context5.next = 25;
24503 break;
24504 }
24505
24506 throw _iteratorError7;
24507
24508 case 25:
24509 return _context5.finish(22);
24510
24511 case 26:
24512 return _context5.finish(19);
24513
24514 case 27:
24515 case "end":
24516 return _context5.stop();
24517 }
24518 }
24519 }, _callee, null, [[3, 15, 19, 27], [20,, 22, 26]]);
24520 })));
24521 }
24522 /**
24523 * Execute a callback for each item of the stream.
24524 *
24525 * @param callback - The function that will be invoked for each item.
24526 */
24527
24528 }, {
24529 key: "forEach",
24530 value: function forEach(callback) {
24531 var _iteratorNormalCompletion8 = true;
24532 var _didIteratorError8 = false;
24533 var _iteratorError8 = undefined;
24534
24535 try {
24536 for (var _iterator8 = this._pairs[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
24537 var _step8$value = slicedToArray(_step8.value, 2),
24538 id = _step8$value[0],
24539 item = _step8$value[1];
24540
24541 callback(item, id);
24542 }
24543 } catch (err) {
24544 _didIteratorError8 = true;
24545 _iteratorError8 = err;
24546 } finally {
24547 try {
24548 if (!_iteratorNormalCompletion8 && _iterator8.return != null) {
24549 _iterator8.return();
24550 }
24551 } finally {
24552 if (_didIteratorError8) {
24553 throw _iteratorError8;
24554 }
24555 }
24556 }
24557 }
24558 /**
24559 * Map the items into a different type.
24560 *
24561 * @param callback - The function that does the conversion.
24562 *
24563 * @typeparam Mapped - The type of the item after mapping.
24564 *
24565 * @returns A new data stream with the mapped items.
24566 */
24567
24568 }, {
24569 key: "map",
24570 value: function map(callback) {
24571 var pairs = this._pairs;
24572 return new DataStream(defineProperty$6({}, Symbol.iterator,
24573 /*#__PURE__*/
24574 regenerator.mark(function _callee2() {
24575 var _iteratorNormalCompletion9, _didIteratorError9, _iteratorError9, _iterator9, _step9, _step9$value, id, item;
24576
24577 return regenerator.wrap(function _callee2$(_context6) {
24578 while (1) {
24579 switch (_context6.prev = _context6.next) {
24580 case 0:
24581 _iteratorNormalCompletion9 = true;
24582 _didIteratorError9 = false;
24583 _iteratorError9 = undefined;
24584 _context6.prev = 3;
24585 _iterator9 = pairs[Symbol.iterator]();
24586
24587 case 5:
24588 if (_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done) {
24589 _context6.next = 12;
24590 break;
24591 }
24592
24593 _step9$value = slicedToArray(_step9.value, 2), id = _step9$value[0], item = _step9$value[1];
24594 _context6.next = 9;
24595 return [id, callback(item, id)];
24596
24597 case 9:
24598 _iteratorNormalCompletion9 = true;
24599 _context6.next = 5;
24600 break;
24601
24602 case 12:
24603 _context6.next = 18;
24604 break;
24605
24606 case 14:
24607 _context6.prev = 14;
24608 _context6.t0 = _context6["catch"](3);
24609 _didIteratorError9 = true;
24610 _iteratorError9 = _context6.t0;
24611
24612 case 18:
24613 _context6.prev = 18;
24614 _context6.prev = 19;
24615
24616 if (!_iteratorNormalCompletion9 && _iterator9.return != null) {
24617 _iterator9.return();
24618 }
24619
24620 case 21:
24621 _context6.prev = 21;
24622
24623 if (!_didIteratorError9) {
24624 _context6.next = 24;
24625 break;
24626 }
24627
24628 throw _iteratorError9;
24629
24630 case 24:
24631 return _context6.finish(21);
24632
24633 case 25:
24634 return _context6.finish(18);
24635
24636 case 26:
24637 case "end":
24638 return _context6.stop();
24639 }
24640 }
24641 }, _callee2, null, [[3, 14, 18, 26], [19,, 21, 25]]);
24642 })));
24643 }
24644 /**
24645 * Get the item with the maximum value of given property.
24646 *
24647 * @param callback - The function that picks and possibly converts the property.
24648 *
24649 * @returns The item with the maximum if found otherwise null.
24650 */
24651
24652 }, {
24653 key: "max",
24654 value: function max(callback) {
24655 var iter = this._pairs[Symbol.iterator]();
24656
24657 var curr = iter.next();
24658
24659 if (curr.done) {
24660 return null;
24661 }
24662
24663 var maxItem = curr.value[1];
24664 var maxValue = callback(curr.value[1], curr.value[0]);
24665
24666 while (!(curr = iter.next()).done) {
24667 var _curr$value = slicedToArray(curr.value, 2),
24668 id = _curr$value[0],
24669 item = _curr$value[1];
24670
24671 var _value = callback(item, id);
24672
24673 if (_value > maxValue) {
24674 maxValue = _value;
24675 maxItem = item;
24676 }
24677 }
24678
24679 return maxItem;
24680 }
24681 /**
24682 * Get the item with the minimum value of given property.
24683 *
24684 * @param callback - The function that picks and possibly converts the property.
24685 *
24686 * @returns The item with the minimum if found otherwise null.
24687 */
24688
24689 }, {
24690 key: "min",
24691 value: function min(callback) {
24692 var iter = this._pairs[Symbol.iterator]();
24693
24694 var curr = iter.next();
24695
24696 if (curr.done) {
24697 return null;
24698 }
24699
24700 var minItem = curr.value[1];
24701 var minValue = callback(curr.value[1], curr.value[0]);
24702
24703 while (!(curr = iter.next()).done) {
24704 var _curr$value2 = slicedToArray(curr.value, 2),
24705 id = _curr$value2[0],
24706 item = _curr$value2[1];
24707
24708 var _value2 = callback(item, id);
24709
24710 if (_value2 < minValue) {
24711 minValue = _value2;
24712 minItem = item;
24713 }
24714 }
24715
24716 return minItem;
24717 }
24718 /**
24719 * Reduce the items into a single value.
24720 *
24721 * @param callback - The function that does the reduction.
24722 * @param accumulator - The initial value of the accumulator.
24723 *
24724 * @typeparam T - The type of the accumulated value.
24725 *
24726 * @returns The reduced value.
24727 */
24728
24729 }, {
24730 key: "reduce",
24731 value: function reduce(callback, accumulator) {
24732 var _iteratorNormalCompletion10 = true;
24733 var _didIteratorError10 = false;
24734 var _iteratorError10 = undefined;
24735
24736 try {
24737 for (var _iterator10 = this._pairs[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
24738 var _step10$value = slicedToArray(_step10.value, 2),
24739 id = _step10$value[0],
24740 item = _step10$value[1];
24741
24742 accumulator = callback(accumulator, item, id);
24743 }
24744 } catch (err) {
24745 _didIteratorError10 = true;
24746 _iteratorError10 = err;
24747 } finally {
24748 try {
24749 if (!_iteratorNormalCompletion10 && _iterator10.return != null) {
24750 _iterator10.return();
24751 }
24752 } finally {
24753 if (_didIteratorError10) {
24754 throw _iteratorError10;
24755 }
24756 }
24757 }
24758
24759 return accumulator;
24760 }
24761 /**
24762 * Sort the items.
24763 *
24764 * @param callback - Item comparator.
24765 *
24766 * @returns A new stream with sorted items.
24767 */
24768
24769 }, {
24770 key: "sort",
24771 value: function sort(callback) {
24772 var _this = this;
24773
24774 return new DataStream(defineProperty$6({}, Symbol.iterator, function () {
24775 return toConsumableArray(_this._pairs).sort(function (_ref3, _ref4) {
24776 var _ref5 = slicedToArray(_ref3, 2),
24777 idA = _ref5[0],
24778 itemA = _ref5[1];
24779
24780 var _ref6 = slicedToArray(_ref4, 2),
24781 idB = _ref6[0],
24782 itemB = _ref6[1];
24783
24784 return callback(itemA, itemB, idA, idB);
24785 })[Symbol.iterator]();
24786 }));
24787 }
24788 }]);
24789 return DataStream;
24790 }();
24791
24792 function ownKeys$3(object, enumerableOnly) {
24793 var keys = Object.keys(object);
24794
24795 if (Object.getOwnPropertySymbols) {
24796 keys.push.apply(keys, Object.getOwnPropertySymbols(object));
24797 }
24798
24799 if (enumerableOnly) keys = keys.filter(function (sym) {
24800 return Object.getOwnPropertyDescriptor(object, sym).enumerable;
24801 });
24802 return keys;
24803 }
24804
24805 function _objectSpread(target) {
24806 for (var i = 1; i < arguments.length; i++) {
24807 var source = arguments[i] != null ? arguments[i] : {};
24808
24809 if (i % 2) {
24810 ownKeys$3(source, true).forEach(function (key) {
24811 defineProperty$6(target, key, source[key]);
24812 });
24813 } else if (Object.getOwnPropertyDescriptors) {
24814 Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
24815 } else {
24816 ownKeys$3(source).forEach(function (key) {
24817 Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
24818 });
24819 }
24820 }
24821
24822 return target;
24823 }
24824 /**
24825 * # DataSet
24826 *
24827 * Vis.js comes with a flexible DataSet, which can be used to hold and manipulate unstructured data and listen for changes in the data. The DataSet is key/value based. Data items can be added, updated and removed from the DataSet, and one can subscribe to changes in the DataSet. The data in the DataSet can be filtered and ordered, and fields (like dates) can be converted to a specific type. Data can be normalized when appending it to the DataSet as well.
24828 *
24829 * ## Example
24830 *
24831 * The following example shows how to use a DataSet.
24832 *
24833 * ```javascript
24834 * // create a DataSet
24835 * var options = {};
24836 * var data = new vis.DataSet(options);
24837 *
24838 * // add items
24839 * // note that the data items can contain different properties and data formats
24840 * data.add([
24841 * {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
24842 * {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
24843 * {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
24844 * {id: 4, text: 'item 4'}
24845 * ]);
24846 *
24847 * // subscribe to any change in the DataSet
24848 * data.on('*', function (event, properties, senderId) {
24849 * console.log('event', event, properties);
24850 * });
24851 *
24852 * // update an existing item
24853 * data.update({id: 2, group: 1});
24854 *
24855 * // remove an item
24856 * data.remove(4);
24857 *
24858 * // get all ids
24859 * var ids = data.getIds();
24860 * console.log('ids', ids);
24861 *
24862 * // get a specific item
24863 * var item1 = data.get(1);
24864 * console.log('item1', item1);
24865 *
24866 * // retrieve a filtered subset of the data
24867 * var items = data.get({
24868 * filter: function (item) {
24869 * return item.group == 1;
24870 * }
24871 * });
24872 * console.log('filtered items', items);
24873 *
24874 * // retrieve formatted items
24875 * var items = data.get({
24876 * fields: ['id', 'date'],
24877 * type: {
24878 * date: 'ISODate'
24879 * }
24880 * });
24881 * console.log('formatted items', items);
24882 * ```
24883 *
24884 * @typeParam Item - Item type that may or may not have an id.
24885 * @typeParam IdProp - Name of the property that contains the id.
24886 */
24887
24888
24889 var DataSet =
24890 /*#__PURE__*/
24891 function (_DataSetPart) {
24892 inherits(DataSet, _DataSetPart);
24893 /**
24894 * Construct a new DataSet.
24895 *
24896 * @param data - Initial data or options.
24897 * @param options - Options (type error if data is also options).
24898 */
24899
24900 function DataSet(data, options) {
24901 var _this;
24902
24903 classCallCheck(this, DataSet);
24904 _this = possibleConstructorReturn(this, getPrototypeOf(DataSet).call(this)); // correctly read optional arguments
24905
24906 if (data && !Array.isArray(data)) {
24907 options = data;
24908 data = [];
24909 }
24910
24911 _this._options = options || {};
24912 _this._data = new Map(); // map with data indexed by id
24913
24914 _this.length = 0; // number of items in the DataSet
24915
24916 _this._idProp = _this._options.fieldId || "id"; // name of the field containing id
24917
24918 _this._type = {}; // internal field types (NOTE: this can differ from this._options.type)
24919 // all variants of a Date are internally stored as Date, so we can convert
24920 // from everything to everything (also from ISODate to Number for example)
24921
24922 if (_this._options.type) {
24923 var fields = Object.keys(_this._options.type);
24924
24925 for (var i = 0, len = fields.length; i < len; i++) {
24926 var field = fields[i];
24927 var value = _this._options.type[field];
24928
24929 if (value == "Date" || value == "ISODate" || value == "ASPDate") {
24930 _this._type[field] = "Date";
24931 } else {
24932 _this._type[field] = value;
24933 }
24934 }
24935 } // add initial data when provided
24936
24937
24938 if (data && data.length) {
24939 _this.add(data);
24940 }
24941
24942 _this.setOptions(options);
24943
24944 return _this;
24945 }
24946 /**
24947 * Set new options.
24948 *
24949 * @param options - The new options.
24950 */
24951
24952
24953 createClass(DataSet, [{
24954 key: "setOptions",
24955 value: function setOptions(options) {
24956 if (options && options.queue !== undefined) {
24957 if (options.queue === false) {
24958 // delete queue if loaded
24959 if (this._queue) {
24960 this._queue.destroy();
24961
24962 delete this._queue;
24963 }
24964 } else {
24965 // create queue and update its options
24966 if (!this._queue) {
24967 this._queue = Queue.extend(this, {
24968 replace: ["add", "update", "remove"]
24969 });
24970 }
24971
24972 if (options.queue && _typeof_1(options.queue) === "object") {
24973 this._queue.setOptions(options.queue);
24974 }
24975 }
24976 }
24977 }
24978 /**
24979 * Add a data item or an array with items.
24980 *
24981 * After the items are added to the DataSet, the DataSet will trigger an event `add`. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
24982 *
24983 * ## Example
24984 *
24985 * ```javascript
24986 * // create a DataSet
24987 * const data = new vis.DataSet()
24988 *
24989 * // add items
24990 * const ids = data.add([
24991 * { id: 1, text: 'item 1' },
24992 * { id: 2, text: 'item 2' },
24993 * { text: 'item without an id' }
24994 * ])
24995 *
24996 * console.log(ids) // [1, 2, '<UUIDv4>']
24997 * ```
24998 *
24999 * @param data - Items to be added (ids will be generated if missing).
25000 * @param senderId - Sender id.
25001 *
25002 * @returns addedIds - Array with the ids (generated if not present) of the added items.
25003 *
25004 * @throws When an item with the same id as any of the added items already exists.
25005 */
25006
25007 }, {
25008 key: "add",
25009 value: function add(data, senderId) {
25010 var _this2 = this;
25011
25012 var addedIds = [];
25013 var id;
25014
25015 if (Array.isArray(data)) {
25016 // Array
25017 var idsToAdd = data.map(function (d) {
25018 return d[_this2._idProp];
25019 });
25020
25021 if (idsToAdd.some(function (id) {
25022 return _this2._data.has(id);
25023 })) {
25024 throw new Error("A duplicate id was found in the parameter array.");
25025 }
25026
25027 for (var i = 0, len = data.length; i < len; i++) {
25028 id = this._addItem(data[i]);
25029 addedIds.push(id);
25030 }
25031 } else if (data && _typeof_1(data) === "object") {
25032 // Single item
25033 id = this._addItem(data);
25034 addedIds.push(id);
25035 } else {
25036 throw new Error("Unknown dataType");
25037 }
25038
25039 if (addedIds.length) {
25040 this._trigger("add", {
25041 items: addedIds
25042 }, senderId);
25043 }
25044
25045 return addedIds;
25046 }
25047 /**
25048 * Update existing items. When an item does not exist, it will be created.
25049 *
25050 * @remarks
25051 * The provided properties will be merged in the existing item. When an item does not exist, it will be created.
25052 *
25053 * After the items are updated, the DataSet will trigger an event `add` for the added items, and an event `update`. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
25054 *
25055 * ## Example
25056 *
25057 * ```javascript
25058 * // create a DataSet
25059 * const data = new vis.DataSet([
25060 * { id: 1, text: 'item 1' },
25061 * { id: 2, text: 'item 2' },
25062 * { id: 3, text: 'item 3' }
25063 * ])
25064 *
25065 * // update items
25066 * const ids = data.update([
25067 * { id: 2, text: 'item 2 (updated)' },
25068 * { id: 4, text: 'item 4 (new)' }
25069 * ])
25070 *
25071 * console.log(ids) // [2, 4]
25072 * ```
25073 *
25074 * ## Warning for TypeScript users
25075 * This method may introduce partial items into the data set. Use add or updateOnly instead for better type safety.
25076 *
25077 * @param data - Items to be updated (if the id is already present) or added (if the id is missing).
25078 * @param senderId - Sender id.
25079 *
25080 * @returns updatedIds - The ids of the added (these may be newly generated if there was no id in the item from the data) or updated items.
25081 *
25082 * @throws When the supplied data is neither an item nor an array of items.
25083 */
25084
25085 }, {
25086 key: "update",
25087 value: function update(data, senderId) {
25088 var _this3 = this;
25089
25090 var addedIds = [];
25091 var updatedIds = [];
25092 var oldData = [];
25093 var updatedData = [];
25094 var idProp = this._idProp;
25095
25096 var addOrUpdate = function addOrUpdate(item) {
25097 var origId = item[idProp];
25098
25099 if (origId != null && _this3._data.has(origId)) {
25100 var fullItem = item; // it has an id, therefore it is a fullitem
25101
25102 var oldItem = Object.assign({}, _this3._data.get(origId)); // update item
25103
25104 var id = _this3._updateItem(fullItem);
25105
25106 updatedIds.push(id);
25107 updatedData.push(fullItem);
25108 oldData.push(oldItem);
25109 } else {
25110 // add new item
25111 var _id = _this3._addItem(item);
25112
25113 addedIds.push(_id);
25114 }
25115 };
25116
25117 if (Array.isArray(data)) {
25118 // Array
25119 for (var i = 0, len = data.length; i < len; i++) {
25120 if (data[i] && _typeof_1(data[i]) === "object") {
25121 addOrUpdate(data[i]);
25122 } else {
25123 console.warn("Ignoring input item, which is not an object at index " + i);
25124 }
25125 }
25126 } else if (data && _typeof_1(data) === "object") {
25127 // Single item
25128 addOrUpdate(data);
25129 } else {
25130 throw new Error("Unknown dataType");
25131 }
25132
25133 if (addedIds.length) {
25134 this._trigger("add", {
25135 items: addedIds
25136 }, senderId);
25137 }
25138
25139 if (updatedIds.length) {
25140 var props = {
25141 items: updatedIds,
25142 oldData: oldData,
25143 data: updatedData
25144 }; // TODO: remove deprecated property 'data' some day
25145 //Object.defineProperty(props, 'data', {
25146 // 'get': (function() {
25147 // console.warn('Property data is deprecated. Use DataSet.get(ids) to retrieve the new data, use the oldData property on this object to get the old data');
25148 // return updatedData;
25149 // }).bind(this)
25150 //});
25151
25152 this._trigger("update", props, senderId);
25153 }
25154
25155 return addedIds.concat(updatedIds);
25156 }
25157 /**
25158 * Update existing items. When an item does not exist, an error will be thrown.
25159 *
25160 * @remarks
25161 * The provided properties will be deeply merged into the existing item.
25162 * When an item does not exist (id not present in the data set or absent), an error will be thrown and nothing will be changed.
25163 *
25164 * After the items are updated, the DataSet will trigger an event `update`.
25165 * When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
25166 *
25167 * ## Example
25168 *
25169 * ```javascript
25170 * // create a DataSet
25171 * const data = new vis.DataSet([
25172 * { id: 1, text: 'item 1' },
25173 * { id: 2, text: 'item 2' },
25174 * { id: 3, text: 'item 3' },
25175 * ])
25176 *
25177 * // update items
25178 * const ids = data.update([
25179 * { id: 2, text: 'item 2 (updated)' }, // works
25180 * // { id: 4, text: 'item 4 (new)' }, // would throw
25181 * // { text: 'item 4 (new)' }, // would also throw
25182 * ])
25183 *
25184 * console.log(ids) // [2]
25185 * ```
25186 *
25187 * @param data - Updates (the id and optionally other props) to the items in this data set.
25188 * @param senderId - Sender id.
25189 *
25190 * @returns updatedIds - The ids of the updated items.
25191 *
25192 * @throws When the supplied data is neither an item nor an array of items, when the ids are missing.
25193 */
25194
25195 }, {
25196 key: "updateOnly",
25197 value: function updateOnly(data, senderId) {
25198 var _this4 = this;
25199
25200 if (!Array.isArray(data)) {
25201 data = [data];
25202 }
25203
25204 var updateEventData = data.map(function (update) {
25205 var oldData = _this4._data.get(update[_this4._idProp]);
25206
25207 if (oldData == null) {
25208 throw new Error("Updating non-existent items is not allowed.");
25209 }
25210
25211 return {
25212 oldData: oldData,
25213 update: update
25214 };
25215 }).map(function (_ref) {
25216 var oldData = _ref.oldData,
25217 update = _ref.update;
25218 var id = oldData[_this4._idProp];
25219 var updatedData = deepExtend$1(deepExtend$1({}, oldData), update);
25220
25221 _this4._data.set(id, updatedData);
25222
25223 return {
25224 id: id,
25225 oldData: oldData,
25226 updatedData: updatedData
25227 };
25228 });
25229
25230 if (updateEventData.length) {
25231 var props = {
25232 items: updateEventData.map(function (value) {
25233 return value.id;
25234 }),
25235 oldData: updateEventData.map(function (value) {
25236 return value.oldData;
25237 }),
25238 data: updateEventData.map(function (value) {
25239 return value.updatedData;
25240 })
25241 }; // TODO: remove deprecated property 'data' some day
25242 //Object.defineProperty(props, 'data', {
25243 // 'get': (function() {
25244 // console.warn('Property data is deprecated. Use DataSet.get(ids) to retrieve the new data, use the oldData property on this object to get the old data');
25245 // return updatedData;
25246 // }).bind(this)
25247 //});
25248
25249 this._trigger("update", props, senderId);
25250
25251 return props.items;
25252 } else {
25253 return [];
25254 }
25255 }
25256 /** @inheritdoc */
25257
25258 }, {
25259 key: "get",
25260 value: function get(first, second) {
25261 // @TODO: Woudn't it be better to split this into multiple methods?
25262 // parse the arguments
25263 var id = undefined;
25264 var ids = undefined;
25265 var options = undefined;
25266
25267 if (isId(first)) {
25268 // get(id [, options])
25269 id = first;
25270 options = second;
25271 } else if (Array.isArray(first)) {
25272 // get(ids [, options])
25273 ids = first;
25274 options = second;
25275 } else {
25276 // get([, options])
25277 options = first;
25278 } // determine the return type
25279
25280
25281 var returnType = options && options.returnType === "Object" ? "Object" : "Array"; // @TODO: WTF is this? Or am I missing something?
25282 // var returnType
25283 // if (options && options.returnType) {
25284 // var allowedValues = ['Array', 'Object']
25285 // returnType =
25286 // allowedValues.indexOf(options.returnType) == -1
25287 // ? 'Array'
25288 // : options.returnType
25289 // } else {
25290 // returnType = 'Array'
25291 // }
25292 // build options
25293
25294 var type = options && options.type || this._options.type;
25295 var filter = options && options.filter;
25296 var items = [];
25297 var item = null;
25298 var itemIds = null;
25299 var itemId = null; // convert items
25300
25301 if (id != null) {
25302 // return a single item
25303 item = this._getItem(id, type);
25304
25305 if (item && filter && !filter(item)) {
25306 item = null;
25307 }
25308 } else if (ids != null) {
25309 // return a subset of items
25310 for (var i = 0, len = ids.length; i < len; i++) {
25311 item = this._getItem(ids[i], type);
25312
25313 if (item != null && (!filter || filter(item))) {
25314 items.push(item);
25315 }
25316 }
25317 } else {
25318 // return all items
25319 itemIds = toConsumableArray(this._data.keys());
25320
25321 for (var _i = 0, _len = itemIds.length; _i < _len; _i++) {
25322 itemId = itemIds[_i];
25323 item = this._getItem(itemId, type);
25324
25325 if (item != null && (!filter || filter(item))) {
25326 items.push(item);
25327 }
25328 }
25329 } // order the results
25330
25331
25332 if (options && options.order && id == undefined) {
25333 this._sort(items, options.order);
25334 } // filter fields of the items
25335
25336
25337 if (options && options.fields) {
25338 var fields = options.fields;
25339
25340 if (id != undefined && item != null) {
25341 item = this._filterFields(item, fields);
25342 } else {
25343 for (var _i2 = 0, _len2 = items.length; _i2 < _len2; _i2++) {
25344 items[_i2] = this._filterFields(items[_i2], fields);
25345 }
25346 }
25347 } // return the results
25348
25349
25350 if (returnType == "Object") {
25351 var result = {};
25352
25353 for (var _i3 = 0, _len3 = items.length; _i3 < _len3; _i3++) {
25354 var resultant = items[_i3]; // @TODO: Shoudn't this be this._fieldId?
25355 // result[resultant.id] = resultant
25356
25357 var _id2 = resultant[this._idProp];
25358 result[_id2] = resultant;
25359 }
25360
25361 return result;
25362 } else {
25363 if (id != null) {
25364 // a single item
25365 return item;
25366 } else {
25367 // just return our array
25368 return items;
25369 }
25370 }
25371 }
25372 /** @inheritdoc */
25373
25374 }, {
25375 key: "getIds",
25376 value: function getIds(options) {
25377 var data = this._data;
25378 var filter = options && options.filter;
25379 var order = options && options.order;
25380 var type = options && options.type || this._options.type;
25381 var itemIds = toConsumableArray(data.keys());
25382 var ids = [];
25383 var item;
25384 var items;
25385
25386 if (filter) {
25387 // get filtered items
25388 if (order) {
25389 // create ordered list
25390 items = [];
25391
25392 for (var i = 0, len = itemIds.length; i < len; i++) {
25393 var id = itemIds[i];
25394 item = this._getItem(id, type);
25395
25396 if (filter(item)) {
25397 items.push(item);
25398 }
25399 }
25400
25401 this._sort(items, order);
25402
25403 for (var _i4 = 0, _len4 = items.length; _i4 < _len4; _i4++) {
25404 ids.push(items[_i4][this._idProp]);
25405 }
25406 } else {
25407 // create unordered list
25408 for (var _i5 = 0, _len5 = itemIds.length; _i5 < _len5; _i5++) {
25409 var _id3 = itemIds[_i5];
25410 item = this._getItem(_id3, type);
25411
25412 if (filter(item)) {
25413 ids.push(item[this._idProp]);
25414 }
25415 }
25416 }
25417 } else {
25418 // get all items
25419 if (order) {
25420 // create an ordered list
25421 items = [];
25422
25423 for (var _i6 = 0, _len6 = itemIds.length; _i6 < _len6; _i6++) {
25424 var _id4 = itemIds[_i6];
25425 items.push(data.get(_id4));
25426 }
25427
25428 this._sort(items, order);
25429
25430 for (var _i7 = 0, _len7 = items.length; _i7 < _len7; _i7++) {
25431 ids.push(items[_i7][this._idProp]);
25432 }
25433 } else {
25434 // create unordered list
25435 for (var _i8 = 0, _len8 = itemIds.length; _i8 < _len8; _i8++) {
25436 var _id5 = itemIds[_i8];
25437 item = data.get(_id5);
25438 ids.push(item[this._idProp]);
25439 }
25440 }
25441 }
25442
25443 return ids;
25444 }
25445 /** @inheritdoc */
25446
25447 }, {
25448 key: "getDataSet",
25449 value: function getDataSet() {
25450 return this;
25451 }
25452 /** @inheritdoc */
25453
25454 }, {
25455 key: "forEach",
25456 value: function forEach(callback, options) {
25457 var filter = options && options.filter;
25458 var type = options && options.type || this._options.type;
25459 var data = this._data;
25460 var itemIds = toConsumableArray(data.keys());
25461
25462 if (options && options.order) {
25463 // execute forEach on ordered list
25464 var items = this.get(options);
25465
25466 for (var i = 0, len = items.length; i < len; i++) {
25467 var item = items[i];
25468 var id = item[this._idProp];
25469 callback(item, id);
25470 }
25471 } else {
25472 // unordered
25473 for (var _i9 = 0, _len9 = itemIds.length; _i9 < _len9; _i9++) {
25474 var _id6 = itemIds[_i9];
25475
25476 var _item = this._getItem(_id6, type);
25477
25478 if (!filter || filter(_item)) {
25479 callback(_item, _id6);
25480 }
25481 }
25482 }
25483 }
25484 /** @inheritdoc */
25485
25486 }, {
25487 key: "map",
25488 value: function map(callback, options) {
25489 var filter = options && options.filter;
25490 var type = options && options.type || this._options.type;
25491 var mappedItems = [];
25492 var data = this._data;
25493 var itemIds = toConsumableArray(data.keys()); // convert and filter items
25494
25495 for (var i = 0, len = itemIds.length; i < len; i++) {
25496 var id = itemIds[i];
25497
25498 var item = this._getItem(id, type);
25499
25500 if (!filter || filter(item)) {
25501 mappedItems.push(callback(item, id));
25502 }
25503 } // order items
25504
25505
25506 if (options && options.order) {
25507 this._sort(mappedItems, options.order);
25508 }
25509
25510 return mappedItems;
25511 }
25512 /**
25513 * Filter the fields of an item.
25514 *
25515 * @param item - The item whose fields should be filtered.
25516 * @param fields - The names of the fields that will be kept.
25517 *
25518 * @typeParam K - Field name type.
25519 *
25520 * @returns The item without any additional fields.
25521 */
25522
25523 }, {
25524 key: "_filterFields",
25525 value: function _filterFields(item, fields) {
25526 if (!item) {
25527 // item is null
25528 return item;
25529 }
25530
25531 return (Array.isArray(fields) ? // Use the supplied array
25532 fields : // Use the keys of the supplied object
25533 Object.keys(fields)).reduce(function (filteredItem, field) {
25534 filteredItem[field] = item[field];
25535 return filteredItem;
25536 }, {});
25537 }
25538 /**
25539 * Sort the provided array with items.
25540 *
25541 * @param items - Items to be sorted in place.
25542 * @param order - A field name or custom sort function.
25543 *
25544 * @typeParam T - The type of the items in the items array.
25545 */
25546
25547 }, {
25548 key: "_sort",
25549 value: function _sort(items, order) {
25550 if (typeof order === "string") {
25551 // order by provided field name
25552 var name = order; // field name
25553
25554 items.sort(function (a, b) {
25555 // @TODO: How to treat missing properties?
25556 var av = a[name];
25557 var bv = b[name];
25558 return av > bv ? 1 : av < bv ? -1 : 0;
25559 });
25560 } else if (typeof order === "function") {
25561 // order by sort function
25562 items.sort(order);
25563 } else {
25564 // TODO: extend order by an Object {field:string, direction:string}
25565 // where direction can be 'asc' or 'desc'
25566 throw new TypeError("Order must be a function or a string");
25567 }
25568 }
25569 /**
25570 * Remove an item or multiple items by “reference” (only the id is used) or by id.
25571 *
25572 * The method ignores removal of non-existing items, and returns an array containing the ids of the items which are actually removed from the DataSet.
25573 *
25574 * After the items are removed, the DataSet will trigger an event `remove` for the removed items. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
25575 *
25576 * ## Example
25577 * ```javascript
25578 * // create a DataSet
25579 * const data = new vis.DataSet([
25580 * { id: 1, text: 'item 1' },
25581 * { id: 2, text: 'item 2' },
25582 * { id: 3, text: 'item 3' }
25583 * ])
25584 *
25585 * // remove items
25586 * const ids = data.remove([2, { id: 3 }, 4])
25587 *
25588 * console.log(ids) // [2, 3]
25589 * ```
25590 *
25591 * @param id - One or more items or ids of items to be removed.
25592 * @param senderId - Sender id.
25593 *
25594 * @returns The ids of the removed items.
25595 */
25596
25597 }, {
25598 key: "remove",
25599 value: function remove(id, senderId) {
25600 var removedIds = [];
25601 var removedItems = []; // force everything to be an array for simplicity
25602
25603 var ids = Array.isArray(id) ? id : [id];
25604
25605 for (var i = 0, len = ids.length; i < len; i++) {
25606 var item = this._remove(ids[i]);
25607
25608 if (item) {
25609 var itemId = item[this._idProp];
25610
25611 if (itemId != null) {
25612 removedIds.push(itemId);
25613 removedItems.push(item);
25614 }
25615 }
25616 }
25617
25618 if (removedIds.length) {
25619 this._trigger("remove", {
25620 items: removedIds,
25621 oldData: removedItems
25622 }, senderId);
25623 }
25624
25625 return removedIds;
25626 }
25627 /**
25628 * Remove an item by its id or reference.
25629 *
25630 * @param id - Id of an item or the item itself.
25631 *
25632 * @returns The removed item if removed, null otherwise.
25633 */
25634
25635 }, {
25636 key: "_remove",
25637 value: function _remove(id) {
25638 // @TODO: It origianlly returned the item although the docs say id.
25639 // The code expects the item, so probably an error in the docs.
25640 var ident; // confirm the id to use based on the args type
25641
25642 if (isId(id)) {
25643 ident = id;
25644 } else if (id && _typeof_1(id) === "object") {
25645 ident = id[this._idProp]; // look for the identifier field using ._idProp
25646 } // do the removing if the item is found
25647
25648
25649 if (ident != null && this._data.has(ident)) {
25650 var item = this._data.get(ident) || null;
25651
25652 this._data.delete(ident);
25653
25654 --this.length;
25655 return item;
25656 }
25657
25658 return null;
25659 }
25660 /**
25661 * Clear the entire data set.
25662 *
25663 * After the items are removed, the [[DataSet]] will trigger an event `remove` for all removed items. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
25664 *
25665 * @param senderId - Sender id.
25666 *
25667 * @returns removedIds - The ids of all removed items.
25668 */
25669
25670 }, {
25671 key: "clear",
25672 value: function clear(senderId) {
25673 var ids = toConsumableArray(this._data.keys());
25674 var items = [];
25675
25676 for (var i = 0, len = ids.length; i < len; i++) {
25677 items.push(this._data.get(ids[i]));
25678 }
25679
25680 this._data.clear();
25681
25682 this.length = 0;
25683
25684 this._trigger("remove", {
25685 items: ids,
25686 oldData: items
25687 }, senderId);
25688
25689 return ids;
25690 }
25691 /**
25692 * Find the item with maximum value of a specified field.
25693 *
25694 * @param field - Name of the property that should be searched for max value.
25695 *
25696 * @returns Item containing max value, or null if no items.
25697 */
25698
25699 }, {
25700 key: "max",
25701 value: function max(field) {
25702 var max = null;
25703 var maxField = null;
25704 var _iteratorNormalCompletion = true;
25705 var _didIteratorError = false;
25706 var _iteratorError = undefined;
25707
25708 try {
25709 for (var _iterator = this._data.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
25710 var item = _step.value;
25711 var itemField = item[field];
25712
25713 if (typeof itemField === "number" && (maxField == null || itemField > maxField)) {
25714 max = item;
25715 maxField = itemField;
25716 }
25717 }
25718 } catch (err) {
25719 _didIteratorError = true;
25720 _iteratorError = err;
25721 } finally {
25722 try {
25723 if (!_iteratorNormalCompletion && _iterator.return != null) {
25724 _iterator.return();
25725 }
25726 } finally {
25727 if (_didIteratorError) {
25728 throw _iteratorError;
25729 }
25730 }
25731 }
25732
25733 return max || null;
25734 }
25735 /**
25736 * Find the item with minimum value of a specified field.
25737 *
25738 * @param field - Name of the property that should be searched for min value.
25739 *
25740 * @returns Item containing min value, or null if no items.
25741 */
25742
25743 }, {
25744 key: "min",
25745 value: function min(field) {
25746 var min = null;
25747 var minField = null;
25748 var _iteratorNormalCompletion2 = true;
25749 var _didIteratorError2 = false;
25750 var _iteratorError2 = undefined;
25751
25752 try {
25753 for (var _iterator2 = this._data.values()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
25754 var item = _step2.value;
25755 var itemField = item[field];
25756
25757 if (typeof itemField === "number" && (minField == null || itemField < minField)) {
25758 min = item;
25759 minField = itemField;
25760 }
25761 }
25762 } catch (err) {
25763 _didIteratorError2 = true;
25764 _iteratorError2 = err;
25765 } finally {
25766 try {
25767 if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
25768 _iterator2.return();
25769 }
25770 } finally {
25771 if (_didIteratorError2) {
25772 throw _iteratorError2;
25773 }
25774 }
25775 }
25776
25777 return min || null;
25778 }
25779 /**
25780 * Find all distinct values of a specified field
25781 *
25782 * @param prop - The property name whose distinct values should be returned.
25783 *
25784 * @returns Unordered array containing all distinct values. Items without specified property are ignored.
25785 */
25786
25787 }, {
25788 key: "distinct",
25789 value: function distinct(prop) {
25790 var data = this._data;
25791 var itemIds = toConsumableArray(data.keys());
25792 var values = [];
25793 var fieldType = this._options.type && this._options.type[prop] || null;
25794 var count = 0;
25795
25796 for (var i = 0, len = itemIds.length; i < len; i++) {
25797 var id = itemIds[i];
25798 var item = data.get(id);
25799 var value = item[prop];
25800 var exists = false;
25801
25802 for (var j = 0; j < count; j++) {
25803 if (values[j] == value) {
25804 exists = true;
25805 break;
25806 }
25807 }
25808
25809 if (!exists && value !== undefined) {
25810 values[count] = value;
25811 count++;
25812 }
25813 }
25814
25815 if (fieldType) {
25816 for (var _i10 = 0, _len10 = values.length; _i10 < _len10; _i10++) {
25817 values[_i10] = convert$1(values[_i10], fieldType);
25818 }
25819 }
25820
25821 return values;
25822 }
25823 /**
25824 * Add a single item. Will fail when an item with the same id already exists.
25825 *
25826 * @param item - A new item to be added.
25827 *
25828 * @returns Added item's id. An id is generated when it is not present in the item.
25829 */
25830
25831 }, {
25832 key: "_addItem",
25833 value: function _addItem(item) {
25834 var id = item[this._idProp];
25835
25836 if (id != null) {
25837 // check whether this id is already taken
25838 if (this._data.has(id)) {
25839 // item already exists
25840 throw new Error("Cannot add item: item with id " + id + " already exists");
25841 }
25842 } else {
25843 // generate an id
25844 id = uuid4$1();
25845 item[this._idProp] = id;
25846 }
25847
25848 var d = {};
25849 var fields = Object.keys(item);
25850
25851 for (var i = 0, len = fields.length; i < len; i++) {
25852 var field = fields[i];
25853 var fieldType = this._type[field]; // type may be undefined
25854
25855 d[field] = convert$1(item[field], fieldType);
25856 }
25857
25858 this._data.set(id, d);
25859
25860 ++this.length;
25861 return id;
25862 }
25863 /**
25864 * Get an item. Fields can be converted to a specific type
25865 *
25866 * @param id - Id of the requested item.
25867 * @param types - Property name to type name object map of type converstions.
25868 *
25869 * @returns The item, optionally after type conversion.
25870 */
25871
25872 }, {
25873 key: "_getItem",
25874 value: function _getItem(id, types) {
25875 // @TODO: I have no idea how to type this.
25876 // get the item from the dataset
25877 var raw = this._data.get(id);
25878
25879 if (!raw) {
25880 return null;
25881 } // convert the items field types
25882
25883
25884 var converted;
25885 var fields = Object.keys(raw);
25886
25887 if (types) {
25888 converted = {};
25889
25890 for (var i = 0, len = fields.length; i < len; i++) {
25891 var field = fields[i];
25892 var value = raw[field];
25893 converted[field] = convert$1(value, types[field]);
25894 }
25895 } else {
25896 // no field types specified, no converting needed
25897 converted = _objectSpread({}, raw);
25898 }
25899
25900 if (converted[this._idProp] == null) {
25901 converted[this._idProp] = raw.id;
25902 }
25903
25904 return converted;
25905 }
25906 /**
25907 * Update a single item: merge with existing item.
25908 * Will fail when the item has no id, or when there does not exist an item with the same id.
25909 *
25910 * @param item - The new item
25911 *
25912 * @returns The id of the updated item.
25913 */
25914
25915 }, {
25916 key: "_updateItem",
25917 value: function _updateItem(item) {
25918 var id = item[this._idProp];
25919
25920 if (id == null) {
25921 throw new Error("Cannot update item: item has no id (item: " + JSON.stringify(item) + ")");
25922 }
25923
25924 var d = this._data.get(id);
25925
25926 if (!d) {
25927 // item doesn't exist
25928 throw new Error("Cannot update item: no item with id " + id + " found");
25929 } // merge with current item
25930
25931
25932 var fields = Object.keys(item);
25933
25934 for (var i = 0, len = fields.length; i < len; i++) {
25935 var field = fields[i];
25936 var fieldType = this._type[field]; // type may be undefined
25937
25938 d[field] = convert$1(item[field], fieldType);
25939 }
25940
25941 return id;
25942 }
25943 /** @inheritdoc */
25944
25945 }, {
25946 key: "stream",
25947 value: function stream(ids) {
25948 if (ids) {
25949 var data = this._data;
25950 return new DataStream(defineProperty$6({}, Symbol.iterator,
25951 /*#__PURE__*/
25952 regenerator.mark(function _callee() {
25953 var _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, id, item;
25954
25955 return regenerator.wrap(function _callee$(_context) {
25956 while (1) {
25957 switch (_context.prev = _context.next) {
25958 case 0:
25959 _iteratorNormalCompletion3 = true;
25960 _didIteratorError3 = false;
25961 _iteratorError3 = undefined;
25962 _context.prev = 3;
25963 _iterator3 = ids[Symbol.iterator]();
25964
25965 case 5:
25966 if (_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done) {
25967 _context.next = 14;
25968 break;
25969 }
25970
25971 id = _step3.value;
25972 item = data.get(id);
25973
25974 if (!(item != null)) {
25975 _context.next = 11;
25976 break;
25977 }
25978
25979 _context.next = 11;
25980 return [id, item];
25981
25982 case 11:
25983 _iteratorNormalCompletion3 = true;
25984 _context.next = 5;
25985 break;
25986
25987 case 14:
25988 _context.next = 20;
25989 break;
25990
25991 case 16:
25992 _context.prev = 16;
25993 _context.t0 = _context["catch"](3);
25994 _didIteratorError3 = true;
25995 _iteratorError3 = _context.t0;
25996
25997 case 20:
25998 _context.prev = 20;
25999 _context.prev = 21;
26000
26001 if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
26002 _iterator3.return();
26003 }
26004
26005 case 23:
26006 _context.prev = 23;
26007
26008 if (!_didIteratorError3) {
26009 _context.next = 26;
26010 break;
26011 }
26012
26013 throw _iteratorError3;
26014
26015 case 26:
26016 return _context.finish(23);
26017
26018 case 27:
26019 return _context.finish(20);
26020
26021 case 28:
26022 case "end":
26023 return _context.stop();
26024 }
26025 }
26026 }, _callee, null, [[3, 16, 20, 28], [21,, 23, 27]]);
26027 })));
26028 } else {
26029 return new DataStream(defineProperty$6({}, Symbol.iterator, this._data.entries.bind(this._data)));
26030 }
26031 }
26032 }]);
26033 return DataSet;
26034 }(DataSetPart);
26035 /**
26036 * DataView
26037 *
26038 * A DataView offers a filtered and/or formatted view on a DataSet. One can subscribe to changes in a DataView, and easily get filtered or formatted data without having to specify filters and field types all the time.
26039 *
26040 * ## Example
26041 * ```javascript
26042 * // create a DataSet
26043 * var data = new vis.DataSet();
26044 * data.add([
26045 * {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
26046 * {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
26047 * {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
26048 * {id: 4, text: 'item 4'}
26049 * ]);
26050 *
26051 * // create a DataView
26052 * // the view will only contain items having a property group with value 1,
26053 * // and will only output fields id, text, and date.
26054 * var view = new vis.DataView(data, {
26055 * filter: function (item) {
26056 * return (item.group == 1);
26057 * },
26058 * fields: ['id', 'text', 'date']
26059 * });
26060 *
26061 * // subscribe to any change in the DataView
26062 * view.on('*', function (event, properties, senderId) {
26063 * console.log('event', event, properties);
26064 * });
26065 *
26066 * // update an item in the data set
26067 * data.update({id: 2, group: 1});
26068 *
26069 * // get all ids in the view
26070 * var ids = view.getIds();
26071 * console.log('ids', ids); // will output [1, 2]
26072 *
26073 * // get all items in the view
26074 * var items = view.get();
26075 * ```
26076 *
26077 * @typeParam Item - Item type that may or may not have an id.
26078 * @typeParam IdProp - Name of the property that contains the id.
26079 */
26080
26081
26082 var DataView$2 =
26083 /*#__PURE__*/
26084 function (_DataSetPart) {
26085 inherits(DataView, _DataSetPart);
26086 /**
26087 * Create a DataView.
26088 *
26089 * @param data - The instance containing data (directly or indirectly).
26090 * @param options - Options to configure this data view.
26091 */
26092
26093 function DataView(data, options) {
26094 var _this;
26095
26096 classCallCheck(this, DataView);
26097 _this = possibleConstructorReturn(this, getPrototypeOf(DataView).call(this));
26098 /** @inheritdoc */
26099
26100 _this.length = 0;
26101 _this._ids = new Set(); // ids of the items currently in memory (just contains a boolean true)
26102
26103 _this._options = options || {};
26104 _this._listener = _this._onEvent.bind(assertThisInitialized(_this));
26105
26106 _this.setData(data);
26107
26108 return _this;
26109 } // TODO: implement a function .config() to dynamically update things like configured filter
26110 // and trigger changes accordingly
26111
26112 /**
26113 * Set a data source for the view.
26114 *
26115 * @param data - The instance containing data (directly or indirectly).
26116 */
26117
26118
26119 createClass(DataView, [{
26120 key: "setData",
26121 value: function setData(data) {
26122 if (this._data) {
26123 // unsubscribe from current dataset
26124 if (this._data.off) {
26125 this._data.off("*", this._listener);
26126 } // trigger a remove of all items in memory
26127
26128
26129 var ids = this._data.getIds({
26130 filter: this._options.filter
26131 });
26132
26133 var items = this._data.get(ids);
26134
26135 this._ids.clear();
26136
26137 this.length = 0;
26138
26139 this._trigger("remove", {
26140 items: ids,
26141 oldData: items
26142 });
26143 }
26144
26145 if (data != null) {
26146 this._data = data; // trigger an add of all added items
26147
26148 var _ids = this._data.getIds({
26149 filter: this._options.filter
26150 });
26151
26152 for (var i = 0, len = _ids.length; i < len; i++) {
26153 var id = _ids[i];
26154
26155 this._ids.add(id);
26156 }
26157
26158 this.length = _ids.length;
26159
26160 this._trigger("add", {
26161 items: _ids
26162 });
26163 } else {
26164 this._data = new DataSet();
26165 } // subscribe to new dataset
26166
26167
26168 if (this._data.on) {
26169 this._data.on("*", this._listener);
26170 }
26171 }
26172 /**
26173 * Refresh the DataView.
26174 * Useful when the DataView has a filter function containing a variable parameter.
26175 */
26176
26177 }, {
26178 key: "refresh",
26179 value: function refresh() {
26180 var ids = this._data.getIds({
26181 filter: this._options.filter
26182 });
26183
26184 var oldIds = toConsumableArray(this._ids);
26185 var newIds = {};
26186 var addedIds = [];
26187 var removedIds = [];
26188 var removedItems = []; // check for additions
26189
26190 for (var i = 0, len = ids.length; i < len; i++) {
26191 var id = ids[i];
26192 newIds[id] = true;
26193
26194 if (!this._ids.has(id)) {
26195 addedIds.push(id);
26196
26197 this._ids.add(id);
26198 }
26199 } // check for removals
26200
26201
26202 for (var _i = 0, _len = oldIds.length; _i < _len; _i++) {
26203 var _id = oldIds[_i];
26204
26205 var item = this._data.get(_id);
26206
26207 if (item == null) {
26208 // @TODO: Investigate.
26209 // Doesn't happen during tests or examples.
26210 // Is it really impossible or could it eventually happen?
26211 // How to handle it if it does? The types guarantee non-nullable items.
26212 console.error("If you see this, report it please.");
26213 } else if (!newIds[_id]) {
26214 removedIds.push(_id);
26215 removedItems.push(item);
26216
26217 this._ids.delete(_id);
26218 }
26219 }
26220
26221 this.length += addedIds.length - removedIds.length; // trigger events
26222
26223 if (addedIds.length) {
26224 this._trigger("add", {
26225 items: addedIds
26226 });
26227 }
26228
26229 if (removedIds.length) {
26230 this._trigger("remove", {
26231 items: removedIds,
26232 oldData: removedItems
26233 });
26234 }
26235 }
26236 /** @inheritdoc */
26237
26238 }, {
26239 key: "get",
26240 value: function get(first, second) {
26241 if (this._data == null) {
26242 return null;
26243 } // parse the arguments
26244
26245
26246 var ids = null;
26247 var options;
26248
26249 if (isId(first) || Array.isArray(first)) {
26250 ids = first;
26251 options = second;
26252 } else {
26253 options = first;
26254 } // extend the options with the default options and provided options
26255
26256
26257 var viewOptions = Object.assign({}, this._options, options); // create a combined filter method when needed
26258
26259 var thisFilter = this._options.filter;
26260 var optionsFilter = options && options.filter;
26261
26262 if (thisFilter && optionsFilter) {
26263 viewOptions.filter = function (item) {
26264 return thisFilter(item) && optionsFilter(item);
26265 };
26266 }
26267
26268 if (ids == null) {
26269 return this._data.get(viewOptions);
26270 } else {
26271 return this._data.get(ids, viewOptions);
26272 }
26273 }
26274 /** @inheritdoc */
26275
26276 }, {
26277 key: "getIds",
26278 value: function getIds(options) {
26279 if (this._data.length) {
26280 var defaultFilter = this._options.filter;
26281 var optionsFilter = options != null ? options.filter : null;
26282 var filter;
26283
26284 if (optionsFilter) {
26285 if (defaultFilter) {
26286 filter = function filter(item) {
26287 return defaultFilter(item) && optionsFilter(item);
26288 };
26289 } else {
26290 filter = optionsFilter;
26291 }
26292 } else {
26293 filter = defaultFilter;
26294 }
26295
26296 return this._data.getIds({
26297 filter: filter,
26298 order: options && options.order
26299 });
26300 } else {
26301 return [];
26302 }
26303 }
26304 /** @inheritdoc */
26305
26306 }, {
26307 key: "forEach",
26308 value: function forEach(callback, options) {
26309 if (this._data) {
26310 var defaultFilter = this._options.filter;
26311 var optionsFilter = options && options.filter;
26312 var filter;
26313
26314 if (optionsFilter) {
26315 if (defaultFilter) {
26316 filter = function filter(item) {
26317 return defaultFilter(item) && optionsFilter(item);
26318 };
26319 } else {
26320 filter = optionsFilter;
26321 }
26322 } else {
26323 filter = defaultFilter;
26324 }
26325
26326 this._data.forEach(callback, {
26327 filter: filter,
26328 order: options && options.order
26329 });
26330 }
26331 }
26332 /** @inheritdoc */
26333
26334 }, {
26335 key: "map",
26336 value: function map(callback, options) {
26337 if (this._data) {
26338 var defaultFilter = this._options.filter;
26339 var optionsFilter = options && options.filter;
26340 var filter;
26341
26342 if (optionsFilter) {
26343 if (defaultFilter) {
26344 filter = function filter(item) {
26345 return defaultFilter(item) && optionsFilter(item);
26346 };
26347 } else {
26348 filter = optionsFilter;
26349 }
26350 } else {
26351 filter = defaultFilter;
26352 }
26353
26354 return this._data.map(callback, {
26355 filter: filter,
26356 order: options && options.order
26357 });
26358 } else {
26359 return [];
26360 }
26361 }
26362 /** @inheritdoc */
26363
26364 }, {
26365 key: "getDataSet",
26366 value: function getDataSet() {
26367 return this._data.getDataSet();
26368 }
26369 /** @inheritdoc */
26370
26371 }, {
26372 key: "stream",
26373 value: function stream(ids) {
26374 return this._data.stream(ids || defineProperty$6({}, Symbol.iterator, this._ids.keys.bind(this._ids)));
26375 }
26376 /**
26377 * Event listener. Will propagate all events from the connected data set to the subscribers of the DataView, but will filter the items and only trigger when there are changes in the filtered data set.
26378 *
26379 * @param event - The name of the event.
26380 * @param params - Parameters of the event.
26381 * @param senderId - Id supplied by the sender.
26382 */
26383
26384 }, {
26385 key: "_onEvent",
26386 value: function _onEvent(event, params, senderId) {
26387 if (!params || !params.items || !this._data) {
26388 return;
26389 }
26390
26391 var ids = params.items;
26392 var addedIds = [];
26393 var updatedIds = [];
26394 var removedIds = [];
26395 var oldItems = [];
26396 var updatedItems = [];
26397 var removedItems = [];
26398
26399 switch (event) {
26400 case "add":
26401 // filter the ids of the added items
26402 for (var i = 0, len = ids.length; i < len; i++) {
26403 var id = ids[i];
26404 var item = this.get(id);
26405
26406 if (item) {
26407 this._ids.add(id);
26408
26409 addedIds.push(id);
26410 }
26411 }
26412
26413 break;
26414
26415 case "update":
26416 // determine the event from the views viewpoint: an updated
26417 // item can be added, updated, or removed from this view.
26418 for (var _i2 = 0, _len2 = ids.length; _i2 < _len2; _i2++) {
26419 var _id2 = ids[_i2];
26420
26421 var _item = this.get(_id2);
26422
26423 if (_item) {
26424 if (this._ids.has(_id2)) {
26425 updatedIds.push(_id2);
26426 updatedItems.push(params.data[_i2]);
26427 oldItems.push(params.oldData[_i2]);
26428 } else {
26429 this._ids.add(_id2);
26430
26431 addedIds.push(_id2);
26432 }
26433 } else {
26434 if (this._ids.has(_id2)) {
26435 this._ids.delete(_id2);
26436
26437 removedIds.push(_id2);
26438 removedItems.push(params.oldData[_i2]);
26439 }
26440 }
26441 }
26442
26443 break;
26444
26445 case "remove":
26446 // filter the ids of the removed items
26447 for (var _i3 = 0, _len3 = ids.length; _i3 < _len3; _i3++) {
26448 var _id3 = ids[_i3];
26449
26450 if (this._ids.has(_id3)) {
26451 this._ids.delete(_id3);
26452
26453 removedIds.push(_id3);
26454 removedItems.push(params.oldData[_i3]);
26455 }
26456 }
26457
26458 break;
26459 }
26460
26461 this.length += addedIds.length - removedIds.length;
26462
26463 if (addedIds.length) {
26464 this._trigger("add", {
26465 items: addedIds
26466 }, senderId);
26467 }
26468
26469 if (updatedIds.length) {
26470 this._trigger("update", {
26471 items: updatedIds,
26472 oldData: oldItems,
26473 data: updatedItems
26474 }, senderId);
26475 }
26476
26477 if (removedIds.length) {
26478 this._trigger("remove", {
26479 items: removedIds,
26480 oldData: removedItems
26481 }, senderId);
26482 }
26483 }
26484 }]);
26485 return DataView;
26486 }(DataSetPart);
26487
26488 var index$1 = {
26489 DataSet: DataSet,
26490 DataView: DataView$2,
26491 Queue: Queue
26492 };
26493
26494 var esm$1 = /*#__PURE__*/Object.freeze({
26495 __proto__: null,
26496 'default': index$1,
26497 DataSet: DataSet,
26498 DataStream: DataStream,
26499 DataView: DataView$2,
26500 Queue: Queue
26501 });
26502
26503 var trim$2 = stringTrim.trim;
26504 var nativeParseFloat = global_1.parseFloat;
26505 var FORCED = 1 / nativeParseFloat(whitespaces + '-0') !== -Infinity; // `parseFloat` method
26506 // https://tc39.github.io/ecma262/#sec-parsefloat-string
26507
26508 var _parseFloat = FORCED ? function parseFloat(string) {
26509 var trimmedString = trim$2(String(string));
26510 var result = nativeParseFloat(trimmedString);
26511 return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
26512 } : nativeParseFloat;
26513
26514 // https://tc39.github.io/ecma262/#sec-parsefloat-string
26515
26516 _export({
26517 global: true,
26518 forced: parseFloat != _parseFloat
26519 }, {
26520 parseFloat: _parseFloat
26521 });
26522
26523 var trim$3 = stringTrim.trim;
26524 var nativeParseInt = global_1.parseInt;
26525 var hex = /^[+-]?0[Xx]/;
26526 var FORCED$1 = nativeParseInt(whitespaces + '08') !== 8 || nativeParseInt(whitespaces + '0x16') !== 22; // `parseInt` method
26527 // https://tc39.github.io/ecma262/#sec-parseint-string-radix
26528
26529 var _parseInt = FORCED$1 ? function parseInt(string, radix) {
26530 var S = trim$3(String(string));
26531 return nativeParseInt(S, radix >>> 0 || (hex.test(S) ? 16 : 10));
26532 } : nativeParseInt;
26533
26534 // https://tc39.github.io/ecma262/#sec-parseint-string-radix
26535
26536 _export({
26537 global: true,
26538 forced: parseInt != _parseInt
26539 }, {
26540 parseInt: _parseInt
26541 });
26542
26543 var max$3 = Math.max;
26544 var min$5 = Math.min;
26545 var floor$3 = Math.floor;
26546 var SUBSTITUTION_SYMBOLS$1 = /\$([$&'`]|\d\d?|<[^>]*>)/g;
26547 var SUBSTITUTION_SYMBOLS_NO_NAMED$1 = /\$([$&'`]|\d\d?)/g;
26548
26549 var maybeToString$1 = function (it) {
26550 return it === undefined ? it : String(it);
26551 }; // @@replace logic
26552
26553
26554 fixRegexpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, maybeCallNative) {
26555 return [// `String.prototype.replace` method
26556 // https://tc39.github.io/ecma262/#sec-string.prototype.replace
26557 function replace(searchValue, replaceValue) {
26558 var O = requireObjectCoercible(this);
26559 var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
26560 return replacer !== undefined ? replacer.call(searchValue, O, replaceValue) : nativeReplace.call(String(O), searchValue, replaceValue);
26561 }, // `RegExp.prototype[@@replace]` method
26562 // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace
26563 function (regexp, replaceValue) {
26564 var res = maybeCallNative(nativeReplace, regexp, this, replaceValue);
26565 if (res.done) return res.value;
26566 var rx = anObject(regexp);
26567 var S = String(this);
26568 var functionalReplace = typeof replaceValue === 'function';
26569 if (!functionalReplace) replaceValue = String(replaceValue);
26570 var global = rx.global;
26571
26572 if (global) {
26573 var fullUnicode = rx.unicode;
26574 rx.lastIndex = 0;
26575 }
26576
26577 var results = [];
26578
26579 while (true) {
26580 var result = regexpExecAbstract(rx, S);
26581 if (result === null) break;
26582 results.push(result);
26583 if (!global) break;
26584 var matchStr = String(result[0]);
26585 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
26586 }
26587
26588 var accumulatedResult = '';
26589 var nextSourcePosition = 0;
26590
26591 for (var i = 0; i < results.length; i++) {
26592 result = results[i];
26593 var matched = String(result[0]);
26594 var position = max$3(min$5(toInteger(result.index), S.length), 0);
26595 var captures = []; // NOTE: This is equivalent to
26596 // captures = result.slice(1).map(maybeToString)
26597 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
26598 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
26599 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
26600
26601 for (var j = 1; j < result.length; j++) captures.push(maybeToString$1(result[j]));
26602
26603 var namedCaptures = result.groups;
26604
26605 if (functionalReplace) {
26606 var replacerArgs = [matched].concat(captures, position, S);
26607 if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
26608 var replacement = String(replaceValue.apply(undefined, replacerArgs));
26609 } else {
26610 replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
26611 }
26612
26613 if (position >= nextSourcePosition) {
26614 accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
26615 nextSourcePosition = position + matched.length;
26616 }
26617 }
26618
26619 return accumulatedResult + S.slice(nextSourcePosition);
26620 }]; // https://tc39.github.io/ecma262/#sec-getsubstitution
26621
26622 function getSubstitution(matched, str, position, captures, namedCaptures, replacement) {
26623 var tailPos = position + matched.length;
26624 var m = captures.length;
26625 var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED$1;
26626
26627 if (namedCaptures !== undefined) {
26628 namedCaptures = toObject(namedCaptures);
26629 symbols = SUBSTITUTION_SYMBOLS$1;
26630 }
26631
26632 return nativeReplace.call(replacement, symbols, function (match, ch) {
26633 var capture;
26634
26635 switch (ch.charAt(0)) {
26636 case '$':
26637 return '$';
26638
26639 case '&':
26640 return matched;
26641
26642 case '`':
26643 return str.slice(0, position);
26644
26645 case "'":
26646 return str.slice(tailPos);
26647
26648 case '<':
26649 capture = namedCaptures[ch.slice(1, -1)];
26650 break;
26651
26652 default:
26653 // \d\d?
26654 var n = +ch;
26655 if (n === 0) return match;
26656
26657 if (n > m) {
26658 var f = floor$3(n / 10);
26659 if (f === 0) return match;
26660 if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
26661 return match;
26662 }
26663
26664 capture = captures[n - 1];
26665 }
26666
26667 return capture === undefined ? '' : capture;
26668 });
26669 }
26670 });
26671
26672 var nativeJoin = [].join;
26673 var ES3_STRINGS = indexedObject != Object;
26674 var SLOPPY_METHOD$1 = sloppyArrayMethod('join', ','); // `Array.prototype.join` method
26675 // https://tc39.github.io/ecma262/#sec-array.prototype.join
26676
26677 _export({
26678 target: 'Array',
26679 proto: true,
26680 forced: ES3_STRINGS || SLOPPY_METHOD$1
26681 }, {
26682 join: function join(separator) {
26683 return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
26684 }
26685 });
26686
26687 /**
26688 * Helper functions for components
26689 * @class
26690 */
26691
26692 var ComponentUtil =
26693 /*#__PURE__*/
26694 function () {
26695 function ComponentUtil() {
26696 _classCallCheck(this, ComponentUtil);
26697 }
26698
26699 _createClass(ComponentUtil, null, [{
26700 key: "choosify",
26701
26702 /**
26703 * Determine values to use for (sub)options of 'chosen'.
26704 *
26705 * This option is either a boolean or an object whose values should be examined further.
26706 * The relevant structures are:
26707 *
26708 * - chosen: <boolean value>
26709 * - chosen: { subOption: <boolean or function> }
26710 *
26711 * Where subOption is 'node', 'edge' or 'label'.
26712 *
26713 * The intention of this method appears to be to set a specific priority to the options;
26714 * Since most properties are either bridged or merged into the local options objects, there
26715 * is not much point in handling them separately.
26716 * TODO: examine if 'most' in previous sentence can be replaced with 'all'. In that case, we
26717 * should be able to get rid of this method.
26718 *
26719 * @param {string} subOption option within object 'chosen' to consider; either 'node', 'edge' or 'label'
26720 * @param {Object} pile array of options objects to consider
26721 *
26722 * @return {boolean|function} value for passed subOption of 'chosen' to use
26723 */
26724 value: function choosify(subOption, pile) {
26725 // allowed values for subOption
26726 var allowed = ['node', 'edge', 'label'];
26727 var value = true;
26728 var chosen = topMost(pile, 'chosen');
26729
26730 if (typeof chosen === 'boolean') {
26731 value = chosen;
26732 } else if (_typeof$1(chosen) === 'object') {
26733 if (allowed.indexOf(subOption) === -1) {
26734 throw new Error('choosify: subOption \'' + subOption + '\' should be one of ' + "'" + allowed.join("', '") + "'");
26735 }
26736
26737 var chosenEdge = topMost(pile, ['chosen', subOption]);
26738
26739 if (typeof chosenEdge === 'boolean' || typeof chosenEdge === 'function') {
26740 value = chosenEdge;
26741 }
26742 }
26743
26744 return value;
26745 }
26746 /**
26747 * Check if the point falls within the given rectangle.
26748 *
26749 * @param {rect} rect
26750 * @param {point} point
26751 * @param {rotationPoint} [rotationPoint] if specified, the rotation that applies to the rectangle.
26752 * @returns {boolean} true if point within rectangle, false otherwise
26753 * @static
26754 */
26755
26756 }, {
26757 key: "pointInRect",
26758 value: function pointInRect(rect, point, rotationPoint) {
26759 if (rect.width <= 0 || rect.height <= 0) {
26760 return false; // early out
26761 }
26762
26763 if (rotationPoint !== undefined) {
26764 // Rotate the point the same amount as the rectangle
26765 var tmp = {
26766 x: point.x - rotationPoint.x,
26767 y: point.y - rotationPoint.y
26768 };
26769
26770 if (rotationPoint.angle !== 0) {
26771 // In order to get the coordinates the same, you need to
26772 // rotate in the reverse direction
26773 var angle = -rotationPoint.angle;
26774 var tmp2 = {
26775 x: Math.cos(angle) * tmp.x - Math.sin(angle) * tmp.y,
26776 y: Math.sin(angle) * tmp.x + Math.cos(angle) * tmp.y
26777 };
26778 point = tmp2;
26779 } else {
26780 point = tmp;
26781 } // Note that if a rotation is specified, the rectangle coordinates
26782 // are **not* the full canvas coordinates. They are relative to the
26783 // rotationPoint. Hence, the point coordinates need not be translated
26784 // back in this case.
26785
26786 }
26787
26788 var right = rect.x + rect.width;
26789 var bottom = rect.y + rect.width;
26790 return rect.left < point.x && right > point.x && rect.top < point.y && bottom > point.y;
26791 }
26792 /**
26793 * Check if given value is acceptable as a label text.
26794 *
26795 * @param {*} text value to check; can be anything at this point
26796 * @returns {boolean} true if valid label value, false otherwise
26797 */
26798
26799 }, {
26800 key: "isValidLabel",
26801 value: function isValidLabel(text) {
26802 // Note that this is quite strict: types that *might* be converted to string are disallowed
26803 return typeof text === 'string' && text !== '';
26804 }
26805 }]);
26806
26807 return ComponentUtil;
26808 }();
26809
26810 var SPECIES$5 = wellKnownSymbol('species');
26811 var nativeSlice = [].slice;
26812 var max$4 = Math.max; // `Array.prototype.slice` method
26813 // https://tc39.github.io/ecma262/#sec-array.prototype.slice
26814 // fallback for not array-like ES3 strings and DOM objects
26815
26816 _export({
26817 target: 'Array',
26818 proto: true,
26819 forced: !arrayMethodHasSpeciesSupport('slice')
26820 }, {
26821 slice: function slice(start, end) {
26822 var O = toIndexedObject(this);
26823 var length = toLength(O.length);
26824 var k = toAbsoluteIndex(start, length);
26825 var fin = toAbsoluteIndex(end === undefined ? length : end, length); // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
26826
26827 var Constructor, result, n;
26828
26829 if (isArray(O)) {
26830 Constructor = O.constructor; // cross-realm fallback
26831
26832 if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) {
26833 Constructor = undefined;
26834 } else if (isObject(Constructor)) {
26835 Constructor = Constructor[SPECIES$5];
26836 if (Constructor === null) Constructor = undefined;
26837 }
26838
26839 if (Constructor === Array || Constructor === undefined) {
26840 return nativeSlice.call(O, k, fin);
26841 }
26842 }
26843
26844 result = new (Constructor === undefined ? Array : Constructor)(max$4(fin - k, 0));
26845
26846 for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);
26847
26848 result.length = n;
26849 return result;
26850 }
26851 });
26852
26853 var SPECIES$6 = wellKnownSymbol('species');
26854
26855 var setSpecies = function (CONSTRUCTOR_NAME) {
26856 var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
26857 var defineProperty = objectDefineProperty.f;
26858
26859 if (descriptors && Constructor && !Constructor[SPECIES$6]) {
26860 defineProperty(Constructor, SPECIES$6, {
26861 configurable: true,
26862 get: function () {
26863 return this;
26864 }
26865 });
26866 }
26867 };
26868
26869 var defineProperty$7 = objectDefineProperty.f;
26870 var getOwnPropertyNames$2 = objectGetOwnPropertyNames.f;
26871 var MATCH$3 = wellKnownSymbol('match');
26872 var NativeRegExp = global_1.RegExp;
26873 var RegExpPrototype = NativeRegExp.prototype;
26874 var re1 = /a/g;
26875 var re2 = /a/g; // "new" should create a new object, old webkit bug
26876
26877 var CORRECT_NEW = new NativeRegExp(re1) !== re1;
26878 var FORCED$2 = descriptors && isForced_1('RegExp', !CORRECT_NEW || fails(function () {
26879 re2[MATCH$3] = false; // RegExp constructor can alter flags and IsRegExp works correct with @@match
26880
26881 return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
26882 })); // `RegExp` constructor
26883 // https://tc39.github.io/ecma262/#sec-regexp-constructor
26884
26885 if (FORCED$2) {
26886 var RegExpWrapper = function RegExp(pattern, flags) {
26887 var thisIsRegExp = this instanceof RegExpWrapper;
26888 var patternIsRegExp = isRegexp(pattern);
26889 var flagsAreUndefined = flags === undefined;
26890 return !thisIsRegExp && patternIsRegExp && pattern.constructor === RegExpWrapper && flagsAreUndefined ? pattern : inheritIfRequired(CORRECT_NEW ? new NativeRegExp(patternIsRegExp && !flagsAreUndefined ? pattern.source : pattern, flags) : NativeRegExp((patternIsRegExp = pattern instanceof RegExpWrapper) ? pattern.source : pattern, patternIsRegExp && flagsAreUndefined ? regexpFlags.call(pattern) : flags), thisIsRegExp ? this : RegExpPrototype, RegExpWrapper);
26891 };
26892
26893 var proxy = function (key) {
26894 key in RegExpWrapper || defineProperty$7(RegExpWrapper, key, {
26895 configurable: true,
26896 get: function () {
26897 return NativeRegExp[key];
26898 },
26899 set: function (it) {
26900 NativeRegExp[key] = it;
26901 }
26902 });
26903 };
26904
26905 var keys$4 = getOwnPropertyNames$2(NativeRegExp);
26906 var index$2 = 0;
26907
26908 while (keys$4.length > index$2) proxy(keys$4[index$2++]);
26909
26910 RegExpPrototype.constructor = RegExpWrapper;
26911 RegExpWrapper.prototype = RegExpPrototype;
26912 redefine(global_1, 'RegExp', RegExpWrapper);
26913 } // https://tc39.github.io/ecma262/#sec-get-regexp-@@species
26914
26915
26916 setSpecies('RegExp');
26917
26918 var TO_STRING$1 = 'toString';
26919 var RegExpPrototype$1 = RegExp.prototype;
26920 var nativeToString = RegExpPrototype$1[TO_STRING$1];
26921 var NOT_GENERIC = fails(function () {
26922 return nativeToString.call({
26923 source: 'a',
26924 flags: 'b'
26925 }) != '/a/b';
26926 }); // FF44- RegExp#toString has a wrong name
26927
26928 var INCORRECT_NAME = nativeToString.name != TO_STRING$1; // `RegExp.prototype.toString` method
26929 // https://tc39.github.io/ecma262/#sec-regexp.prototype.tostring
26930
26931 if (NOT_GENERIC || INCORRECT_NAME) {
26932 redefine(RegExp.prototype, TO_STRING$1, function toString() {
26933 var R = anObject(this);
26934 var p = String(R.source);
26935 var rf = R.flags;
26936 var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype$1) ? regexpFlags.call(R) : rf);
26937 return '/' + p + '/' + f;
26938 }, {
26939 unsafe: true
26940 });
26941 }
26942
26943 fixRegexpWellKnownSymbolLogic('match', 1, function (MATCH, nativeMatch, maybeCallNative) {
26944 return [// `String.prototype.match` method
26945 // https://tc39.github.io/ecma262/#sec-string.prototype.match
26946 function match(regexp) {
26947 var O = requireObjectCoercible(this);
26948 var matcher = regexp == undefined ? undefined : regexp[MATCH];
26949 return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
26950 }, // `RegExp.prototype[@@match]` method
26951 // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@match
26952 function (regexp) {
26953 var res = maybeCallNative(nativeMatch, regexp, this);
26954 if (res.done) return res.value;
26955 var rx = anObject(regexp);
26956 var S = String(this);
26957 if (!rx.global) return regexpExecAbstract(rx, S);
26958 var fullUnicode = rx.unicode;
26959 rx.lastIndex = 0;
26960 var A = [];
26961 var n = 0;
26962 var result;
26963
26964 while ((result = regexpExecAbstract(rx, S)) !== null) {
26965 var matchStr = String(result[0]);
26966 A[n] = matchStr;
26967 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
26968 n++;
26969 }
26970
26971 return n === 0 ? null : A;
26972 }];
26973 });
26974
26975 // https://tc39.github.io/ecma262/#sec-string.prototype.bold
26976
26977
26978 _export({
26979 target: 'String',
26980 proto: true,
26981 forced: forcedStringHtmlMethod('bold')
26982 }, {
26983 bold: function bold() {
26984 return createHtml(this, 'b', '', '');
26985 }
26986 });
26987
26988 var iterators = {};
26989
26990 var ITERATOR$2 = wellKnownSymbol('iterator');
26991 var BUGGY_SAFARI_ITERATORS = false;
26992
26993 var returnThis$1 = function () {
26994 return this;
26995 }; // `%IteratorPrototype%` object
26996 // https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object
26997
26998
26999 var IteratorPrototype$1, PrototypeOfArrayIteratorPrototype, arrayIterator;
27000
27001 if ([].keys) {
27002 arrayIterator = [].keys(); // Safari 8 has buggy iterators w/o `next`
27003
27004 if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;else {
27005 PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
27006 if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype$1 = PrototypeOfArrayIteratorPrototype;
27007 }
27008 }
27009
27010 if (IteratorPrototype$1 == undefined) IteratorPrototype$1 = {}; // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
27011
27012 if ( !has(IteratorPrototype$1, ITERATOR$2)) {
27013 createNonEnumerableProperty(IteratorPrototype$1, ITERATOR$2, returnThis$1);
27014 }
27015
27016 var iteratorsCore = {
27017 IteratorPrototype: IteratorPrototype$1,
27018 BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
27019 };
27020
27021 var IteratorPrototype$2 = iteratorsCore.IteratorPrototype;
27022
27023 var returnThis$2 = function () {
27024 return this;
27025 };
27026
27027 var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
27028 var TO_STRING_TAG = NAME + ' Iterator';
27029 IteratorConstructor.prototype = objectCreate(IteratorPrototype$2, {
27030 next: createPropertyDescriptor(1, next)
27031 });
27032 setToStringTag(IteratorConstructor, TO_STRING_TAG, false);
27033 iterators[TO_STRING_TAG] = returnThis$2;
27034 return IteratorConstructor;
27035 };
27036
27037 var IteratorPrototype$3 = iteratorsCore.IteratorPrototype;
27038 var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS;
27039 var ITERATOR$3 = wellKnownSymbol('iterator');
27040 var KEYS$1 = 'keys';
27041 var VALUES$1 = 'values';
27042 var ENTRIES = 'entries';
27043
27044 var returnThis$3 = function () {
27045 return this;
27046 };
27047
27048 var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
27049 createIteratorConstructor(IteratorConstructor, NAME, next);
27050
27051 var getIterationMethod = function (KIND) {
27052 if (KIND === DEFAULT && defaultIterator) return defaultIterator;
27053 if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND];
27054
27055 switch (KIND) {
27056 case KEYS$1:
27057 return function keys() {
27058 return new IteratorConstructor(this, KIND);
27059 };
27060
27061 case VALUES$1:
27062 return function values() {
27063 return new IteratorConstructor(this, KIND);
27064 };
27065
27066 case ENTRIES:
27067 return function entries() {
27068 return new IteratorConstructor(this, KIND);
27069 };
27070 }
27071
27072 return function () {
27073 return new IteratorConstructor(this);
27074 };
27075 };
27076
27077 var TO_STRING_TAG = NAME + ' Iterator';
27078 var INCORRECT_VALUES_NAME = false;
27079 var IterablePrototype = Iterable.prototype;
27080 var nativeIterator = IterablePrototype[ITERATOR$3] || IterablePrototype['@@iterator'] || DEFAULT && IterablePrototype[DEFAULT];
27081 var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT);
27082 var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
27083 var CurrentIteratorPrototype, methods, KEY; // fix native
27084
27085 if (anyNativeIterator) {
27086 CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));
27087
27088 if (IteratorPrototype$3 !== Object.prototype && CurrentIteratorPrototype.next) {
27089 if ( objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$3) {
27090 if (objectSetPrototypeOf) {
27091 objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$3);
27092 } else if (typeof CurrentIteratorPrototype[ITERATOR$3] != 'function') {
27093 createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$3, returnThis$3);
27094 }
27095 } // Set @@toStringTag to native iterators
27096
27097
27098 setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);
27099 }
27100 } // fix Array#{values, @@iterator}.name in V8 / FF
27101
27102
27103 if (DEFAULT == VALUES$1 && nativeIterator && nativeIterator.name !== VALUES$1) {
27104 INCORRECT_VALUES_NAME = true;
27105
27106 defaultIterator = function values() {
27107 return nativeIterator.call(this);
27108 };
27109 } // define iterator
27110
27111
27112 if ( IterablePrototype[ITERATOR$3] !== defaultIterator) {
27113 createNonEnumerableProperty(IterablePrototype, ITERATOR$3, defaultIterator);
27114 }
27115
27116 iterators[NAME] = defaultIterator; // export additional methods
27117
27118 if (DEFAULT) {
27119 methods = {
27120 values: getIterationMethod(VALUES$1),
27121 keys: IS_SET ? defaultIterator : getIterationMethod(KEYS$1),
27122 entries: getIterationMethod(ENTRIES)
27123 };
27124 if (FORCED) for (KEY in methods) {
27125 if (BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
27126 redefine(IterablePrototype, KEY, methods[KEY]);
27127 }
27128 } else _export({
27129 target: NAME,
27130 proto: true,
27131 forced: BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME
27132 }, methods);
27133 }
27134
27135 return methods;
27136 };
27137
27138 var ARRAY_ITERATOR = 'Array Iterator';
27139 var setInternalState$1 = internalState.set;
27140 var getInternalState$1 = internalState.getterFor(ARRAY_ITERATOR); // `Array.prototype.entries` method
27141 // https://tc39.github.io/ecma262/#sec-array.prototype.entries
27142 // `Array.prototype.keys` method
27143 // https://tc39.github.io/ecma262/#sec-array.prototype.keys
27144 // `Array.prototype.values` method
27145 // https://tc39.github.io/ecma262/#sec-array.prototype.values
27146 // `Array.prototype[@@iterator]` method
27147 // https://tc39.github.io/ecma262/#sec-array.prototype-@@iterator
27148 // `CreateArrayIterator` internal method
27149 // https://tc39.github.io/ecma262/#sec-createarrayiterator
27150
27151 var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
27152 setInternalState$1(this, {
27153 type: ARRAY_ITERATOR,
27154 target: toIndexedObject(iterated),
27155 // target
27156 index: 0,
27157 // next index
27158 kind: kind // kind
27159
27160 }); // `%ArrayIteratorPrototype%.next` method
27161 // https://tc39.github.io/ecma262/#sec-%arrayiteratorprototype%.next
27162 }, function () {
27163 var state = getInternalState$1(this);
27164 var target = state.target;
27165 var kind = state.kind;
27166 var index = state.index++;
27167
27168 if (!target || index >= target.length) {
27169 state.target = undefined;
27170 return {
27171 value: undefined,
27172 done: true
27173 };
27174 }
27175
27176 if (kind == 'keys') return {
27177 value: index,
27178 done: false
27179 };
27180 if (kind == 'values') return {
27181 value: target[index],
27182 done: false
27183 };
27184 return {
27185 value: [index, target[index]],
27186 done: false
27187 };
27188 }, 'values'); // argumentsList[@@iterator] is %ArrayProto_values%
27189 // https://tc39.github.io/ecma262/#sec-createunmappedargumentsobject
27190 // https://tc39.github.io/ecma262/#sec-createmappedargumentsobject
27191
27192 iterators.Arguments = iterators.Array; // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
27193
27194 addToUnscopables('keys');
27195 addToUnscopables('values');
27196 addToUnscopables('entries');
27197
27198 var nativeAssign = Object.assign; // `Object.assign` method
27199 // https://tc39.github.io/ecma262/#sec-object.assign
27200 // should work with symbols and should have deterministic property order (V8 bug)
27201
27202 var objectAssign = !nativeAssign || fails(function () {
27203 var A = {};
27204 var B = {}; // eslint-disable-next-line no-undef
27205
27206 var symbol = Symbol();
27207 var alphabet = 'abcdefghijklmnopqrst';
27208 A[symbol] = 7;
27209 alphabet.split('').forEach(function (chr) {
27210 B[chr] = chr;
27211 });
27212 return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet;
27213 }) ? function assign(target, source) {
27214 // eslint-disable-line no-unused-vars
27215 var T = toObject(target);
27216 var argumentsLength = arguments.length;
27217 var index = 1;
27218 var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
27219 var propertyIsEnumerable = objectPropertyIsEnumerable.f;
27220
27221 while (argumentsLength > index) {
27222 var S = indexedObject(arguments[index++]);
27223 var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
27224 var length = keys.length;
27225 var j = 0;
27226 var key;
27227
27228 while (length > j) {
27229 key = keys[j++];
27230 if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
27231 }
27232 }
27233
27234 return T;
27235 } : nativeAssign;
27236
27237 // https://tc39.github.io/ecma262/#sec-object.assign
27238
27239 _export({
27240 target: 'Object',
27241 stat: true,
27242 forced: Object.assign !== objectAssign
27243 }, {
27244 assign: objectAssign
27245 });
27246
27247 var ITERATOR$4 = wellKnownSymbol('iterator');
27248 var TO_STRING_TAG$5 = wellKnownSymbol('toStringTag');
27249 var ArrayValues$1 = es_array_iterator.values;
27250
27251 for (var COLLECTION_NAME$1 in domIterables) {
27252 var Collection$2 = global_1[COLLECTION_NAME$1];
27253 var CollectionPrototype$1 = Collection$2 && Collection$2.prototype;
27254
27255 if (CollectionPrototype$1) {
27256 // some Chrome versions have non-configurable methods on DOMTokenList
27257 if (CollectionPrototype$1[ITERATOR$4] !== ArrayValues$1) try {
27258 createNonEnumerableProperty(CollectionPrototype$1, ITERATOR$4, ArrayValues$1);
27259 } catch (error) {
27260 CollectionPrototype$1[ITERATOR$4] = ArrayValues$1;
27261 }
27262
27263 if (!CollectionPrototype$1[TO_STRING_TAG$5]) {
27264 createNonEnumerableProperty(CollectionPrototype$1, TO_STRING_TAG$5, COLLECTION_NAME$1);
27265 }
27266
27267 if (domIterables[COLLECTION_NAME$1]) for (var METHOD_NAME in es_array_iterator) {
27268 // some Chrome versions have non-configurable methods on DOMTokenList
27269 if (CollectionPrototype$1[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {
27270 createNonEnumerableProperty(CollectionPrototype$1, METHOD_NAME, es_array_iterator[METHOD_NAME]);
27271 } catch (error) {
27272 CollectionPrototype$1[METHOD_NAME] = es_array_iterator[METHOD_NAME];
27273 }
27274 }
27275 }
27276 }
27277
27278 /**
27279 * Callback to determine text dimensions, using the parent label settings.
27280 * @callback MeasureText
27281 * @param {text} text
27282 * @param {text} mod
27283 * @return {Object} { width, values} width in pixels and font attributes
27284 */
27285
27286 /**
27287 * Helper class for Label which collects results of splitting labels into lines and blocks.
27288 *
27289 * @private
27290 */
27291 var LabelAccumulator =
27292 /*#__PURE__*/
27293 function () {
27294 /**
27295 * @param {MeasureText} measureText
27296 */
27297 function LabelAccumulator(measureText) {
27298 _classCallCheck(this, LabelAccumulator);
27299
27300 this.measureText = measureText;
27301 this.current = 0;
27302 this.width = 0;
27303 this.height = 0;
27304 this.lines = [];
27305 }
27306 /**
27307 * Append given text to the given line.
27308 *
27309 * @param {number} l index of line to add to
27310 * @param {string} text string to append to line
27311 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
27312 * @private
27313 */
27314
27315
27316 _createClass(LabelAccumulator, [{
27317 key: "_add",
27318 value: function _add(l, text) {
27319 var mod = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'normal';
27320
27321 if (this.lines[l] === undefined) {
27322 this.lines[l] = {
27323 width: 0,
27324 height: 0,
27325 blocks: []
27326 };
27327 } // We still need to set a block for undefined and empty texts, hence return at this point
27328 // This is necessary because we don't know at this point if we're at the
27329 // start of an empty line or not.
27330 // To compensate, empty blocks are removed in `finalize()`.
27331 //
27332 // Empty strings should still have a height
27333
27334
27335 var tmpText = text;
27336 if (text === undefined || text === "") tmpText = " "; // Determine width and get the font properties
27337
27338 var result = this.measureText(tmpText, mod);
27339 var block = Object.assign({}, result.values);
27340 block.text = text;
27341 block.width = result.width;
27342 block.mod = mod;
27343
27344 if (text === undefined || text === "") {
27345 block.width = 0;
27346 }
27347
27348 this.lines[l].blocks.push(block); // Update the line width. We need this for determining if a string goes over max width
27349
27350 this.lines[l].width += block.width;
27351 }
27352 /**
27353 * Returns the width in pixels of the current line.
27354 *
27355 * @returns {number}
27356 */
27357
27358 }, {
27359 key: "curWidth",
27360 value: function curWidth() {
27361 var line = this.lines[this.current];
27362 if (line === undefined) return 0;
27363 return line.width;
27364 }
27365 /**
27366 * Add text in block to current line
27367 *
27368 * @param {string} text
27369 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
27370 */
27371
27372 }, {
27373 key: "append",
27374 value: function append(text) {
27375 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'normal';
27376
27377 this._add(this.current, text, mod);
27378 }
27379 /**
27380 * Add text in block to current line and start a new line
27381 *
27382 * @param {string} text
27383 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
27384 */
27385
27386 }, {
27387 key: "newLine",
27388 value: function newLine(text) {
27389 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'normal';
27390
27391 this._add(this.current, text, mod);
27392
27393 this.current++;
27394 }
27395 /**
27396 * Determine and set the heights of all the lines currently contained in this instance
27397 *
27398 * Note that width has already been set.
27399 *
27400 * @private
27401 */
27402
27403 }, {
27404 key: "determineLineHeights",
27405 value: function determineLineHeights() {
27406 for (var k = 0; k < this.lines.length; k++) {
27407 var line = this.lines[k]; // Looking for max height of blocks in line
27408
27409 var height = 0;
27410
27411 if (line.blocks !== undefined) {
27412 // Can happen if text contains e.g. '\n '
27413 for (var l = 0; l < line.blocks.length; l++) {
27414 var block = line.blocks[l];
27415
27416 if (height < block.height) {
27417 height = block.height;
27418 }
27419 }
27420 }
27421
27422 line.height = height;
27423 }
27424 }
27425 /**
27426 * Determine the full size of the label text, as determined by current lines and blocks
27427 *
27428 * @private
27429 */
27430
27431 }, {
27432 key: "determineLabelSize",
27433 value: function determineLabelSize() {
27434 var width = 0;
27435 var height = 0;
27436
27437 for (var k = 0; k < this.lines.length; k++) {
27438 var line = this.lines[k];
27439
27440 if (line.width > width) {
27441 width = line.width;
27442 }
27443
27444 height += line.height;
27445 }
27446
27447 this.width = width;
27448 this.height = height;
27449 }
27450 /**
27451 * Remove all empty blocks and empty lines we don't need
27452 *
27453 * This must be done after the width/height determination,
27454 * so that these are set properly for processing here.
27455 *
27456 * @returns {Array<Line>} Lines with empty blocks (and some empty lines) removed
27457 * @private
27458 */
27459
27460 }, {
27461 key: "removeEmptyBlocks",
27462 value: function removeEmptyBlocks() {
27463 var tmpLines = [];
27464
27465 for (var k = 0; k < this.lines.length; k++) {
27466 var line = this.lines[k]; // Note: an empty line in between text has width zero but is still relevant to layout.
27467 // So we can't use width for testing empty line here
27468
27469 if (line.blocks.length === 0) continue; // Discard final empty line always
27470
27471 if (k === this.lines.length - 1) {
27472 if (line.width === 0) continue;
27473 }
27474
27475 var tmpLine = {};
27476 Object.assign(tmpLine, line);
27477 tmpLine.blocks = [];
27478 var firstEmptyBlock = void 0;
27479 var tmpBlocks = [];
27480
27481 for (var l = 0; l < line.blocks.length; l++) {
27482 var block = line.blocks[l];
27483
27484 if (block.width !== 0) {
27485 tmpBlocks.push(block);
27486 } else {
27487 if (firstEmptyBlock === undefined) {
27488 firstEmptyBlock = block;
27489 }
27490 }
27491 } // Ensure that there is *some* text present
27492
27493
27494 if (tmpBlocks.length === 0 && firstEmptyBlock !== undefined) {
27495 tmpBlocks.push(firstEmptyBlock);
27496 }
27497
27498 tmpLine.blocks = tmpBlocks;
27499 tmpLines.push(tmpLine);
27500 }
27501
27502 return tmpLines;
27503 }
27504 /**
27505 * Set the sizes for all lines and the whole thing.
27506 *
27507 * @returns {{width: (number|*), height: (number|*), lines: Array}}
27508 */
27509
27510 }, {
27511 key: "finalize",
27512 value: function finalize() {
27513 //console.log(JSON.stringify(this.lines, null, 2));
27514 this.determineLineHeights();
27515 this.determineLabelSize();
27516 var tmpLines = this.removeEmptyBlocks(); // Return a simple hash object for further processing.
27517
27518 return {
27519 width: this.width,
27520 height: this.height,
27521 lines: tmpLines
27522 };
27523 }
27524 }]);
27525
27526 return LabelAccumulator;
27527 }();
27528
27529 var tagPattern = {
27530 // HTML
27531 '<b>': /<b>/,
27532 '<i>': /<i>/,
27533 '<code>': /<code>/,
27534 '</b>': /<\/b>/,
27535 '</i>': /<\/i>/,
27536 '</code>': /<\/code>/,
27537 // Markdown
27538 '*': /\*/,
27539 // bold
27540 '_': /\_/,
27541 // ital
27542 '`': /`/,
27543 // mono
27544 'afterBold': /[^\*]/,
27545 'afterItal': /[^_]/,
27546 'afterMono': /[^`]/
27547 };
27548 /**
27549 * Internal helper class for parsing the markup tags for HTML and Markdown.
27550 *
27551 * NOTE: Sequences of tabs and spaces are reduced to single space.
27552 * Scan usage of `this.spacing` within method
27553 */
27554
27555 var MarkupAccumulator =
27556 /*#__PURE__*/
27557 function () {
27558 /**
27559 * Create an instance
27560 *
27561 * @param {string} text text to parse for markup
27562 */
27563 function MarkupAccumulator(text) {
27564 _classCallCheck(this, MarkupAccumulator);
27565
27566 this.text = text;
27567 this.bold = false;
27568 this.ital = false;
27569 this.mono = false;
27570 this.spacing = false;
27571 this.position = 0;
27572 this.buffer = "";
27573 this.modStack = [];
27574 this.blocks = [];
27575 }
27576 /**
27577 * Return the mod label currently on the top of the stack
27578 *
27579 * @returns {string} label of topmost mod
27580 * @private
27581 */
27582
27583
27584 _createClass(MarkupAccumulator, [{
27585 key: "mod",
27586 value: function mod() {
27587 return this.modStack.length === 0 ? 'normal' : this.modStack[0];
27588 }
27589 /**
27590 * Return the mod label currently active
27591 *
27592 * @returns {string} label of active mod
27593 * @private
27594 */
27595
27596 }, {
27597 key: "modName",
27598 value: function modName() {
27599 if (this.modStack.length === 0) return 'normal';else if (this.modStack[0] === 'mono') return 'mono';else {
27600 if (this.bold && this.ital) {
27601 return 'boldital';
27602 } else if (this.bold) {
27603 return 'bold';
27604 } else if (this.ital) {
27605 return 'ital';
27606 }
27607 }
27608 }
27609 /**
27610 * @private
27611 */
27612
27613 }, {
27614 key: "emitBlock",
27615 value: function emitBlock() {
27616 if (this.spacing) {
27617 this.add(" ");
27618 this.spacing = false;
27619 }
27620
27621 if (this.buffer.length > 0) {
27622 this.blocks.push({
27623 text: this.buffer,
27624 mod: this.modName()
27625 });
27626 this.buffer = "";
27627 }
27628 }
27629 /**
27630 * Output text to buffer
27631 *
27632 * @param {string} text text to add
27633 * @private
27634 */
27635
27636 }, {
27637 key: "add",
27638 value: function add(text) {
27639 if (text === " ") {
27640 this.spacing = true;
27641 }
27642
27643 if (this.spacing) {
27644 this.buffer += " ";
27645 this.spacing = false;
27646 }
27647
27648 if (text != " ") {
27649 this.buffer += text;
27650 }
27651 }
27652 /**
27653 * Handle parsing of whitespace
27654 *
27655 * @param {string} ch the character to check
27656 * @returns {boolean} true if the character was processed as whitespace, false otherwise
27657 */
27658
27659 }, {
27660 key: "parseWS",
27661 value: function parseWS(ch) {
27662 if (/[ \t]/.test(ch)) {
27663 if (!this.mono) {
27664 this.spacing = true;
27665 } else {
27666 this.add(ch);
27667 }
27668
27669 return true;
27670 }
27671
27672 return false;
27673 }
27674 /**
27675 * @param {string} tagName label for block type to set
27676 * @private
27677 */
27678
27679 }, {
27680 key: "setTag",
27681 value: function setTag(tagName) {
27682 this.emitBlock();
27683 this[tagName] = true;
27684 this.modStack.unshift(tagName);
27685 }
27686 /**
27687 * @param {string} tagName label for block type to unset
27688 * @private
27689 */
27690
27691 }, {
27692 key: "unsetTag",
27693 value: function unsetTag(tagName) {
27694 this.emitBlock();
27695 this[tagName] = false;
27696 this.modStack.shift();
27697 }
27698 /**
27699 * @param {string} tagName label for block type we are currently processing
27700 * @param {string|RegExp} tag string to match in text
27701 * @returns {boolean} true if the tag was processed, false otherwise
27702 */
27703
27704 }, {
27705 key: "parseStartTag",
27706 value: function parseStartTag(tagName, tag) {
27707 // Note: if 'mono' passed as tagName, there is a double check here. This is OK
27708 if (!this.mono && !this[tagName] && this.match(tag)) {
27709 this.setTag(tagName);
27710 return true;
27711 }
27712
27713 return false;
27714 }
27715 /**
27716 * @param {string|RegExp} tag
27717 * @param {number} [advance=true] if set, advance current position in text
27718 * @returns {boolean} true if match at given position, false otherwise
27719 * @private
27720 */
27721
27722 }, {
27723 key: "match",
27724 value: function match(tag) {
27725 var advance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
27726
27727 var _this$prepareRegExp = this.prepareRegExp(tag),
27728 _this$prepareRegExp2 = _slicedToArray(_this$prepareRegExp, 2),
27729 regExp = _this$prepareRegExp2[0],
27730 length = _this$prepareRegExp2[1];
27731
27732 var matched = regExp.test(this.text.substr(this.position, length));
27733
27734 if (matched && advance) {
27735 this.position += length - 1;
27736 }
27737
27738 return matched;
27739 }
27740 /**
27741 * @param {string} tagName label for block type we are currently processing
27742 * @param {string|RegExp} tag string to match in text
27743 * @param {RegExp} [nextTag] regular expression to match for characters *following* the current tag
27744 * @returns {boolean} true if the tag was processed, false otherwise
27745 */
27746
27747 }, {
27748 key: "parseEndTag",
27749 value: function parseEndTag(tagName, tag, nextTag) {
27750 var checkTag = this.mod() === tagName;
27751
27752 if (tagName === 'mono') {
27753 // special handling for 'mono'
27754 checkTag = checkTag && this.mono;
27755 } else {
27756 checkTag = checkTag && !this.mono;
27757 }
27758
27759 if (checkTag && this.match(tag)) {
27760 if (nextTag !== undefined) {
27761 // Purpose of the following match is to prevent a direct unset/set of a given tag
27762 // E.g. '*bold **still bold*' => '*bold still bold*'
27763 if (this.position === this.text.length - 1 || this.match(nextTag, false)) {
27764 this.unsetTag(tagName);
27765 }
27766 } else {
27767 this.unsetTag(tagName);
27768 }
27769
27770 return true;
27771 }
27772
27773 return false;
27774 }
27775 /**
27776 * @param {string|RegExp} tag string to match in text
27777 * @param {value} value string to replace tag with, if found at current position
27778 * @returns {boolean} true if the tag was processed, false otherwise
27779 */
27780
27781 }, {
27782 key: "replace",
27783 value: function replace(tag, value) {
27784 if (this.match(tag)) {
27785 this.add(value);
27786 this.position += length - 1;
27787 return true;
27788 }
27789
27790 return false;
27791 }
27792 /**
27793 * Create a regular expression for the tag if it isn't already one.
27794 *
27795 * The return value is an array `[RegExp, number]`, with exactly two value, where:
27796 * - RegExp is the regular expression to use
27797 * - number is the lenth of the input string to match
27798 *
27799 * @param {string|RegExp} tag string to match in text
27800 * @returns {Array} regular expression to use and length of input string to match
27801 * @private
27802 */
27803
27804 }, {
27805 key: "prepareRegExp",
27806 value: function prepareRegExp(tag) {
27807 var length;
27808 var regExp;
27809
27810 if (tag instanceof RegExp) {
27811 regExp = tag;
27812 length = 1; // ASSUMPTION: regexp only tests one character
27813 } else {
27814 // use prepared regexp if present
27815 var prepared = tagPattern[tag];
27816
27817 if (prepared !== undefined) {
27818 regExp = prepared;
27819 } else {
27820 regExp = new RegExp(tag);
27821 }
27822
27823 length = tag.length;
27824 }
27825
27826 return [regExp, length];
27827 }
27828 }]);
27829
27830 return MarkupAccumulator;
27831 }();
27832 /**
27833 * Helper class for Label which explodes the label text into lines and blocks within lines
27834 *
27835 * @private
27836 */
27837
27838
27839 var LabelSplitter =
27840 /*#__PURE__*/
27841 function () {
27842 /**
27843 * @param {CanvasRenderingContext2D} ctx Canvas rendering context
27844 * @param {Label} parent reference to the Label instance using current instance
27845 * @param {boolean} selected
27846 * @param {boolean} hover
27847 */
27848 function LabelSplitter(ctx, parent, selected, hover) {
27849 var _this = this;
27850
27851 _classCallCheck(this, LabelSplitter);
27852
27853 this.ctx = ctx;
27854 this.parent = parent;
27855 this.selected = selected;
27856 this.hover = hover;
27857 /**
27858 * Callback to determine text width; passed to LabelAccumulator instance
27859 *
27860 * @param {String} text string to determine width of
27861 * @param {String} mod font type to use for this text
27862 * @return {Object} { width, values} width in pixels and font attributes
27863 */
27864
27865 var textWidth = function textWidth(text, mod) {
27866 if (text === undefined) return 0; // TODO: This can be done more efficiently with caching
27867 // This will set the ctx.font correctly, depending on selected/hover and mod - so that ctx.measureText() will be accurate.
27868
27869 var values = _this.parent.getFormattingValues(ctx, selected, hover, mod);
27870
27871 var width = 0;
27872
27873 if (text !== '') {
27874 var measure = _this.ctx.measureText(text);
27875
27876 width = measure.width;
27877 }
27878
27879 return {
27880 width: width,
27881 values: values
27882 };
27883 };
27884
27885 this.lines = new LabelAccumulator(textWidth);
27886 }
27887 /**
27888 * Split passed text of a label into lines and blocks.
27889 *
27890 * # NOTE
27891 *
27892 * The handling of spacing is option dependent:
27893 *
27894 * - if `font.multi : false`, all spaces are retained
27895 * - if `font.multi : true`, every sequence of spaces is compressed to a single space
27896 *
27897 * This might not be the best way to do it, but this is as it has been working till now.
27898 * In order not to break existing functionality, for the time being this behaviour will
27899 * be retained in any code changes.
27900 *
27901 * @param {string} text text to split
27902 * @returns {Array<line>}
27903 */
27904
27905
27906 _createClass(LabelSplitter, [{
27907 key: "process",
27908 value: function process(text) {
27909 if (!ComponentUtil.isValidLabel(text)) {
27910 return this.lines.finalize();
27911 }
27912
27913 var font = this.parent.fontOptions; // Normalize the end-of-line's to a single representation - order important
27914
27915 text = text.replace(/\r\n/g, '\n'); // Dos EOL's
27916
27917 text = text.replace(/\r/g, '\n'); // Mac EOL's
27918 // Note that at this point, there can be no \r's in the text.
27919 // This is used later on splitStringIntoLines() to split multifont texts.
27920
27921 var nlLines = String(text).split('\n');
27922 var lineCount = nlLines.length;
27923
27924 if (font.multi) {
27925 // Multi-font case: styling tags active
27926 for (var i = 0; i < lineCount; i++) {
27927 var blocks = this.splitBlocks(nlLines[i], font.multi); // Post: Sequences of tabs and spaces are reduced to single space
27928
27929 if (blocks === undefined) continue;
27930
27931 if (blocks.length === 0) {
27932 this.lines.newLine("");
27933 continue;
27934 }
27935
27936 if (font.maxWdt > 0) {
27937 // widthConstraint.maximum defined
27938 //console.log('Running widthConstraint multi, max: ' + this.fontOptions.maxWdt);
27939 for (var j = 0; j < blocks.length; j++) {
27940 var mod = blocks[j].mod;
27941 var _text = blocks[j].text;
27942 this.splitStringIntoLines(_text, mod, true);
27943 }
27944 } else {
27945 // widthConstraint.maximum NOT defined
27946 for (var _j = 0; _j < blocks.length; _j++) {
27947 var _mod = blocks[_j].mod;
27948 var _text2 = blocks[_j].text;
27949 this.lines.append(_text2, _mod);
27950 }
27951 }
27952
27953 this.lines.newLine();
27954 }
27955 } else {
27956 // Single-font case
27957 if (font.maxWdt > 0) {
27958 // widthConstraint.maximum defined
27959 // console.log('Running widthConstraint normal, max: ' + this.fontOptions.maxWdt);
27960 for (var _i = 0; _i < lineCount; _i++) {
27961 this.splitStringIntoLines(nlLines[_i]);
27962 }
27963 } else {
27964 // widthConstraint.maximum NOT defined
27965 for (var _i2 = 0; _i2 < lineCount; _i2++) {
27966 this.lines.newLine(nlLines[_i2]);
27967 }
27968 }
27969 }
27970
27971 return this.lines.finalize();
27972 }
27973 /**
27974 * normalize the markup system
27975 *
27976 * @param {boolean|'md'|'markdown'|'html'} markupSystem
27977 * @returns {string}
27978 */
27979
27980 }, {
27981 key: "decodeMarkupSystem",
27982 value: function decodeMarkupSystem(markupSystem) {
27983 var system = 'none';
27984
27985 if (markupSystem === 'markdown' || markupSystem === 'md') {
27986 system = 'markdown';
27987 } else if (markupSystem === true || markupSystem === 'html') {
27988 system = 'html';
27989 }
27990
27991 return system;
27992 }
27993 /**
27994 *
27995 * @param {string} text
27996 * @returns {Array}
27997 */
27998
27999 }, {
28000 key: "splitHtmlBlocks",
28001 value: function splitHtmlBlocks(text) {
28002 var s = new MarkupAccumulator(text);
28003
28004 var parseEntities = function parseEntities(ch) {
28005 if (/&/.test(ch)) {
28006 var parsed = s.replace(s.text, '&lt;', '<') || s.replace(s.text, '&amp;', '&');
28007
28008 if (!parsed) {
28009 s.add("&");
28010 }
28011
28012 return true;
28013 }
28014
28015 return false;
28016 };
28017
28018 while (s.position < s.text.length) {
28019 var ch = s.text.charAt(s.position);
28020 var parsed = s.parseWS(ch) || /</.test(ch) && (s.parseStartTag('bold', '<b>') || s.parseStartTag('ital', '<i>') || s.parseStartTag('mono', '<code>') || s.parseEndTag('bold', '</b>') || s.parseEndTag('ital', '</i>') || s.parseEndTag('mono', '</code>')) || parseEntities(ch);
28021
28022 if (!parsed) {
28023 s.add(ch);
28024 }
28025
28026 s.position++;
28027 }
28028
28029 s.emitBlock();
28030 return s.blocks;
28031 }
28032 /**
28033 *
28034 * @param {string} text
28035 * @returns {Array}
28036 */
28037
28038 }, {
28039 key: "splitMarkdownBlocks",
28040 value: function splitMarkdownBlocks(text) {
28041 var _this2 = this;
28042
28043 var s = new MarkupAccumulator(text);
28044 var beginable = true;
28045
28046 var parseOverride = function parseOverride(ch) {
28047 if (/\\/.test(ch)) {
28048 if (s.position < _this2.text.length + 1) {
28049 s.position++;
28050 ch = _this2.text.charAt(s.position);
28051
28052 if (/ \t/.test(ch)) {
28053 s.spacing = true;
28054 } else {
28055 s.add(ch);
28056 beginable = false;
28057 }
28058 }
28059
28060 return true;
28061 }
28062
28063 return false;
28064 };
28065
28066 while (s.position < s.text.length) {
28067 var ch = s.text.charAt(s.position);
28068 var parsed = s.parseWS(ch) || parseOverride(ch) || (beginable || s.spacing) && (s.parseStartTag('bold', '*') || s.parseStartTag('ital', '_') || s.parseStartTag('mono', '`')) || s.parseEndTag('bold', '*', 'afterBold') || s.parseEndTag('ital', '_', 'afterItal') || s.parseEndTag('mono', '`', 'afterMono');
28069
28070 if (!parsed) {
28071 s.add(ch);
28072 beginable = false;
28073 }
28074
28075 s.position++;
28076 }
28077
28078 s.emitBlock();
28079 return s.blocks;
28080 }
28081 /**
28082 * Explodes a piece of text into single-font blocks using a given markup
28083 *
28084 * @param {string} text
28085 * @param {boolean|'md'|'markdown'|'html'} markupSystem
28086 * @returns {Array.<{text: string, mod: string}>}
28087 * @private
28088 */
28089
28090 }, {
28091 key: "splitBlocks",
28092 value: function splitBlocks(text, markupSystem) {
28093 var system = this.decodeMarkupSystem(markupSystem);
28094
28095 if (system === 'none') {
28096 return [{
28097 text: text,
28098 mod: 'normal'
28099 }];
28100 } else if (system === 'markdown') {
28101 return this.splitMarkdownBlocks(text);
28102 } else if (system === 'html') {
28103 return this.splitHtmlBlocks(text);
28104 }
28105 }
28106 /**
28107 * @param {string} text
28108 * @returns {boolean} true if text length over the current max with
28109 * @private
28110 */
28111
28112 }, {
28113 key: "overMaxWidth",
28114 value: function overMaxWidth(text) {
28115 var width = this.ctx.measureText(text).width;
28116 return this.lines.curWidth() + width > this.parent.fontOptions.maxWdt;
28117 }
28118 /**
28119 * Determine the longest part of the sentence which still fits in the
28120 * current max width.
28121 *
28122 * @param {Array} words Array of strings signifying a text lines
28123 * @return {number} index of first item in string making string go over max
28124 * @private
28125 */
28126
28127 }, {
28128 key: "getLongestFit",
28129 value: function getLongestFit(words) {
28130 var text = '';
28131 var w = 0;
28132
28133 while (w < words.length) {
28134 var pre = text === '' ? '' : ' ';
28135 var newText = text + pre + words[w];
28136 if (this.overMaxWidth(newText)) break;
28137 text = newText;
28138 w++;
28139 }
28140
28141 return w;
28142 }
28143 /**
28144 * Determine the longest part of the string which still fits in the
28145 * current max width.
28146 *
28147 * @param {Array} words Array of strings signifying a text lines
28148 * @return {number} index of first item in string making string go over max
28149 */
28150
28151 }, {
28152 key: "getLongestFitWord",
28153 value: function getLongestFitWord(words) {
28154 var w = 0;
28155
28156 while (w < words.length) {
28157 if (this.overMaxWidth(words.slice(0, w))) break;
28158 w++;
28159 }
28160
28161 return w;
28162 }
28163 /**
28164 * Split the passed text into lines, according to width constraint (if any).
28165 *
28166 * The method assumes that the input string is a single line, i.e. without lines break.
28167 *
28168 * This method retains spaces, if still present (case `font.multi: false`).
28169 * A space which falls on an internal line break, will be replaced by a newline.
28170 * There is no special handling of tabs; these go along with the flow.
28171 *
28172 * @param {string} str
28173 * @param {string} [mod='normal']
28174 * @param {boolean} [appendLast=false]
28175 * @private
28176 */
28177
28178 }, {
28179 key: "splitStringIntoLines",
28180 value: function splitStringIntoLines(str) {
28181 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'normal';
28182 var appendLast = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
28183 // Set the canvas context font, based upon the current selected/hover state
28184 // and the provided mod, so the text measurement performed by getLongestFit
28185 // will be accurate - and not just use the font of whoever last used the canvas.
28186 this.parent.getFormattingValues(this.ctx, this.selected, this.hover, mod); // Still-present spaces are relevant, retain them
28187
28188 str = str.replace(/^( +)/g, '$1\r');
28189 str = str.replace(/([^\r][^ ]*)( +)/g, '$1\r$2\r');
28190 var words = str.split('\r');
28191
28192 while (words.length > 0) {
28193 var w = this.getLongestFit(words);
28194
28195 if (w === 0) {
28196 // Special case: the first word is already larger than the max width.
28197 var word = words[0]; // Break the word to the largest part that fits the line
28198
28199 var x = this.getLongestFitWord(word);
28200 this.lines.newLine(word.slice(0, x), mod); // Adjust the word, so that the rest will be done next iteration
28201
28202 words[0] = word.slice(x);
28203 } else {
28204 // skip any space that is replaced by a newline
28205 var newW = w;
28206
28207 if (words[w - 1] === ' ') {
28208 w--;
28209 } else if (words[newW] === ' ') {
28210 newW++;
28211 }
28212
28213 var text = words.slice(0, w).join("");
28214
28215 if (w == words.length && appendLast) {
28216 this.lines.append(text, mod);
28217 } else {
28218 this.lines.newLine(text, mod);
28219 } // Adjust the word, so that the rest will be done next iteration
28220
28221
28222 words = words.slice(newW);
28223 }
28224 }
28225 }
28226 }]);
28227
28228 return LabelSplitter;
28229 }();
28230
28231 /**
28232 * List of special styles for multi-fonts
28233 * @private
28234 */
28235
28236 var multiFontStyle = ['bold', 'ital', 'boldital', 'mono'];
28237 /**
28238 * A Label to be used for Nodes or Edges.
28239 */
28240
28241 var Label =
28242 /*#__PURE__*/
28243 function () {
28244 /**
28245 * @param {Object} body
28246 * @param {Object} options
28247 * @param {boolean} [edgelabel=false]
28248 */
28249 function Label(body, options) {
28250 var edgelabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
28251
28252 _classCallCheck(this, Label);
28253
28254 this.body = body;
28255 this.pointToSelf = false;
28256 this.baseSize = undefined;
28257 this.fontOptions = {}; // instance variable containing the *instance-local* font options
28258
28259 this.setOptions(options);
28260 this.size = {
28261 top: 0,
28262 left: 0,
28263 width: 0,
28264 height: 0,
28265 yLine: 0
28266 };
28267 this.isEdgeLabel = edgelabel;
28268 }
28269 /**
28270 * @param {Object} options the options of the parent Node-instance
28271 */
28272
28273
28274 _createClass(Label, [{
28275 key: "setOptions",
28276 value: function setOptions(options) {
28277 this.elementOptions = options; // Reference to the options of the parent Node-instance
28278
28279 this.initFontOptions(options.font);
28280
28281 if (ComponentUtil.isValidLabel(options.label)) {
28282 this.labelDirty = true;
28283 } else {
28284 // Bad label! Change the option value to prevent bad stuff happening
28285 options.label = undefined;
28286 }
28287
28288 if (options.font !== undefined && options.font !== null) {
28289 // font options can be deleted at various levels
28290 if (typeof options.font === 'string') {
28291 this.baseSize = this.fontOptions.size;
28292 } else if (_typeof$1(options.font) === 'object') {
28293 var size = options.font.size;
28294
28295 if (size !== undefined) {
28296 this.baseSize = size;
28297 }
28298 }
28299 }
28300 }
28301 /**
28302 * Init the font Options structure.
28303 *
28304 * Member fontOptions serves as an accumulator for the current font options.
28305 * As such, it needs to be completely separated from the node options.
28306 *
28307 * @param {Object} newFontOptions the new font options to process
28308 * @private
28309 */
28310
28311 }, {
28312 key: "initFontOptions",
28313 value: function initFontOptions(newFontOptions) {
28314 var _this = this;
28315
28316 // Prepare the multi-font option objects.
28317 // These will be filled in propagateFonts(), if required
28318 forEach(multiFontStyle, function (style) {
28319 _this.fontOptions[style] = {};
28320 }); // Handle shorthand option, if present
28321
28322 if (Label.parseFontString(this.fontOptions, newFontOptions)) {
28323 this.fontOptions.vadjust = 0;
28324 return;
28325 } // Copy over the non-multifont options, if specified
28326
28327
28328 forEach(newFontOptions, function (prop, n) {
28329 if (prop !== undefined && prop !== null && _typeof$1(prop) !== 'object') {
28330 _this.fontOptions[n] = prop;
28331 }
28332 });
28333 }
28334 /**
28335 * If in-variable is a string, parse it as a font specifier.
28336 *
28337 * Note that following is not done here and have to be done after the call:
28338 * - Not all font options are set (vadjust, mod)
28339 *
28340 * @param {Object} outOptions out-parameter, object in which to store the parse results (if any)
28341 * @param {Object} inOptions font options to parse
28342 * @return {boolean} true if font parsed as string, false otherwise
28343 * @static
28344 */
28345
28346 }, {
28347 key: "constrain",
28348
28349 /**
28350 * Set the width and height constraints based on 'nearest' value
28351 *
28352 * @param {Array} pile array of option objects to consider
28353 * @returns {object} the actual constraint values to use
28354 * @private
28355 */
28356 value: function constrain(pile) {
28357 // NOTE: constrainWidth and constrainHeight never set!
28358 // NOTE: for edge labels, only 'maxWdt' set
28359 // Node labels can set all the fields
28360 var fontOptions = {
28361 constrainWidth: false,
28362 maxWdt: -1,
28363 minWdt: -1,
28364 constrainHeight: false,
28365 minHgt: -1,
28366 valign: 'middle'
28367 };
28368 var widthConstraint = topMost(pile, 'widthConstraint');
28369
28370 if (typeof widthConstraint === 'number') {
28371 fontOptions.maxWdt = Number(widthConstraint);
28372 fontOptions.minWdt = Number(widthConstraint);
28373 } else if (_typeof$1(widthConstraint) === 'object') {
28374 var widthConstraintMaximum = topMost(pile, ['widthConstraint', 'maximum']);
28375
28376 if (typeof widthConstraintMaximum === 'number') {
28377 fontOptions.maxWdt = Number(widthConstraintMaximum);
28378 }
28379
28380 var widthConstraintMinimum = topMost(pile, ['widthConstraint', 'minimum']);
28381
28382 if (typeof widthConstraintMinimum === 'number') {
28383 fontOptions.minWdt = Number(widthConstraintMinimum);
28384 }
28385 }
28386
28387 var heightConstraint = topMost(pile, 'heightConstraint');
28388
28389 if (typeof heightConstraint === 'number') {
28390 fontOptions.minHgt = Number(heightConstraint);
28391 } else if (_typeof$1(heightConstraint) === 'object') {
28392 var heightConstraintMinimum = topMost(pile, ['heightConstraint', 'minimum']);
28393
28394 if (typeof heightConstraintMinimum === 'number') {
28395 fontOptions.minHgt = Number(heightConstraintMinimum);
28396 }
28397
28398 var heightConstraintValign = topMost(pile, ['heightConstraint', 'valign']);
28399
28400 if (typeof heightConstraintValign === 'string') {
28401 if (heightConstraintValign === 'top' || heightConstraintValign === 'bottom') {
28402 fontOptions.valign = heightConstraintValign;
28403 }
28404 }
28405 }
28406
28407 return fontOptions;
28408 }
28409 /**
28410 * Set options and update internal state
28411 *
28412 * @param {Object} options options to set
28413 * @param {Array} pile array of option objects to consider for option 'chosen'
28414 */
28415
28416 }, {
28417 key: "update",
28418 value: function update(options, pile) {
28419 this.setOptions(options, true);
28420 this.propagateFonts(pile);
28421 deepExtend(this.fontOptions, this.constrain(pile));
28422 this.fontOptions.chooser = ComponentUtil.choosify('label', pile);
28423 }
28424 /**
28425 * When margins are set in an element, adjust sizes is called to remove them
28426 * from the width/height constraints. This must be done prior to label sizing.
28427 *
28428 * @param {{top: number, right: number, bottom: number, left: number}} margins
28429 */
28430
28431 }, {
28432 key: "adjustSizes",
28433 value: function adjustSizes(margins) {
28434 var widthBias = margins ? margins.right + margins.left : 0;
28435
28436 if (this.fontOptions.constrainWidth) {
28437 this.fontOptions.maxWdt -= widthBias;
28438 this.fontOptions.minWdt -= widthBias;
28439 }
28440
28441 var heightBias = margins ? margins.top + margins.bottom : 0;
28442
28443 if (this.fontOptions.constrainHeight) {
28444 this.fontOptions.minHgt -= heightBias;
28445 }
28446 } /////////////////////////////////////////////////////////
28447 // Methods for handling options piles
28448 // Eventually, these will be moved to a separate class
28449 /////////////////////////////////////////////////////////
28450
28451 /**
28452 * Add the font members of the passed list of option objects to the pile.
28453 *
28454 * @param {Pile} dstPile pile of option objects add to
28455 * @param {Pile} srcPile pile of option objects to take font options from
28456 * @private
28457 */
28458
28459 }, {
28460 key: "addFontOptionsToPile",
28461 value: function addFontOptionsToPile(dstPile, srcPile) {
28462 for (var i = 0; i < srcPile.length; ++i) {
28463 this.addFontToPile(dstPile, srcPile[i]);
28464 }
28465 }
28466 /**
28467 * Add given font option object to the list of objects (the 'pile') to consider for determining
28468 * multi-font option values.
28469 *
28470 * @param {Pile} pile pile of option objects to use
28471 * @param {object} options instance to add to pile
28472 * @private
28473 */
28474
28475 }, {
28476 key: "addFontToPile",
28477 value: function addFontToPile(pile, options) {
28478 if (options === undefined) return;
28479 if (options.font === undefined || options.font === null) return;
28480 var item = options.font;
28481 pile.push(item);
28482 }
28483 /**
28484 * Collect all own-property values from the font pile that aren't multi-font option objectss.
28485 *
28486 * @param {Pile} pile pile of option objects to use
28487 * @returns {object} object with all current own basic font properties
28488 * @private
28489 */
28490
28491 }, {
28492 key: "getBasicOptions",
28493 value: function getBasicOptions(pile) {
28494 var ret = {}; // Scans the whole pile to get all options present
28495
28496 for (var n = 0; n < pile.length; ++n) {
28497 var fontOptions = pile[n]; // Convert shorthand if necessary
28498
28499 var tmpShorthand = {};
28500
28501 if (Label.parseFontString(tmpShorthand, fontOptions)) {
28502 fontOptions = tmpShorthand;
28503 }
28504
28505 forEach(fontOptions, function (opt, name) {
28506 if (opt === undefined) return; // multi-font option need not be present
28507
28508 if (ret.hasOwnProperty(name)) return; // Keep first value we encounter
28509
28510 if (multiFontStyle.indexOf(name) !== -1) {
28511 // Skip multi-font properties but we do need the structure
28512 ret[name] = {};
28513 } else {
28514 ret[name] = opt;
28515 }
28516 });
28517 }
28518
28519 return ret;
28520 }
28521 /**
28522 * Return the value for given option for the given multi-font.
28523 *
28524 * All available option objects are trawled in the set order to construct the option values.
28525 *
28526 * ---------------------------------------------------------------------
28527 * ## Traversal of pile for multi-fonts
28528 *
28529 * The determination of multi-font option values is a special case, because any values not
28530 * present in the multi-font options should by definition be taken from the main font options,
28531 * i.e. from the current 'parent' object of the multi-font option.
28532 *
28533 * ### Search order for multi-fonts
28534 *
28535 * 'bold' used as example:
28536 *
28537 * - search in option group 'bold' in local properties
28538 * - search in main font option group in local properties
28539 *
28540 * ---------------------------------------------------------------------
28541 *
28542 * @param {Pile} pile pile of option objects to use
28543 * @param {MultiFontStyle} multiName sub path for the multi-font
28544 * @param {string} option the option to search for, for the given multi-font
28545 * @returns {string|number} the value for the given option
28546 * @private
28547 */
28548
28549 }, {
28550 key: "getFontOption",
28551 value: function getFontOption(pile, multiName, option) {
28552 var multiFont; // Search multi font in local properties
28553
28554 for (var n = 0; n < pile.length; ++n) {
28555 var fontOptions = pile[n];
28556
28557 if (fontOptions.hasOwnProperty(multiName)) {
28558 multiFont = fontOptions[multiName];
28559 if (multiFont === undefined || multiFont === null) continue; // Convert shorthand if necessary
28560 // TODO: inefficient to do this conversion every time; find a better way.
28561
28562 var tmpShorthand = {};
28563
28564 if (Label.parseFontString(tmpShorthand, multiFont)) {
28565 multiFont = tmpShorthand;
28566 }
28567
28568 if (multiFont.hasOwnProperty(option)) {
28569 return multiFont[option];
28570 }
28571 }
28572 } // Option is not mentioned in the multi font options; take it from the parent font options.
28573 // These have already been converted with getBasicOptions(), so use the converted values.
28574
28575
28576 if (this.fontOptions.hasOwnProperty(option)) {
28577 return this.fontOptions[option];
28578 } // A value **must** be found; you should never get here.
28579
28580
28581 throw new Error("Did not find value for multi-font for property: '" + option + "'");
28582 }
28583 /**
28584 * Return all options values for the given multi-font.
28585 *
28586 * All available option objects are trawled in the set order to construct the option values.
28587 *
28588 * @param {Pile} pile pile of option objects to use
28589 * @param {MultiFontStyle} multiName sub path for the mod-font
28590 * @returns {MultiFontOptions}
28591 * @private
28592 */
28593
28594 }, {
28595 key: "getFontOptions",
28596 value: function getFontOptions(pile, multiName) {
28597 var result = {};
28598 var optionNames = ['color', 'size', 'face', 'mod', 'vadjust']; // List of allowed options per multi-font
28599
28600 for (var i = 0; i < optionNames.length; ++i) {
28601 var mod = optionNames[i];
28602 result[mod] = this.getFontOption(pile, multiName, mod);
28603 }
28604
28605 return result;
28606 } /////////////////////////////////////////////////////////
28607 // End methods for handling options piles
28608 /////////////////////////////////////////////////////////
28609
28610 /**
28611 * Collapse the font options for the multi-font to single objects, from
28612 * the chain of option objects passed (the 'pile').
28613 *
28614 * @param {Pile} pile sequence of option objects to consider.
28615 * First item in list assumed to be the newly set options.
28616 */
28617
28618 }, {
28619 key: "propagateFonts",
28620 value: function propagateFonts(pile) {
28621 var _this2 = this;
28622
28623 var fontPile = []; // sequence of font objects to consider, order important
28624 // Note that this.elementOptions is not used here.
28625
28626 this.addFontOptionsToPile(fontPile, pile);
28627 this.fontOptions = this.getBasicOptions(fontPile); // We set multifont values even if multi === false, for consistency (things break otherwise)
28628
28629 var _loop = function _loop(i) {
28630 var mod = multiFontStyle[i];
28631 var modOptions = _this2.fontOptions[mod];
28632
28633 var tmpMultiFontOptions = _this2.getFontOptions(fontPile, mod); // Copy over found values
28634
28635
28636 forEach(tmpMultiFontOptions, function (option, n) {
28637 modOptions[n] = option;
28638 });
28639 modOptions.size = Number(modOptions.size);
28640 modOptions.vadjust = Number(modOptions.vadjust);
28641 };
28642
28643 for (var i = 0; i < multiFontStyle.length; ++i) {
28644 _loop(i);
28645 }
28646 }
28647 /**
28648 * Main function. This is called from anything that wants to draw a label.
28649 * @param {CanvasRenderingContext2D} ctx
28650 * @param {number} x
28651 * @param {number} y
28652 * @param {boolean} selected
28653 * @param {boolean} hover
28654 * @param {string} [baseline='middle']
28655 */
28656
28657 }, {
28658 key: "draw",
28659 value: function draw(ctx, x, y, selected, hover) {
28660 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'middle';
28661 // if no label, return
28662 if (this.elementOptions.label === undefined) return; // check if we have to render the label
28663
28664 var viewFontSize = this.fontOptions.size * this.body.view.scale;
28665 if (this.elementOptions.label && viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) return; // This ensures that there will not be HUGE letters on screen
28666 // by setting an upper limit on the visible text size (regardless of zoomLevel)
28667
28668 if (viewFontSize >= this.elementOptions.scaling.label.maxVisible) {
28669 viewFontSize = Number(this.elementOptions.scaling.label.maxVisible) / this.body.view.scale;
28670 } // update the size cache if required
28671
28672
28673 this.calculateLabelSize(ctx, selected, hover, x, y, baseline);
28674
28675 this._drawBackground(ctx);
28676
28677 this._drawText(ctx, x, this.size.yLine, baseline, viewFontSize);
28678 }
28679 /**
28680 * Draws the label background
28681 * @param {CanvasRenderingContext2D} ctx
28682 * @private
28683 */
28684
28685 }, {
28686 key: "_drawBackground",
28687 value: function _drawBackground(ctx) {
28688 if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") {
28689 ctx.fillStyle = this.fontOptions.background;
28690 var size = this.getSize();
28691 ctx.fillRect(size.left, size.top, size.width, size.height);
28692 }
28693 }
28694 /**
28695 *
28696 * @param {CanvasRenderingContext2D} ctx
28697 * @param {number} x
28698 * @param {number} y
28699 * @param {string} [baseline='middle']
28700 * @param {number} viewFontSize
28701 * @private
28702 */
28703
28704 }, {
28705 key: "_drawText",
28706 value: function _drawText(ctx, x, y) {
28707 var baseline = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'middle';
28708 var viewFontSize = arguments.length > 4 ? arguments[4] : undefined;
28709
28710 var _this$_setAlignment = this._setAlignment(ctx, x, y, baseline);
28711
28712 var _this$_setAlignment2 = _slicedToArray(_this$_setAlignment, 2);
28713
28714 x = _this$_setAlignment2[0];
28715 y = _this$_setAlignment2[1];
28716 ctx.textAlign = 'left';
28717 x = x - this.size.width / 2; // Shift label 1/2-distance to the left
28718
28719 if (this.fontOptions.valign && this.size.height > this.size.labelHeight) {
28720 if (this.fontOptions.valign === 'top') {
28721 y -= (this.size.height - this.size.labelHeight) / 2;
28722 }
28723
28724 if (this.fontOptions.valign === 'bottom') {
28725 y += (this.size.height - this.size.labelHeight) / 2;
28726 }
28727 } // draw the text
28728
28729
28730 for (var i = 0; i < this.lineCount; i++) {
28731 var line = this.lines[i];
28732
28733 if (line && line.blocks) {
28734 var width = 0;
28735
28736 if (this.isEdgeLabel || this.fontOptions.align === 'center') {
28737 width += (this.size.width - line.width) / 2;
28738 } else if (this.fontOptions.align === 'right') {
28739 width += this.size.width - line.width;
28740 }
28741
28742 for (var j = 0; j < line.blocks.length; j++) {
28743 var block = line.blocks[j];
28744 ctx.font = block.font;
28745
28746 var _this$_getColor = this._getColor(block.color, viewFontSize, block.strokeColor),
28747 _this$_getColor2 = _slicedToArray(_this$_getColor, 2),
28748 fontColor = _this$_getColor2[0],
28749 strokeColor = _this$_getColor2[1];
28750
28751 if (block.strokeWidth > 0) {
28752 ctx.lineWidth = block.strokeWidth;
28753 ctx.strokeStyle = strokeColor;
28754 ctx.lineJoin = 'round';
28755 }
28756
28757 ctx.fillStyle = fontColor;
28758
28759 if (block.strokeWidth > 0) {
28760 ctx.strokeText(block.text, x + width, y + block.vadjust);
28761 }
28762
28763 ctx.fillText(block.text, x + width, y + block.vadjust);
28764 width += block.width;
28765 }
28766
28767 y += line.height;
28768 }
28769 }
28770 }
28771 /**
28772 *
28773 * @param {CanvasRenderingContext2D} ctx
28774 * @param {number} x
28775 * @param {number} y
28776 * @param {string} baseline
28777 * @returns {Array.<number>}
28778 * @private
28779 */
28780
28781 }, {
28782 key: "_setAlignment",
28783 value: function _setAlignment(ctx, x, y, baseline) {
28784 // check for label alignment (for edges)
28785 // TODO: make alignment for nodes
28786 if (this.isEdgeLabel && this.fontOptions.align !== 'horizontal' && this.pointToSelf === false) {
28787 x = 0;
28788 y = 0;
28789 var lineMargin = 2;
28790
28791 if (this.fontOptions.align === 'top') {
28792 ctx.textBaseline = 'alphabetic';
28793 y -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
28794 } else if (this.fontOptions.align === 'bottom') {
28795 ctx.textBaseline = 'hanging';
28796 y += 2 * lineMargin; // distance from edge, required because we use hanging. Hanging has less difference between browsers
28797 } else {
28798 ctx.textBaseline = 'middle';
28799 }
28800 } else {
28801 ctx.textBaseline = baseline;
28802 }
28803
28804 return [x, y];
28805 }
28806 /**
28807 * fade in when relative scale is between threshold and threshold - 1.
28808 * If the relative scale would be smaller than threshold -1 the draw function would have returned before coming here.
28809 *
28810 * @param {string} color The font color to use
28811 * @param {number} viewFontSize
28812 * @param {string} initialStrokeColor
28813 * @returns {Array.<string>} An array containing the font color and stroke color
28814 * @private
28815 */
28816
28817 }, {
28818 key: "_getColor",
28819 value: function _getColor(color, viewFontSize, initialStrokeColor) {
28820 var fontColor = color || '#000000';
28821 var strokeColor = initialStrokeColor || '#ffffff';
28822
28823 if (viewFontSize <= this.elementOptions.scaling.label.drawThreshold) {
28824 var opacity = Math.max(0, Math.min(1, 1 - (this.elementOptions.scaling.label.drawThreshold - viewFontSize)));
28825 fontColor = overrideOpacity(fontColor, opacity);
28826 strokeColor = overrideOpacity(strokeColor, opacity);
28827 }
28828
28829 return [fontColor, strokeColor];
28830 }
28831 /**
28832 *
28833 * @param {CanvasRenderingContext2D} ctx
28834 * @param {boolean} selected
28835 * @param {boolean} hover
28836 * @returns {{width: number, height: number}}
28837 */
28838
28839 }, {
28840 key: "getTextSize",
28841 value: function getTextSize(ctx) {
28842 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
28843 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
28844
28845 this._processLabel(ctx, selected, hover);
28846
28847 return {
28848 width: this.size.width,
28849 height: this.size.height,
28850 lineCount: this.lineCount
28851 };
28852 }
28853 /**
28854 * Get the current dimensions of the label
28855 *
28856 * @return {rect}
28857 */
28858
28859 }, {
28860 key: "getSize",
28861 value: function getSize() {
28862 var lineMargin = 2;
28863 var x = this.size.left; // default values which might be overridden below
28864
28865 var y = this.size.top - 0.5 * lineMargin; // idem
28866
28867 if (this.isEdgeLabel) {
28868 var x2 = -this.size.width * 0.5;
28869
28870 switch (this.fontOptions.align) {
28871 case 'middle':
28872 x = x2;
28873 y = -this.size.height * 0.5;
28874 break;
28875
28876 case 'top':
28877 x = x2;
28878 y = -(this.size.height + lineMargin);
28879 break;
28880
28881 case 'bottom':
28882 x = x2;
28883 y = lineMargin;
28884 break;
28885 }
28886 }
28887
28888 var ret = {
28889 left: x,
28890 top: y,
28891 width: this.size.width,
28892 height: this.size.height
28893 };
28894 return ret;
28895 }
28896 /**
28897 *
28898 * @param {CanvasRenderingContext2D} ctx
28899 * @param {boolean} selected
28900 * @param {boolean} hover
28901 * @param {number} [x=0]
28902 * @param {number} [y=0]
28903 * @param {'middle'|'hanging'} [baseline='middle']
28904 */
28905
28906 }, {
28907 key: "calculateLabelSize",
28908 value: function calculateLabelSize(ctx, selected, hover) {
28909 var x = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
28910 var y = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
28911 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'middle';
28912
28913 this._processLabel(ctx, selected, hover);
28914
28915 this.size.left = x - this.size.width * 0.5;
28916 this.size.top = y - this.size.height * 0.5;
28917 this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size;
28918
28919 if (baseline === "hanging") {
28920 this.size.top += 0.5 * this.fontOptions.size;
28921 this.size.top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
28922
28923 this.size.yLine += 4; // distance from node
28924 }
28925 }
28926 /**
28927 *
28928 * @param {CanvasRenderingContext2D} ctx
28929 * @param {boolean} selected
28930 * @param {boolean} hover
28931 * @param {string} mod
28932 * @returns {{color, size, face, mod, vadjust, strokeWidth: *, strokeColor: (*|string|allOptions.edges.font.strokeColor|{string}|allOptions.nodes.font.strokeColor|Array)}}
28933 */
28934
28935 }, {
28936 key: "getFormattingValues",
28937 value: function getFormattingValues(ctx, selected, hover, mod) {
28938 var getValue = function getValue(fontOptions, mod, option) {
28939 if (mod === "normal") {
28940 if (option === 'mod') return "";
28941 return fontOptions[option];
28942 }
28943
28944 if (fontOptions[mod][option] !== undefined) {
28945 // Grumbl leaving out test on undefined equals false for ""
28946 return fontOptions[mod][option];
28947 } else {
28948 // Take from parent font option
28949 return fontOptions[option];
28950 }
28951 };
28952
28953 var values = {
28954 color: getValue(this.fontOptions, mod, 'color'),
28955 size: getValue(this.fontOptions, mod, 'size'),
28956 face: getValue(this.fontOptions, mod, 'face'),
28957 mod: getValue(this.fontOptions, mod, 'mod'),
28958 vadjust: getValue(this.fontOptions, mod, 'vadjust'),
28959 strokeWidth: this.fontOptions.strokeWidth,
28960 strokeColor: this.fontOptions.strokeColor
28961 };
28962
28963 if (selected || hover) {
28964 if (mod === "normal" && this.fontOptions.chooser === true && this.elementOptions.labelHighlightBold) {
28965 values.mod = 'bold';
28966 } else {
28967 if (typeof this.fontOptions.chooser === 'function') {
28968 this.fontOptions.chooser(values, this.elementOptions.id, selected, hover);
28969 }
28970 }
28971 }
28972
28973 var fontString = "";
28974
28975 if (values.mod !== undefined && values.mod !== "") {
28976 // safeguard for undefined - this happened
28977 fontString += values.mod + " ";
28978 }
28979
28980 fontString += values.size + "px " + values.face;
28981 ctx.font = fontString.replace(/"/g, "");
28982 values.font = ctx.font;
28983 values.height = values.size;
28984 return values;
28985 }
28986 /**
28987 *
28988 * @param {boolean} selected
28989 * @param {boolean} hover
28990 * @returns {boolean}
28991 */
28992
28993 }, {
28994 key: "differentState",
28995 value: function differentState(selected, hover) {
28996 return selected !== this.selectedState || hover !== this.hoverState;
28997 }
28998 /**
28999 * This explodes the passed text into lines and determines the width, height and number of lines.
29000 *
29001 * @param {CanvasRenderingContext2D} ctx
29002 * @param {boolean} selected
29003 * @param {boolean} hover
29004 * @param {string} inText the text to explode
29005 * @returns {{width, height, lines}|*}
29006 * @private
29007 */
29008
29009 }, {
29010 key: "_processLabelText",
29011 value: function _processLabelText(ctx, selected, hover, inText) {
29012 var splitter = new LabelSplitter(ctx, this, selected, hover);
29013 return splitter.process(inText);
29014 }
29015 /**
29016 * This explodes the label string into lines and sets the width, height and number of lines.
29017 * @param {CanvasRenderingContext2D} ctx
29018 * @param {boolean} selected
29019 * @param {boolean} hover
29020 * @private
29021 */
29022
29023 }, {
29024 key: "_processLabel",
29025 value: function _processLabel(ctx, selected, hover) {
29026 if (this.labelDirty === false && !this.differentState(selected, hover)) return;
29027
29028 var state = this._processLabelText(ctx, selected, hover, this.elementOptions.label);
29029
29030 if (this.fontOptions.minWdt > 0 && state.width < this.fontOptions.minWdt) {
29031 state.width = this.fontOptions.minWdt;
29032 }
29033
29034 this.size.labelHeight = state.height;
29035
29036 if (this.fontOptions.minHgt > 0 && state.height < this.fontOptions.minHgt) {
29037 state.height = this.fontOptions.minHgt;
29038 }
29039
29040 this.lines = state.lines;
29041 this.lineCount = state.lines.length;
29042 this.size.width = state.width;
29043 this.size.height = state.height;
29044 this.selectedState = selected;
29045 this.hoverState = hover;
29046 this.labelDirty = false;
29047 }
29048 /**
29049 * Check if this label is visible
29050 *
29051 * @return {boolean} true if this label will be show, false otherwise
29052 */
29053
29054 }, {
29055 key: "visible",
29056 value: function visible() {
29057 if (this.size.width === 0 || this.size.height === 0 || this.elementOptions.label === undefined) {
29058 return false; // nothing to display
29059 }
29060
29061 var viewFontSize = this.fontOptions.size * this.body.view.scale;
29062
29063 if (viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) {
29064 return false; // Too small or too far away to show
29065 }
29066
29067 return true;
29068 }
29069 }], [{
29070 key: "parseFontString",
29071 value: function parseFontString(outOptions, inOptions) {
29072 if (!inOptions || typeof inOptions !== 'string') return false;
29073 var newOptionsArray = inOptions.split(" ");
29074 outOptions.size = +newOptionsArray[0].replace("px", '');
29075 outOptions.face = newOptionsArray[1];
29076 outOptions.color = newOptionsArray[2];
29077 return true;
29078 }
29079 }]);
29080
29081 return Label;
29082 }();
29083
29084 // https://tc39.github.io/ecma262/#sec-array.prototype.fill
29085
29086 _export({
29087 target: 'Array',
29088 proto: true
29089 }, {
29090 fill: arrayFill
29091 }); // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
29092
29093 addToUnscopables('fill');
29094
29095 /**
29096 * The Base class for all Nodes.
29097 */
29098 var NodeBase =
29099 /*#__PURE__*/
29100 function () {
29101 /**
29102 * @param {Object} options
29103 * @param {Object} body
29104 * @param {Label} labelModule
29105 */
29106 function NodeBase(options, body, labelModule) {
29107 _classCallCheck(this, NodeBase);
29108
29109 this.body = body;
29110 this.labelModule = labelModule;
29111 this.setOptions(options);
29112 this.top = undefined;
29113 this.left = undefined;
29114 this.height = undefined;
29115 this.width = undefined;
29116 this.radius = undefined;
29117 this.margin = undefined;
29118 this.refreshNeeded = true;
29119 this.boundingBox = {
29120 top: 0,
29121 left: 0,
29122 right: 0,
29123 bottom: 0
29124 };
29125 }
29126 /**
29127 *
29128 * @param {Object} options
29129 */
29130
29131
29132 _createClass(NodeBase, [{
29133 key: "setOptions",
29134 value: function setOptions(options) {
29135 this.options = options;
29136 }
29137 /**
29138 *
29139 * @param {Label} labelModule
29140 * @private
29141 */
29142
29143 }, {
29144 key: "_setMargins",
29145 value: function _setMargins(labelModule) {
29146 this.margin = {};
29147
29148 if (this.options.margin) {
29149 if (_typeof$1(this.options.margin) == 'object') {
29150 this.margin.top = this.options.margin.top;
29151 this.margin.right = this.options.margin.right;
29152 this.margin.bottom = this.options.margin.bottom;
29153 this.margin.left = this.options.margin.left;
29154 } else {
29155 this.margin.top = this.options.margin;
29156 this.margin.right = this.options.margin;
29157 this.margin.bottom = this.options.margin;
29158 this.margin.left = this.options.margin;
29159 }
29160 }
29161
29162 labelModule.adjustSizes(this.margin);
29163 }
29164 /**
29165 *
29166 * @param {CanvasRenderingContext2D} ctx
29167 * @param {number} angle
29168 * @returns {number}
29169 * @private
29170 */
29171
29172 }, {
29173 key: "_distanceToBorder",
29174 value: function _distanceToBorder(ctx, angle) {
29175 var borderWidth = this.options.borderWidth;
29176 this.resize(ctx);
29177 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
29178 }
29179 /**
29180 *
29181 * @param {CanvasRenderingContext2D} ctx
29182 * @param {ArrowOptions} values
29183 */
29184
29185 }, {
29186 key: "enableShadow",
29187 value: function enableShadow(ctx, values) {
29188 if (values.shadow) {
29189 ctx.shadowColor = values.shadowColor;
29190 ctx.shadowBlur = values.shadowSize;
29191 ctx.shadowOffsetX = values.shadowX;
29192 ctx.shadowOffsetY = values.shadowY;
29193 }
29194 }
29195 /**
29196 *
29197 * @param {CanvasRenderingContext2D} ctx
29198 * @param {ArrowOptions} values
29199 */
29200
29201 }, {
29202 key: "disableShadow",
29203 value: function disableShadow(ctx, values) {
29204 if (values.shadow) {
29205 ctx.shadowColor = 'rgba(0,0,0,0)';
29206 ctx.shadowBlur = 0;
29207 ctx.shadowOffsetX = 0;
29208 ctx.shadowOffsetY = 0;
29209 }
29210 }
29211 /**
29212 *
29213 * @param {CanvasRenderingContext2D} ctx
29214 * @param {ArrowOptions} values
29215 */
29216
29217 }, {
29218 key: "enableBorderDashes",
29219 value: function enableBorderDashes(ctx, values) {
29220 if (values.borderDashes !== false) {
29221 if (ctx.setLineDash !== undefined) {
29222 var dashes = values.borderDashes;
29223
29224 if (dashes === true) {
29225 dashes = [5, 15];
29226 }
29227
29228 ctx.setLineDash(dashes);
29229 } else {
29230 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
29231 this.options.shapeProperties.borderDashes = false;
29232 values.borderDashes = false;
29233 }
29234 }
29235 }
29236 /**
29237 *
29238 * @param {CanvasRenderingContext2D} ctx
29239 * @param {ArrowOptions} values
29240 */
29241
29242 }, {
29243 key: "disableBorderDashes",
29244 value: function disableBorderDashes(ctx, values) {
29245 if (values.borderDashes !== false) {
29246 if (ctx.setLineDash !== undefined) {
29247 ctx.setLineDash([0]);
29248 } else {
29249 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
29250 this.options.shapeProperties.borderDashes = false;
29251 values.borderDashes = false;
29252 }
29253 }
29254 }
29255 /**
29256 * Determine if the shape of a node needs to be recalculated.
29257 *
29258 * @param {boolean} selected
29259 * @param {boolean} hover
29260 * @returns {boolean}
29261 * @protected
29262 */
29263
29264 }, {
29265 key: "needsRefresh",
29266 value: function needsRefresh(selected, hover) {
29267 if (this.refreshNeeded === true) {
29268 // This is probably not the best location to reset this member.
29269 // However, in the current logic, it is the most convenient one.
29270 this.refreshNeeded = false;
29271 return true;
29272 }
29273
29274 return this.width === undefined || this.labelModule.differentState(selected, hover);
29275 }
29276 /**
29277 *
29278 * @param {CanvasRenderingContext2D} ctx
29279 * @param {ArrowOptions} values
29280 */
29281
29282 }, {
29283 key: "initContextForDraw",
29284 value: function initContextForDraw(ctx, values) {
29285 var borderWidth = values.borderWidth / this.body.view.scale;
29286 ctx.lineWidth = Math.min(this.width, borderWidth);
29287 ctx.strokeStyle = values.borderColor;
29288 ctx.fillStyle = values.color;
29289 }
29290 /**
29291 *
29292 * @param {CanvasRenderingContext2D} ctx
29293 * @param {ArrowOptions} values
29294 */
29295
29296 }, {
29297 key: "performStroke",
29298 value: function performStroke(ctx, values) {
29299 var borderWidth = values.borderWidth / this.body.view.scale; //draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
29300
29301 ctx.save(); // if borders are zero width, they will be drawn with width 1 by default. This prevents that
29302
29303 if (borderWidth > 0) {
29304 this.enableBorderDashes(ctx, values); //draw the border
29305
29306 ctx.stroke(); //disable dashed border for other elements
29307
29308 this.disableBorderDashes(ctx, values);
29309 }
29310
29311 ctx.restore();
29312 }
29313 /**
29314 *
29315 * @param {CanvasRenderingContext2D} ctx
29316 * @param {ArrowOptions} values
29317 */
29318
29319 }, {
29320 key: "performFill",
29321 value: function performFill(ctx, values) {
29322 // draw shadow if enabled
29323 this.enableShadow(ctx, values); // draw the background
29324
29325 ctx.fill(); // disable shadows for other elements.
29326
29327 this.disableShadow(ctx, values);
29328 this.performStroke(ctx, values);
29329 }
29330 /**
29331 *
29332 * @param {number} margin
29333 * @private
29334 */
29335
29336 }, {
29337 key: "_addBoundingBoxMargin",
29338 value: function _addBoundingBoxMargin(margin) {
29339 this.boundingBox.left -= margin;
29340 this.boundingBox.top -= margin;
29341 this.boundingBox.bottom += margin;
29342 this.boundingBox.right += margin;
29343 }
29344 /**
29345 * Actual implementation of this method call.
29346 *
29347 * Doing it like this makes it easier to override
29348 * in the child classes.
29349 *
29350 * @param {number} x width
29351 * @param {number} y height
29352 * @param {CanvasRenderingContext2D} ctx
29353 * @param {boolean} selected
29354 * @param {boolean} hover
29355 * @private
29356 */
29357
29358 }, {
29359 key: "_updateBoundingBox",
29360 value: function _updateBoundingBox(x, y, ctx, selected, hover) {
29361 if (ctx !== undefined) {
29362 this.resize(ctx, selected, hover);
29363 }
29364
29365 this.left = x - this.width / 2;
29366 this.top = y - this.height / 2;
29367 this.boundingBox.left = this.left;
29368 this.boundingBox.top = this.top;
29369 this.boundingBox.bottom = this.top + this.height;
29370 this.boundingBox.right = this.left + this.width;
29371 }
29372 /**
29373 * Default implementation of this method call.
29374 * This acts as a stub which can be overridden.
29375 *
29376 * @param {number} x width
29377 * @param {number} y height
29378 * @param {CanvasRenderingContext2D} ctx
29379 * @param {boolean} selected
29380 * @param {boolean} hover
29381 */
29382
29383 }, {
29384 key: "updateBoundingBox",
29385 value: function updateBoundingBox(x, y, ctx, selected, hover) {
29386 this._updateBoundingBox(x, y, ctx, selected, hover);
29387 }
29388 /**
29389 * Determine the dimensions to use for nodes with an internal label
29390 *
29391 * Currently, these are: Circle, Ellipse, Database, Box
29392 * The other nodes have external labels, and will not call this method
29393 *
29394 * If there is no label, decent default values are supplied.
29395 *
29396 * @param {CanvasRenderingContext2D} ctx
29397 * @param {boolean} [selected]
29398 * @param {boolean} [hover]
29399 * @returns {{width:number, height:number}}
29400 */
29401
29402 }, {
29403 key: "getDimensionsFromLabel",
29404 value: function getDimensionsFromLabel(ctx, selected, hover) {
29405 // NOTE: previously 'textSize' was not put in 'this' for Ellipse
29406 // TODO: examine the consequences.
29407 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
29408 var width = this.textSize.width;
29409 var height = this.textSize.height;
29410 var DEFAULT_SIZE = 14;
29411
29412 if (width === 0) {
29413 // This happens when there is no label text set
29414 width = DEFAULT_SIZE; // use a decent default
29415
29416 height = DEFAULT_SIZE; // if width zero, then height also always zero
29417 }
29418
29419 return {
29420 width: width,
29421 height: height
29422 };
29423 }
29424 }]);
29425
29426 return NodeBase;
29427 }();
29428
29429 /**
29430 * A Box Node/Cluster shape.
29431 *
29432 * @extends NodeBase
29433 */
29434
29435 var Box =
29436 /*#__PURE__*/
29437 function (_NodeBase) {
29438 _inherits(Box, _NodeBase);
29439
29440 /**
29441 * @param {Object} options
29442 * @param {Object} body
29443 * @param {Label} labelModule
29444 */
29445 function Box(options, body, labelModule) {
29446 var _this;
29447
29448 _classCallCheck(this, Box);
29449
29450 _this = _possibleConstructorReturn(this, _getPrototypeOf(Box).call(this, options, body, labelModule));
29451
29452 _this._setMargins(labelModule);
29453
29454 return _this;
29455 }
29456 /**
29457 *
29458 * @param {CanvasRenderingContext2D} ctx
29459 * @param {boolean} [selected]
29460 * @param {boolean} [hover]
29461 */
29462
29463
29464 _createClass(Box, [{
29465 key: "resize",
29466 value: function resize(ctx) {
29467 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
29468 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
29469
29470 if (this.needsRefresh(selected, hover)) {
29471 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
29472 this.width = dimensions.width + this.margin.right + this.margin.left;
29473 this.height = dimensions.height + this.margin.top + this.margin.bottom;
29474 this.radius = this.width / 2;
29475 }
29476 }
29477 /**
29478 *
29479 * @param {CanvasRenderingContext2D} ctx
29480 * @param {number} x width
29481 * @param {number} y height
29482 * @param {boolean} selected
29483 * @param {boolean} hover
29484 * @param {ArrowOptions} values
29485 */
29486
29487 }, {
29488 key: "draw",
29489 value: function draw(ctx, x, y, selected, hover, values) {
29490 this.resize(ctx, selected, hover);
29491 this.left = x - this.width / 2;
29492 this.top = y - this.height / 2;
29493 this.initContextForDraw(ctx, values);
29494 ctx.roundRect(this.left, this.top, this.width, this.height, values.borderRadius);
29495 this.performFill(ctx, values);
29496 this.updateBoundingBox(x, y, ctx, selected, hover);
29497 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
29498 }
29499 /**
29500 *
29501 * @param {number} x width
29502 * @param {number} y height
29503 * @param {CanvasRenderingContext2D} ctx
29504 * @param {boolean} selected
29505 * @param {boolean} hover
29506 */
29507
29508 }, {
29509 key: "updateBoundingBox",
29510 value: function updateBoundingBox(x, y, ctx, selected, hover) {
29511 this._updateBoundingBox(x, y, ctx, selected, hover);
29512
29513 var borderRadius = this.options.shapeProperties.borderRadius; // only effective for box
29514
29515 this._addBoundingBoxMargin(borderRadius);
29516 }
29517 /**
29518 *
29519 * @param {CanvasRenderingContext2D} ctx
29520 * @param {number} angle
29521 * @returns {number}
29522 */
29523
29524 }, {
29525 key: "distanceToBorder",
29526 value: function distanceToBorder(ctx, angle) {
29527 this.resize(ctx);
29528 var borderWidth = this.options.borderWidth;
29529 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
29530 }
29531 }]);
29532
29533 return Box;
29534 }(NodeBase);
29535
29536 /**
29537 * NOTE: This is a bad base class
29538 *
29539 * Child classes are:
29540 *
29541 * Image - uses *only* image methods
29542 * Circle - uses *only* _drawRawCircle
29543 * CircleImage - uses all
29544 *
29545 * TODO: Refactor, move _drawRawCircle to different module, derive Circle from NodeBase
29546 * Rename this to ImageBase
29547 * Consolidate common code in Image and CircleImage to base class
29548 *
29549 * @extends NodeBase
29550 */
29551
29552 var CircleImageBase =
29553 /*#__PURE__*/
29554 function (_NodeBase) {
29555 _inherits(CircleImageBase, _NodeBase);
29556
29557 /**
29558 * @param {Object} options
29559 * @param {Object} body
29560 * @param {Label} labelModule
29561 */
29562 function CircleImageBase(options, body, labelModule) {
29563 var _this;
29564
29565 _classCallCheck(this, CircleImageBase);
29566
29567 _this = _possibleConstructorReturn(this, _getPrototypeOf(CircleImageBase).call(this, options, body, labelModule));
29568 _this.labelOffset = 0;
29569 _this.selected = false;
29570 return _this;
29571 }
29572 /**
29573 *
29574 * @param {Object} options
29575 * @param {Object} [imageObj]
29576 * @param {Object} [imageObjAlt]
29577 */
29578
29579
29580 _createClass(CircleImageBase, [{
29581 key: "setOptions",
29582 value: function setOptions(options, imageObj, imageObjAlt) {
29583 this.options = options;
29584
29585 if (!(imageObj === undefined && imageObjAlt === undefined)) {
29586 this.setImages(imageObj, imageObjAlt);
29587 }
29588 }
29589 /**
29590 * Set the images for this node.
29591 *
29592 * The images can be updated after the initial setting of options;
29593 * therefore, this method needs to be reentrant.
29594 *
29595 * For correct working in error cases, it is necessary to properly set
29596 * field 'nodes.brokenImage' in the options.
29597 *
29598 * @param {Image} imageObj required; main image to show for this node
29599 * @param {Image|undefined} imageObjAlt optional; image to show when node is selected
29600 */
29601
29602 }, {
29603 key: "setImages",
29604 value: function setImages(imageObj, imageObjAlt) {
29605 if (imageObjAlt && this.selected) {
29606 this.imageObj = imageObjAlt;
29607 this.imageObjAlt = imageObj;
29608 } else {
29609 this.imageObj = imageObj;
29610 this.imageObjAlt = imageObjAlt;
29611 }
29612 }
29613 /**
29614 * Set selection and switch between the base and the selected image.
29615 *
29616 * Do the switch only if imageObjAlt exists.
29617 *
29618 * @param {boolean} selected value of new selected state for current node
29619 */
29620
29621 }, {
29622 key: "switchImages",
29623 value: function switchImages(selected) {
29624 var selection_changed = selected && !this.selected || !selected && this.selected;
29625 this.selected = selected; // Remember new selection
29626
29627 if (this.imageObjAlt !== undefined && selection_changed) {
29628 var imageTmp = this.imageObj;
29629 this.imageObj = this.imageObjAlt;
29630 this.imageObjAlt = imageTmp;
29631 }
29632 }
29633 /**
29634 * Returns Image Padding from node options
29635 *
29636 * @returns {{top: number,left: number,bottom: number,right: number}} image padding inside this shape
29637 * @private
29638 */
29639
29640 }, {
29641 key: "_getImagePadding",
29642 value: function _getImagePadding() {
29643 var imgPadding = {
29644 top: 0,
29645 right: 0,
29646 bottom: 0,
29647 left: 0
29648 };
29649
29650 if (this.options.imagePadding) {
29651 var optImgPadding = this.options.imagePadding;
29652
29653 if (_typeof$1(optImgPadding) == 'object') {
29654 imgPadding.top = optImgPadding.top;
29655 imgPadding.right = optImgPadding.right;
29656 imgPadding.bottom = optImgPadding.bottom;
29657 imgPadding.left = optImgPadding.left;
29658 } else {
29659 imgPadding.top = optImgPadding;
29660 imgPadding.right = optImgPadding;
29661 imgPadding.bottom = optImgPadding;
29662 imgPadding.left = optImgPadding;
29663 }
29664 }
29665
29666 return imgPadding;
29667 }
29668 /**
29669 * Adjust the node dimensions for a loaded image.
29670 *
29671 * Pre: this.imageObj is valid
29672 */
29673
29674 }, {
29675 key: "_resizeImage",
29676 value: function _resizeImage() {
29677 var width, height;
29678
29679 if (this.options.shapeProperties.useImageSize === false) {
29680 // Use the size property
29681 var ratio_width = 1;
29682 var ratio_height = 1; // Only calculate the proper ratio if both width and height not zero
29683
29684 if (this.imageObj.width && this.imageObj.height) {
29685 if (this.imageObj.width > this.imageObj.height) {
29686 ratio_width = this.imageObj.width / this.imageObj.height;
29687 } else {
29688 ratio_height = this.imageObj.height / this.imageObj.width;
29689 }
29690 }
29691
29692 width = this.options.size * 2 * ratio_width;
29693 height = this.options.size * 2 * ratio_height;
29694 } else {
29695 // Use the image size with image padding
29696 var imgPadding = this._getImagePadding();
29697
29698 width = this.imageObj.width + imgPadding.left + imgPadding.right;
29699 height = this.imageObj.height + imgPadding.top + imgPadding.bottom;
29700 }
29701
29702 this.width = width;
29703 this.height = height;
29704 this.radius = 0.5 * this.width;
29705 }
29706 /**
29707 *
29708 * @param {CanvasRenderingContext2D} ctx
29709 * @param {number} x width
29710 * @param {number} y height
29711 * @param {ArrowOptions} values
29712 * @private
29713 */
29714
29715 }, {
29716 key: "_drawRawCircle",
29717 value: function _drawRawCircle(ctx, x, y, values) {
29718 this.initContextForDraw(ctx, values);
29719 ctx.circle(x, y, values.size);
29720 this.performFill(ctx, values);
29721 }
29722 /**
29723 *
29724 * @param {CanvasRenderingContext2D} ctx
29725 * @param {ArrowOptions} values
29726 * @private
29727 */
29728
29729 }, {
29730 key: "_drawImageAtPosition",
29731 value: function _drawImageAtPosition(ctx, values) {
29732 if (this.imageObj.width != 0) {
29733 // draw the image
29734 ctx.globalAlpha = 1.0; // draw shadow if enabled
29735
29736 this.enableShadow(ctx, values);
29737 var factor = 1;
29738
29739 if (this.options.shapeProperties.interpolation === true) {
29740 factor = this.imageObj.width / this.width / this.body.view.scale;
29741 }
29742
29743 var imgPadding = this._getImagePadding();
29744
29745 var imgPosLeft = this.left + imgPadding.left;
29746 var imgPosTop = this.top + imgPadding.top;
29747 var imgWidth = this.width - imgPadding.left - imgPadding.right;
29748 var imgHeight = this.height - imgPadding.top - imgPadding.bottom;
29749 this.imageObj.drawImageAtPosition(ctx, factor, imgPosLeft, imgPosTop, imgWidth, imgHeight); // disable shadows for other elements.
29750
29751 this.disableShadow(ctx, values);
29752 }
29753 }
29754 /**
29755 *
29756 * @param {CanvasRenderingContext2D} ctx
29757 * @param {number} x width
29758 * @param {number} y height
29759 * @param {boolean} selected
29760 * @param {boolean} hover
29761 * @private
29762 */
29763
29764 }, {
29765 key: "_drawImageLabel",
29766 value: function _drawImageLabel(ctx, x, y, selected, hover) {
29767 var yLabel;
29768 var offset = 0;
29769
29770 if (this.height !== undefined) {
29771 offset = this.height * 0.5;
29772 var labelDimensions = this.labelModule.getTextSize(ctx, selected, hover);
29773
29774 if (labelDimensions.lineCount >= 1) {
29775 offset += labelDimensions.height / 2;
29776 }
29777 }
29778
29779 yLabel = y + offset;
29780
29781 if (this.options.label) {
29782 this.labelOffset = offset;
29783 }
29784
29785 this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');
29786 }
29787 }]);
29788
29789 return CircleImageBase;
29790 }(NodeBase);
29791
29792 /**
29793 * A Circle Node/Cluster shape.
29794 *
29795 * @extends CircleImageBase
29796 */
29797
29798 var Circle =
29799 /*#__PURE__*/
29800 function (_CircleImageBase) {
29801 _inherits(Circle, _CircleImageBase);
29802
29803 /**
29804 * @param {Object} options
29805 * @param {Object} body
29806 * @param {Label} labelModule
29807 */
29808 function Circle(options, body, labelModule) {
29809 var _this;
29810
29811 _classCallCheck(this, Circle);
29812
29813 _this = _possibleConstructorReturn(this, _getPrototypeOf(Circle).call(this, options, body, labelModule));
29814
29815 _this._setMargins(labelModule);
29816
29817 return _this;
29818 }
29819 /**
29820 *
29821 * @param {CanvasRenderingContext2D} ctx
29822 * @param {boolean} [selected]
29823 * @param {boolean} [hover]
29824 */
29825
29826
29827 _createClass(Circle, [{
29828 key: "resize",
29829 value: function resize(ctx) {
29830 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
29831 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
29832
29833 if (this.needsRefresh(selected, hover)) {
29834 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
29835 var diameter = Math.max(dimensions.width + this.margin.right + this.margin.left, dimensions.height + this.margin.top + this.margin.bottom);
29836 this.options.size = diameter / 2; // NOTE: this size field only set here, not in Ellipse, Database, Box
29837
29838 this.width = diameter;
29839 this.height = diameter;
29840 this.radius = this.width / 2;
29841 }
29842 }
29843 /**
29844 *
29845 * @param {CanvasRenderingContext2D} ctx
29846 * @param {number} x width
29847 * @param {number} y height
29848 * @param {boolean} selected
29849 * @param {boolean} hover
29850 * @param {ArrowOptions} values
29851 */
29852
29853 }, {
29854 key: "draw",
29855 value: function draw(ctx, x, y, selected, hover, values) {
29856 this.resize(ctx, selected, hover);
29857 this.left = x - this.width / 2;
29858 this.top = y - this.height / 2;
29859
29860 this._drawRawCircle(ctx, x, y, values);
29861
29862 this.updateBoundingBox(x, y);
29863 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, y, selected, hover);
29864 }
29865 /**
29866 *
29867 * @param {number} x width
29868 * @param {number} y height
29869 */
29870
29871 }, {
29872 key: "updateBoundingBox",
29873 value: function updateBoundingBox(x, y) {
29874 this.boundingBox.top = y - this.options.size;
29875 this.boundingBox.left = x - this.options.size;
29876 this.boundingBox.right = x + this.options.size;
29877 this.boundingBox.bottom = y + this.options.size;
29878 }
29879 /**
29880 *
29881 * @param {CanvasRenderingContext2D} ctx
29882 * @param {number} angle - Unused
29883 * @returns {number}
29884 */
29885
29886 }, {
29887 key: "distanceToBorder",
29888 value: function distanceToBorder(ctx, angle) {
29889 // eslint-disable-line no-unused-vars
29890 this.resize(ctx);
29891 return this.width * 0.5;
29892 }
29893 }]);
29894
29895 return Circle;
29896 }(CircleImageBase);
29897
29898 /**
29899 * A CircularImage Node/Cluster shape.
29900 *
29901 * @extends CircleImageBase
29902 */
29903
29904 var CircularImage =
29905 /*#__PURE__*/
29906 function (_CircleImageBase) {
29907 _inherits(CircularImage, _CircleImageBase);
29908
29909 /**
29910 * @param {Object} options
29911 * @param {Object} body
29912 * @param {Label} labelModule
29913 * @param {Image} imageObj
29914 * @param {Image} imageObjAlt
29915 */
29916 function CircularImage(options, body, labelModule, imageObj, imageObjAlt) {
29917 var _this;
29918
29919 _classCallCheck(this, CircularImage);
29920
29921 _this = _possibleConstructorReturn(this, _getPrototypeOf(CircularImage).call(this, options, body, labelModule));
29922
29923 _this.setImages(imageObj, imageObjAlt);
29924
29925 return _this;
29926 }
29927 /**
29928 *
29929 * @param {CanvasRenderingContext2D} ctx
29930 * @param {boolean} [selected]
29931 * @param {boolean} [hover]
29932 */
29933
29934
29935 _createClass(CircularImage, [{
29936 key: "resize",
29937 value: function resize(ctx) {
29938 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
29939 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
29940 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
29941
29942 if (imageAbsent) {
29943 var diameter = this.options.size * 2;
29944 this.width = diameter;
29945 this.height = diameter;
29946 this.radius = 0.5 * this.width;
29947 return;
29948 } // At this point, an image is present, i.e. this.imageObj is valid.
29949
29950
29951 if (this.needsRefresh(selected, hover)) {
29952 this._resizeImage();
29953 }
29954 }
29955 /**
29956 *
29957 * @param {CanvasRenderingContext2D} ctx
29958 * @param {number} x width
29959 * @param {number} y height
29960 * @param {boolean} selected
29961 * @param {boolean} hover
29962 * @param {ArrowOptions} values
29963 */
29964
29965 }, {
29966 key: "draw",
29967 value: function draw(ctx, x, y, selected, hover, values) {
29968 this.switchImages(selected);
29969 this.resize();
29970 this.left = x - this.width / 2;
29971 this.top = y - this.height / 2; // draw the background circle. IMPORTANT: the stroke in this method is used by the clip method below.
29972
29973 this._drawRawCircle(ctx, x, y, values); // now we draw in the circle, we save so we can revert the clip operation after drawing.
29974
29975
29976 ctx.save(); // clip is used to use the stroke in drawRawCircle as an area that we can draw in.
29977
29978 ctx.clip(); // draw the image
29979
29980 this._drawImageAtPosition(ctx, values); // restore so we can again draw on the full canvas
29981
29982
29983 ctx.restore();
29984
29985 this._drawImageLabel(ctx, x, y, selected, hover);
29986
29987 this.updateBoundingBox(x, y);
29988 } // TODO: compare with Circle.updateBoundingBox(), consolidate? More stuff is happening here
29989
29990 /**
29991 *
29992 * @param {number} x width
29993 * @param {number} y height
29994 */
29995
29996 }, {
29997 key: "updateBoundingBox",
29998 value: function updateBoundingBox(x, y) {
29999 this.boundingBox.top = y - this.options.size;
30000 this.boundingBox.left = x - this.options.size;
30001 this.boundingBox.right = x + this.options.size;
30002 this.boundingBox.bottom = y + this.options.size; // TODO: compare with Image.updateBoundingBox(), consolidate?
30003
30004 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
30005 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
30006 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
30007 }
30008 /**
30009 *
30010 * @param {CanvasRenderingContext2D} ctx
30011 * @param {number} angle - Unused
30012 * @returns {number}
30013 */
30014
30015 }, {
30016 key: "distanceToBorder",
30017 value: function distanceToBorder(ctx, angle) {
30018 // eslint-disable-line no-unused-vars
30019 this.resize(ctx);
30020 return this.width * 0.5;
30021 }
30022 }]);
30023
30024 return CircularImage;
30025 }(CircleImageBase);
30026
30027 /**
30028 * A Database Node/Cluster shape.
30029 *
30030 * @extends NodeBase
30031 */
30032
30033 var Database =
30034 /*#__PURE__*/
30035 function (_NodeBase) {
30036 _inherits(Database, _NodeBase);
30037
30038 /**
30039 * @param {Object} options
30040 * @param {Object} body
30041 * @param {Label} labelModule
30042 */
30043 function Database(options, body, labelModule) {
30044 var _this;
30045
30046 _classCallCheck(this, Database);
30047
30048 _this = _possibleConstructorReturn(this, _getPrototypeOf(Database).call(this, options, body, labelModule));
30049
30050 _this._setMargins(labelModule);
30051
30052 return _this;
30053 }
30054 /**
30055 *
30056 * @param {CanvasRenderingContext2D} ctx
30057 * @param {boolean} selected
30058 * @param {boolean} hover
30059 */
30060
30061
30062 _createClass(Database, [{
30063 key: "resize",
30064 value: function resize(ctx, selected, hover) {
30065 if (this.needsRefresh(selected, hover)) {
30066 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
30067 var size = dimensions.width + this.margin.right + this.margin.left;
30068 this.width = size;
30069 this.height = size;
30070 this.radius = this.width / 2;
30071 }
30072 }
30073 /**
30074 *
30075 * @param {CanvasRenderingContext2D} ctx
30076 * @param {number} x width
30077 * @param {number} y height
30078 * @param {boolean} selected
30079 * @param {boolean} hover
30080 * @param {ArrowOptions} values
30081 */
30082
30083 }, {
30084 key: "draw",
30085 value: function draw(ctx, x, y, selected, hover, values) {
30086 this.resize(ctx, selected, hover);
30087 this.left = x - this.width / 2;
30088 this.top = y - this.height / 2;
30089 this.initContextForDraw(ctx, values);
30090 ctx.database(x - this.width / 2, y - this.height / 2, this.width, this.height);
30091 this.performFill(ctx, values);
30092 this.updateBoundingBox(x, y, ctx, selected, hover);
30093 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
30094 }
30095 /**
30096 *
30097 * @param {CanvasRenderingContext2D} ctx
30098 * @param {number} angle
30099 * @returns {number}
30100 */
30101
30102 }, {
30103 key: "distanceToBorder",
30104 value: function distanceToBorder(ctx, angle) {
30105 return this._distanceToBorder(ctx, angle);
30106 }
30107 }]);
30108
30109 return Database;
30110 }(NodeBase);
30111
30112 /**
30113 * Base class for constructing Node/Cluster Shapes.
30114 *
30115 * @extends NodeBase
30116 */
30117
30118 var ShapeBase =
30119 /*#__PURE__*/
30120 function (_NodeBase) {
30121 _inherits(ShapeBase, _NodeBase);
30122
30123 /**
30124 * @param {Object} options
30125 * @param {Object} body
30126 * @param {Label} labelModule
30127 */
30128 function ShapeBase(options, body, labelModule) {
30129 _classCallCheck(this, ShapeBase);
30130
30131 return _possibleConstructorReturn(this, _getPrototypeOf(ShapeBase).call(this, options, body, labelModule));
30132 }
30133 /**
30134 *
30135 * @param {CanvasRenderingContext2D} ctx
30136 * @param {boolean} [selected]
30137 * @param {boolean} [hover]
30138 * @param {Object} [values={size: this.options.size}]
30139 */
30140
30141
30142 _createClass(ShapeBase, [{
30143 key: "resize",
30144 value: function resize(ctx) {
30145 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
30146 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
30147 var values = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {
30148 size: this.options.size
30149 };
30150
30151 if (this.needsRefresh(selected, hover)) {
30152 this.labelModule.getTextSize(ctx, selected, hover);
30153 var size = 2 * values.size;
30154 this.width = size;
30155 this.height = size;
30156 this.radius = 0.5 * this.width;
30157 }
30158 }
30159 /**
30160 *
30161 * @param {CanvasRenderingContext2D} ctx
30162 * @param {string} shape
30163 * @param {number} sizeMultiplier - Unused! TODO: Remove next major release
30164 * @param {number} x
30165 * @param {number} y
30166 * @param {boolean} selected
30167 * @param {boolean} hover
30168 * @param {ArrowOptions} values
30169 * @private
30170 */
30171
30172 }, {
30173 key: "_drawShape",
30174 value: function _drawShape(ctx, shape, sizeMultiplier, x, y, selected, hover, values) {
30175 this.resize(ctx, selected, hover, values);
30176 this.left = x - this.width / 2;
30177 this.top = y - this.height / 2;
30178 this.initContextForDraw(ctx, values);
30179 ctx[shape](x, y, values.size);
30180 this.performFill(ctx, values);
30181
30182 if (this.options.icon !== undefined) {
30183 if (this.options.icon.code !== undefined) {
30184 ctx.font = (selected ? "bold " : "") + this.height / 2 + "px " + (this.options.icon.face || 'FontAwesome');
30185 ctx.fillStyle = this.options.icon.color || "black";
30186 ctx.textAlign = "center";
30187 ctx.textBaseline = "middle";
30188 ctx.fillText(this.options.icon.code, x, y);
30189 }
30190 }
30191
30192 if (this.options.label !== undefined) {
30193 // Need to call following here in order to ensure value for `this.labelModule.size.height`
30194 this.labelModule.calculateLabelSize(ctx, selected, hover, x, y, 'hanging');
30195 var yLabel = y + 0.5 * this.height + 0.5 * this.labelModule.size.height;
30196 this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');
30197 }
30198
30199 this.updateBoundingBox(x, y);
30200 }
30201 /**
30202 *
30203 * @param {number} x
30204 * @param {number} y
30205 */
30206
30207 }, {
30208 key: "updateBoundingBox",
30209 value: function updateBoundingBox(x, y) {
30210 this.boundingBox.top = y - this.options.size;
30211 this.boundingBox.left = x - this.options.size;
30212 this.boundingBox.right = x + this.options.size;
30213 this.boundingBox.bottom = y + this.options.size;
30214
30215 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
30216 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
30217 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
30218 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
30219 }
30220 }
30221 }]);
30222
30223 return ShapeBase;
30224 }(NodeBase);
30225
30226 /**
30227 * A Diamond Node/Cluster shape.
30228 *
30229 * @extends ShapeBase
30230 */
30231
30232 var Diamond =
30233 /*#__PURE__*/
30234 function (_ShapeBase) {
30235 _inherits(Diamond, _ShapeBase);
30236
30237 /**
30238 * @param {Object} options
30239 * @param {Object} body
30240 * @param {Label} labelModule
30241 */
30242 function Diamond(options, body, labelModule) {
30243 _classCallCheck(this, Diamond);
30244
30245 return _possibleConstructorReturn(this, _getPrototypeOf(Diamond).call(this, options, body, labelModule));
30246 }
30247 /**
30248 *
30249 * @param {CanvasRenderingContext2D} ctx
30250 * @param {number} x width
30251 * @param {number} y height
30252 * @param {boolean} selected
30253 * @param {boolean} hover
30254 * @param {ArrowOptions} values
30255 */
30256
30257
30258 _createClass(Diamond, [{
30259 key: "draw",
30260 value: function draw(ctx, x, y, selected, hover, values) {
30261 this._drawShape(ctx, 'diamond', 4, x, y, selected, hover, values);
30262 }
30263 /**
30264 *
30265 * @param {CanvasRenderingContext2D} ctx
30266 * @param {number} angle
30267 * @returns {number}
30268 */
30269
30270 }, {
30271 key: "distanceToBorder",
30272 value: function distanceToBorder(ctx, angle) {
30273 return this._distanceToBorder(ctx, angle);
30274 }
30275 }]);
30276
30277 return Diamond;
30278 }(ShapeBase);
30279
30280 /**
30281 * A Dot Node/Cluster shape.
30282 *
30283 * @extends ShapeBase
30284 */
30285
30286 var Dot =
30287 /*#__PURE__*/
30288 function (_ShapeBase) {
30289 _inherits(Dot, _ShapeBase);
30290
30291 /**
30292 * @param {Object} options
30293 * @param {Object} body
30294 * @param {Label} labelModule
30295 */
30296 function Dot(options, body, labelModule) {
30297 _classCallCheck(this, Dot);
30298
30299 return _possibleConstructorReturn(this, _getPrototypeOf(Dot).call(this, options, body, labelModule));
30300 }
30301 /**
30302 *
30303 * @param {CanvasRenderingContext2D} ctx
30304 * @param {number} x width
30305 * @param {number} y height
30306 * @param {boolean} selected
30307 * @param {boolean} hover
30308 * @param {ArrowOptions} values
30309 */
30310
30311
30312 _createClass(Dot, [{
30313 key: "draw",
30314 value: function draw(ctx, x, y, selected, hover, values) {
30315 this._drawShape(ctx, 'circle', 2, x, y, selected, hover, values);
30316 }
30317 /**
30318 *
30319 * @param {CanvasRenderingContext2D} ctx
30320 * @param {number} angle
30321 * @returns {number}
30322 */
30323
30324 }, {
30325 key: "distanceToBorder",
30326 value: function distanceToBorder(ctx, angle) {
30327 // eslint-disable-line no-unused-vars
30328 this.resize(ctx);
30329 return this.options.size;
30330 }
30331 }]);
30332
30333 return Dot;
30334 }(ShapeBase);
30335
30336 /**
30337 * Am Ellipse Node/Cluster shape.
30338 *
30339 * @extends NodeBase
30340 */
30341
30342 var Ellipse =
30343 /*#__PURE__*/
30344 function (_NodeBase) {
30345 _inherits(Ellipse, _NodeBase);
30346
30347 /**
30348 * @param {Object} options
30349 * @param {Object} body
30350 * @param {Label} labelModule
30351 */
30352 function Ellipse(options, body, labelModule) {
30353 _classCallCheck(this, Ellipse);
30354
30355 return _possibleConstructorReturn(this, _getPrototypeOf(Ellipse).call(this, options, body, labelModule));
30356 }
30357 /**
30358 *
30359 * @param {CanvasRenderingContext2D} ctx
30360 * @param {boolean} [selected]
30361 * @param {boolean} [hover]
30362 */
30363
30364
30365 _createClass(Ellipse, [{
30366 key: "resize",
30367 value: function resize(ctx) {
30368 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
30369 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
30370
30371 if (this.needsRefresh(selected, hover)) {
30372 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
30373 this.height = dimensions.height * 2;
30374 this.width = dimensions.width + dimensions.height;
30375 this.radius = 0.5 * this.width;
30376 }
30377 }
30378 /**
30379 *
30380 * @param {CanvasRenderingContext2D} ctx
30381 * @param {number} x width
30382 * @param {number} y height
30383 * @param {boolean} selected
30384 * @param {boolean} hover
30385 * @param {ArrowOptions} values
30386 */
30387
30388 }, {
30389 key: "draw",
30390 value: function draw(ctx, x, y, selected, hover, values) {
30391 this.resize(ctx, selected, hover);
30392 this.left = x - this.width * 0.5;
30393 this.top = y - this.height * 0.5;
30394 this.initContextForDraw(ctx, values);
30395 ctx.ellipse_vis(this.left, this.top, this.width, this.height);
30396 this.performFill(ctx, values);
30397 this.updateBoundingBox(x, y, ctx, selected, hover);
30398 this.labelModule.draw(ctx, x, y, selected, hover);
30399 }
30400 /**
30401 *
30402 * @param {CanvasRenderingContext2D} ctx
30403 * @param {number} angle
30404 * @returns {number}
30405 */
30406
30407 }, {
30408 key: "distanceToBorder",
30409 value: function distanceToBorder(ctx, angle) {
30410 this.resize(ctx);
30411 var a = this.width * 0.5;
30412 var b = this.height * 0.5;
30413 var w = Math.sin(angle) * a;
30414 var h = Math.cos(angle) * b;
30415 return a * b / Math.sqrt(w * w + h * h);
30416 }
30417 }]);
30418
30419 return Ellipse;
30420 }(NodeBase);
30421
30422 /**
30423 * An icon replacement for the default Node shape.
30424 *
30425 * @extends NodeBase
30426 */
30427
30428 var Icon =
30429 /*#__PURE__*/
30430 function (_NodeBase) {
30431 _inherits(Icon, _NodeBase);
30432
30433 /**
30434 * @param {Object} options
30435 * @param {Object} body
30436 * @param {Label} labelModule
30437 */
30438 function Icon(options, body, labelModule) {
30439 var _this;
30440
30441 _classCallCheck(this, Icon);
30442
30443 _this = _possibleConstructorReturn(this, _getPrototypeOf(Icon).call(this, options, body, labelModule));
30444
30445 _this._setMargins(labelModule);
30446
30447 return _this;
30448 }
30449 /**
30450 *
30451 * @param {CanvasRenderingContext2D} ctx - Unused.
30452 * @param {boolean} [selected]
30453 * @param {boolean} [hover]
30454 */
30455
30456
30457 _createClass(Icon, [{
30458 key: "resize",
30459 value: function resize(ctx, selected, hover) {
30460 if (this.needsRefresh(selected, hover)) {
30461 this.iconSize = {
30462 width: Number(this.options.icon.size),
30463 height: Number(this.options.icon.size)
30464 };
30465 this.width = this.iconSize.width + this.margin.right + this.margin.left;
30466 this.height = this.iconSize.height + this.margin.top + this.margin.bottom;
30467 this.radius = 0.5 * this.width;
30468 }
30469 }
30470 /**
30471 *
30472 * @param {CanvasRenderingContext2D} ctx
30473 * @param {number} x width
30474 * @param {number} y height
30475 * @param {boolean} selected
30476 * @param {boolean} hover
30477 * @param {ArrowOptions} values
30478 */
30479
30480 }, {
30481 key: "draw",
30482 value: function draw(ctx, x, y, selected, hover, values) {
30483 this.resize(ctx, selected, hover);
30484 this.options.icon.size = this.options.icon.size || 50;
30485 this.left = x - this.width / 2;
30486 this.top = y - this.height / 2;
30487
30488 this._icon(ctx, x, y, selected, hover, values);
30489
30490 if (this.options.label !== undefined) {
30491 var iconTextSpacing = 5;
30492 this.labelModule.draw(ctx, this.left + this.iconSize.width / 2 + this.margin.left, y + this.height / 2 + iconTextSpacing, selected);
30493 }
30494
30495 this.updateBoundingBox(x, y);
30496 }
30497 /**
30498 *
30499 * @param {number} x
30500 * @param {number} y
30501 */
30502
30503 }, {
30504 key: "updateBoundingBox",
30505 value: function updateBoundingBox(x, y) {
30506 this.boundingBox.top = y - this.options.icon.size * 0.5;
30507 this.boundingBox.left = x - this.options.icon.size * 0.5;
30508 this.boundingBox.right = x + this.options.icon.size * 0.5;
30509 this.boundingBox.bottom = y + this.options.icon.size * 0.5;
30510
30511 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
30512 var iconTextSpacing = 5;
30513 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
30514 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
30515 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height + iconTextSpacing);
30516 }
30517 }
30518 /**
30519 *
30520 * @param {CanvasRenderingContext2D} ctx
30521 * @param {number} x width
30522 * @param {number} y height
30523 * @param {boolean} selected
30524 * @param {boolean} hover - Unused
30525 * @param {ArrowOptions} values
30526 */
30527
30528 }, {
30529 key: "_icon",
30530 value: function _icon(ctx, x, y, selected, hover, values) {
30531 var iconSize = Number(this.options.icon.size);
30532
30533 if (this.options.icon.code !== undefined) {
30534 ctx.font = [this.options.icon.weight != null ? this.options.icon.weight : selected ? "bold" : "", // If the weight is forced (for example to make Font Awesome 5 work
30535 // properly) substitute slightly bigger size for bold font face.
30536 (this.options.icon.weight != null && selected ? 5 : 0) + iconSize + "px", this.options.icon.face].join(" "); // draw icon
30537
30538 ctx.fillStyle = this.options.icon.color || "black";
30539 ctx.textAlign = "center";
30540 ctx.textBaseline = "middle"; // draw shadow if enabled
30541
30542 this.enableShadow(ctx, values);
30543 ctx.fillText(this.options.icon.code, x, y); // disable shadows for other elements.
30544
30545 this.disableShadow(ctx, values);
30546 } else {
30547 console.error('When using the icon shape, you need to define the code in the icon options object. This can be done per node or globally.');
30548 }
30549 }
30550 /**
30551 *
30552 * @param {CanvasRenderingContext2D} ctx
30553 * @param {number} angle
30554 * @returns {number}
30555 */
30556
30557 }, {
30558 key: "distanceToBorder",
30559 value: function distanceToBorder(ctx, angle) {
30560 return this._distanceToBorder(ctx, angle);
30561 }
30562 }]);
30563
30564 return Icon;
30565 }(NodeBase);
30566
30567 /**
30568 * An image-based replacement for the default Node shape.
30569 *
30570 * @extends CircleImageBase
30571 */
30572
30573 var Image$1 =
30574 /*#__PURE__*/
30575 function (_CircleImageBase) {
30576 _inherits(Image, _CircleImageBase);
30577
30578 /**
30579 * @param {Object} options
30580 * @param {Object} body
30581 * @param {Label} labelModule
30582 * @param {Image} imageObj
30583 * @param {Image} imageObjAlt
30584 */
30585 function Image(options, body, labelModule, imageObj, imageObjAlt) {
30586 var _this;
30587
30588 _classCallCheck(this, Image);
30589
30590 _this = _possibleConstructorReturn(this, _getPrototypeOf(Image).call(this, options, body, labelModule));
30591
30592 _this.setImages(imageObj, imageObjAlt);
30593
30594 return _this;
30595 }
30596 /**
30597 *
30598 * @param {CanvasRenderingContext2D} ctx - Unused.
30599 * @param {boolean} [selected]
30600 * @param {boolean} [hover]
30601 */
30602
30603
30604 _createClass(Image, [{
30605 key: "resize",
30606 value: function resize(ctx) {
30607 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
30608 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
30609 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
30610
30611 if (imageAbsent) {
30612 var side = this.options.size * 2;
30613 this.width = side;
30614 this.height = side;
30615 return;
30616 }
30617
30618 if (this.needsRefresh(selected, hover)) {
30619 this._resizeImage();
30620 }
30621 }
30622 /**
30623 *
30624 * @param {CanvasRenderingContext2D} ctx
30625 * @param {number} x width
30626 * @param {number} y height
30627 * @param {boolean} selected
30628 * @param {boolean} hover
30629 * @param {ArrowOptions} values
30630 */
30631
30632 }, {
30633 key: "draw",
30634 value: function draw(ctx, x, y, selected, hover, values) {
30635 this.switchImages(selected);
30636 this.resize();
30637 this.left = x - this.width / 2;
30638 this.top = y - this.height / 2;
30639
30640 if (this.options.shapeProperties.useBorderWithImage === true) {
30641 var neutralborderWidth = this.options.borderWidth;
30642 var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
30643 var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
30644 ctx.lineWidth = Math.min(this.width, borderWidth);
30645 ctx.beginPath(); // setup the line properties.
30646
30647 ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border; // set a fillstyle
30648
30649 ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background; // draw a rectangle to form the border around. This rectangle is filled so the opacity of a picture (in future vis releases?) can be used to tint the image
30650
30651 ctx.rect(this.left - 0.5 * ctx.lineWidth, this.top - 0.5 * ctx.lineWidth, this.width + ctx.lineWidth, this.height + ctx.lineWidth);
30652 ctx.fill();
30653 this.performStroke(ctx, values);
30654 ctx.closePath();
30655 }
30656
30657 this._drawImageAtPosition(ctx, values);
30658
30659 this._drawImageLabel(ctx, x, y, selected, hover);
30660
30661 this.updateBoundingBox(x, y);
30662 }
30663 /**
30664 *
30665 * @param {number} x
30666 * @param {number} y
30667 */
30668
30669 }, {
30670 key: "updateBoundingBox",
30671 value: function updateBoundingBox(x, y) {
30672 this.resize();
30673
30674 this._updateBoundingBox(x, y);
30675
30676 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
30677 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
30678 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
30679 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
30680 }
30681 }
30682 /**
30683 *
30684 * @param {CanvasRenderingContext2D} ctx
30685 * @param {number} angle
30686 * @returns {number}
30687 */
30688
30689 }, {
30690 key: "distanceToBorder",
30691 value: function distanceToBorder(ctx, angle) {
30692 return this._distanceToBorder(ctx, angle);
30693 }
30694 }]);
30695
30696 return Image;
30697 }(CircleImageBase);
30698
30699 /**
30700 * A Square Node/Cluster shape.
30701 *
30702 * @extends ShapeBase
30703 */
30704
30705 var Square =
30706 /*#__PURE__*/
30707 function (_ShapeBase) {
30708 _inherits(Square, _ShapeBase);
30709
30710 /**
30711 * @param {Object} options
30712 * @param {Object} body
30713 * @param {Label} labelModule
30714 */
30715 function Square(options, body, labelModule) {
30716 _classCallCheck(this, Square);
30717
30718 return _possibleConstructorReturn(this, _getPrototypeOf(Square).call(this, options, body, labelModule));
30719 }
30720 /**
30721 *
30722 * @param {CanvasRenderingContext2D} ctx
30723 * @param {number} x width
30724 * @param {number} y height
30725 * @param {boolean} selected
30726 * @param {boolean} hover
30727 * @param {ArrowOptions} values
30728 */
30729
30730
30731 _createClass(Square, [{
30732 key: "draw",
30733 value: function draw(ctx, x, y, selected, hover, values) {
30734 this._drawShape(ctx, 'square', 2, x, y, selected, hover, values);
30735 }
30736 /**
30737 *
30738 * @param {CanvasRenderingContext2D} ctx
30739 * @param {number} angle
30740 * @returns {number}
30741 */
30742
30743 }, {
30744 key: "distanceToBorder",
30745 value: function distanceToBorder(ctx, angle) {
30746 return this._distanceToBorder(ctx, angle);
30747 }
30748 }]);
30749
30750 return Square;
30751 }(ShapeBase);
30752
30753 /**
30754 * A Hexagon Node/Cluster shape.
30755 *
30756 * @extends ShapeBase
30757 */
30758
30759 var Hexagon =
30760 /*#__PURE__*/
30761 function (_ShapeBase) {
30762 _inherits(Hexagon, _ShapeBase);
30763
30764 /**
30765 * @param {Object} options
30766 * @param {Object} body
30767 * @param {Label} labelModule
30768 */
30769 function Hexagon(options, body, labelModule) {
30770 _classCallCheck(this, Hexagon);
30771
30772 return _possibleConstructorReturn(this, _getPrototypeOf(Hexagon).call(this, options, body, labelModule));
30773 }
30774 /**
30775 *
30776 * @param {CanvasRenderingContext2D} ctx
30777 * @param {number} x width
30778 * @param {number} y height
30779 * @param {boolean} selected
30780 * @param {boolean} hover
30781 * @param {ArrowOptions} values
30782 */
30783
30784
30785 _createClass(Hexagon, [{
30786 key: "draw",
30787 value: function draw(ctx, x, y, selected, hover, values) {
30788 this._drawShape(ctx, 'hexagon', 4, x, y, selected, hover, values);
30789 }
30790 /**
30791 *
30792 * @param {CanvasRenderingContext2D} ctx
30793 * @param {number} angle
30794 * @returns {number}
30795 */
30796
30797 }, {
30798 key: "distanceToBorder",
30799 value: function distanceToBorder(ctx, angle) {
30800 return this._distanceToBorder(ctx, angle);
30801 }
30802 }]);
30803
30804 return Hexagon;
30805 }(ShapeBase);
30806
30807 /**
30808 * A Star Node/Cluster shape.
30809 *
30810 * @extends ShapeBase
30811 */
30812
30813 var Star =
30814 /*#__PURE__*/
30815 function (_ShapeBase) {
30816 _inherits(Star, _ShapeBase);
30817
30818 /**
30819 * @param {Object} options
30820 * @param {Object} body
30821 * @param {Label} labelModule
30822 */
30823 function Star(options, body, labelModule) {
30824 _classCallCheck(this, Star);
30825
30826 return _possibleConstructorReturn(this, _getPrototypeOf(Star).call(this, options, body, labelModule));
30827 }
30828 /**
30829 *
30830 * @param {CanvasRenderingContext2D} ctx
30831 * @param {number} x width
30832 * @param {number} y height
30833 * @param {boolean} selected
30834 * @param {boolean} hover
30835 * @param {ArrowOptions} values
30836 */
30837
30838
30839 _createClass(Star, [{
30840 key: "draw",
30841 value: function draw(ctx, x, y, selected, hover, values) {
30842 this._drawShape(ctx, 'star', 4, x, y, selected, hover, values);
30843 }
30844 /**
30845 *
30846 * @param {CanvasRenderingContext2D} ctx
30847 * @param {number} angle
30848 * @returns {number}
30849 */
30850
30851 }, {
30852 key: "distanceToBorder",
30853 value: function distanceToBorder(ctx, angle) {
30854 return this._distanceToBorder(ctx, angle);
30855 }
30856 }]);
30857
30858 return Star;
30859 }(ShapeBase);
30860
30861 /**
30862 * A text-based replacement for the default Node shape.
30863 *
30864 * @extends NodeBase
30865 */
30866
30867 var Text =
30868 /*#__PURE__*/
30869 function (_NodeBase) {
30870 _inherits(Text, _NodeBase);
30871
30872 /**
30873 * @param {Object} options
30874 * @param {Object} body
30875 * @param {Label} labelModule
30876 */
30877 function Text(options, body, labelModule) {
30878 var _this;
30879
30880 _classCallCheck(this, Text);
30881
30882 _this = _possibleConstructorReturn(this, _getPrototypeOf(Text).call(this, options, body, labelModule));
30883
30884 _this._setMargins(labelModule);
30885
30886 return _this;
30887 }
30888 /**
30889 *
30890 * @param {CanvasRenderingContext2D} ctx
30891 * @param {boolean} selected
30892 * @param {boolean} hover
30893 */
30894
30895
30896 _createClass(Text, [{
30897 key: "resize",
30898 value: function resize(ctx, selected, hover) {
30899 if (this.needsRefresh(selected, hover)) {
30900 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
30901 this.width = this.textSize.width + this.margin.right + this.margin.left;
30902 this.height = this.textSize.height + this.margin.top + this.margin.bottom;
30903 this.radius = 0.5 * this.width;
30904 }
30905 }
30906 /**
30907 *
30908 * @param {CanvasRenderingContext2D} ctx
30909 * @param {number} x width
30910 * @param {number} y height
30911 * @param {boolean} selected
30912 * @param {boolean} hover
30913 * @param {ArrowOptions} values
30914 */
30915
30916 }, {
30917 key: "draw",
30918 value: function draw(ctx, x, y, selected, hover, values) {
30919 this.resize(ctx, selected, hover);
30920 this.left = x - this.width / 2;
30921 this.top = y - this.height / 2; // draw shadow if enabled
30922
30923 this.enableShadow(ctx, values);
30924 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover); // disable shadows for other elements.
30925
30926 this.disableShadow(ctx, values);
30927 this.updateBoundingBox(x, y, ctx, selected, hover);
30928 }
30929 /**
30930 *
30931 * @param {CanvasRenderingContext2D} ctx
30932 * @param {number} angle
30933 * @returns {number}
30934 */
30935
30936 }, {
30937 key: "distanceToBorder",
30938 value: function distanceToBorder(ctx, angle) {
30939 return this._distanceToBorder(ctx, angle);
30940 }
30941 }]);
30942
30943 return Text;
30944 }(NodeBase);
30945
30946 /**
30947 * A Triangle Node/Cluster shape.
30948 *
30949 * @extends ShapeBase
30950 */
30951
30952 var Triangle =
30953 /*#__PURE__*/
30954 function (_ShapeBase) {
30955 _inherits(Triangle, _ShapeBase);
30956
30957 /**
30958 * @param {Object} options
30959 * @param {Object} body
30960 * @param {Label} labelModule
30961 */
30962 function Triangle(options, body, labelModule) {
30963 _classCallCheck(this, Triangle);
30964
30965 return _possibleConstructorReturn(this, _getPrototypeOf(Triangle).call(this, options, body, labelModule));
30966 }
30967 /**
30968 *
30969 * @param {CanvasRenderingContext2D} ctx
30970 * @param {number} x
30971 * @param {number} y
30972 * @param {boolean} selected
30973 * @param {boolean} hover
30974 * @param {ArrowOptions} values
30975 */
30976
30977
30978 _createClass(Triangle, [{
30979 key: "draw",
30980 value: function draw(ctx, x, y, selected, hover, values) {
30981 this._drawShape(ctx, 'triangle', 3, x, y, selected, hover, values);
30982 }
30983 /**
30984 *
30985 * @param {CanvasRenderingContext2D} ctx
30986 * @param {number} angle
30987 * @returns {number}
30988 */
30989
30990 }, {
30991 key: "distanceToBorder",
30992 value: function distanceToBorder(ctx, angle) {
30993 return this._distanceToBorder(ctx, angle);
30994 }
30995 }]);
30996
30997 return Triangle;
30998 }(ShapeBase);
30999
31000 /**
31001 * A downward facing Triangle Node/Cluster shape.
31002 *
31003 * @extends ShapeBase
31004 */
31005
31006 var TriangleDown =
31007 /*#__PURE__*/
31008 function (_ShapeBase) {
31009 _inherits(TriangleDown, _ShapeBase);
31010
31011 /**
31012 * @param {Object} options
31013 * @param {Object} body
31014 * @param {Label} labelModule
31015 */
31016 function TriangleDown(options, body, labelModule) {
31017 _classCallCheck(this, TriangleDown);
31018
31019 return _possibleConstructorReturn(this, _getPrototypeOf(TriangleDown).call(this, options, body, labelModule));
31020 }
31021 /**
31022 *
31023 * @param {CanvasRenderingContext2D} ctx
31024 * @param {number} x
31025 * @param {number} y
31026 * @param {boolean} selected
31027 * @param {boolean} hover
31028 * @param {ArrowOptions} values
31029 */
31030
31031
31032 _createClass(TriangleDown, [{
31033 key: "draw",
31034 value: function draw(ctx, x, y, selected, hover, values) {
31035 this._drawShape(ctx, 'triangleDown', 3, x, y, selected, hover, values);
31036 }
31037 /**
31038 *
31039 * @param {CanvasRenderingContext2D} ctx
31040 * @param {number} angle
31041 * @returns {number}
31042 */
31043
31044 }, {
31045 key: "distanceToBorder",
31046 value: function distanceToBorder(ctx, angle) {
31047 return this._distanceToBorder(ctx, angle);
31048 }
31049 }]);
31050
31051 return TriangleDown;
31052 }(ShapeBase);
31053
31054 var DatePrototype = Date.prototype;
31055 var INVALID_DATE = 'Invalid Date';
31056 var TO_STRING$2 = 'toString';
31057 var nativeDateToString = DatePrototype[TO_STRING$2];
31058 var getTime = DatePrototype.getTime; // `Date.prototype.toString` method
31059 // https://tc39.github.io/ecma262/#sec-date.prototype.tostring
31060
31061 if (new Date(NaN) + '' != INVALID_DATE) {
31062 redefine(DatePrototype, TO_STRING$2, function toString() {
31063 var value = getTime.call(this); // eslint-disable-next-line no-self-compare
31064
31065 return value === value ? nativeDateToString.call(this) : INVALID_DATE;
31066 });
31067 }
31068
31069 var FAILS_ON_PRIMITIVES$1 = fails(function () {
31070 objectKeys(1);
31071 }); // `Object.keys` method
31072 // https://tc39.github.io/ecma262/#sec-object.keys
31073
31074 _export({
31075 target: 'Object',
31076 stat: true,
31077 forced: FAILS_ON_PRIMITIVES$1
31078 }, {
31079 keys: function keys(it) {
31080 return objectKeys(toObject(it));
31081 }
31082 });
31083
31084 var errorFound = false;
31085 var allOptions;
31086 var printStyle = 'background: #FFeeee; color: #dd0000';
31087 /**
31088 * Used to validate options.
31089 */
31090
31091 var Validator =
31092 /*#__PURE__*/
31093 function () {
31094 /**
31095 * @ignore
31096 */
31097 function Validator() {
31098 _classCallCheck(this, Validator);
31099 }
31100 /**
31101 * Main function to be called
31102 * @param {Object} options
31103 * @param {Object} referenceOptions
31104 * @param {Object} subObject
31105 * @returns {boolean}
31106 * @static
31107 */
31108
31109
31110 _createClass(Validator, null, [{
31111 key: "validate",
31112 value: function validate(options, referenceOptions, subObject) {
31113 errorFound = false;
31114 allOptions = referenceOptions;
31115 var usedOptions = referenceOptions;
31116
31117 if (subObject !== undefined) {
31118 usedOptions = referenceOptions[subObject];
31119 }
31120
31121 Validator.parse(options, usedOptions, []);
31122 return errorFound;
31123 }
31124 /**
31125 * Will traverse an object recursively and check every value
31126 * @param {Object} options
31127 * @param {Object} referenceOptions
31128 * @param {array} path | where to look for the actual option
31129 * @static
31130 */
31131
31132 }, {
31133 key: "parse",
31134 value: function parse(options, referenceOptions, path) {
31135 for (var option in options) {
31136 if (options.hasOwnProperty(option)) {
31137 Validator.check(option, options, referenceOptions, path);
31138 }
31139 }
31140 }
31141 /**
31142 * Check every value. If the value is an object, call the parse function on that object.
31143 * @param {string} option
31144 * @param {Object} options
31145 * @param {Object} referenceOptions
31146 * @param {array} path | where to look for the actual option
31147 * @static
31148 */
31149
31150 }, {
31151 key: "check",
31152 value: function check(option, options, referenceOptions, path) {
31153 if (referenceOptions[option] === undefined && referenceOptions.__any__ === undefined) {
31154 Validator.getSuggestion(option, referenceOptions, path);
31155 return;
31156 }
31157
31158 var referenceOption = option;
31159 var is_object = true;
31160
31161 if (referenceOptions[option] === undefined && referenceOptions.__any__ !== undefined) {
31162 // NOTE: This only triggers if the __any__ is in the top level of the options object.
31163 // THAT'S A REALLY BAD PLACE TO ALLOW IT!!!!
31164 // TODO: Examine if needed, remove if possible
31165 // __any__ is a wildcard. Any value is accepted and will be further analysed by reference.
31166 referenceOption = '__any__'; // if the any-subgroup is not a predefined object in the configurator,
31167 // we do not look deeper into the object.
31168
31169 is_object = Validator.getType(options[option]) === 'object';
31170 }
31171
31172 var refOptionObj = referenceOptions[referenceOption];
31173
31174 if (is_object && refOptionObj.__type__ !== undefined) {
31175 refOptionObj = refOptionObj.__type__;
31176 }
31177
31178 Validator.checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path);
31179 }
31180 /**
31181 *
31182 * @param {string} option | the option property
31183 * @param {Object} options | The supplied options object
31184 * @param {Object} referenceOptions | The reference options containing all options and their allowed formats
31185 * @param {string} referenceOption | Usually this is the same as option, except when handling an __any__ tag.
31186 * @param {string} refOptionObj | This is the type object from the reference options
31187 * @param {Array} path | where in the object is the option
31188 * @static
31189 */
31190
31191 }, {
31192 key: "checkFields",
31193 value: function checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path) {
31194 var log = function log(message) {
31195 console.log('%c' + message + Validator.printLocation(path, option), printStyle);
31196 };
31197
31198 var optionType = Validator.getType(options[option]);
31199 var refOptionType = refOptionObj[optionType];
31200
31201 if (refOptionType !== undefined) {
31202 // if the type is correct, we check if it is supposed to be one of a few select values
31203 if (Validator.getType(refOptionType) === 'array' && refOptionType.indexOf(options[option]) === -1) {
31204 log('Invalid option detected in "' + option + '".' + ' Allowed values are:' + Validator.print(refOptionType) + ' not "' + options[option] + '". ');
31205 errorFound = true;
31206 } else if (optionType === 'object' && referenceOption !== "__any__") {
31207 path = copyAndExtendArray(path, option);
31208 Validator.parse(options[option], referenceOptions[referenceOption], path);
31209 }
31210 } else if (refOptionObj['any'] === undefined) {
31211 // type of the field is incorrect and the field cannot be any
31212 log('Invalid type received for "' + option + '". Expected: ' + Validator.print(Object.keys(refOptionObj)) + '. Received [' + optionType + '] "' + options[option] + '"');
31213 errorFound = true;
31214 }
31215 }
31216 /**
31217 *
31218 * @param {Object|boolean|number|string|Array.<number>|Date|Node|Moment|undefined|null} object
31219 * @returns {string}
31220 * @static
31221 */
31222
31223 }, {
31224 key: "getType",
31225 value: function getType(object) {
31226 var type = _typeof$1(object);
31227
31228 if (type === 'object') {
31229 if (object === null) {
31230 return 'null';
31231 }
31232
31233 if (object instanceof Boolean) {
31234 return 'boolean';
31235 }
31236
31237 if (object instanceof Number) {
31238 return 'number';
31239 }
31240
31241 if (object instanceof String) {
31242 return 'string';
31243 }
31244
31245 if (Array.isArray(object)) {
31246 return 'array';
31247 }
31248
31249 if (object instanceof Date) {
31250 return 'date';
31251 }
31252
31253 if (object.nodeType !== undefined) {
31254 return 'dom';
31255 }
31256
31257 if (object._isAMomentObject === true) {
31258 return 'moment';
31259 }
31260
31261 return 'object';
31262 } else if (type === 'number') {
31263 return 'number';
31264 } else if (type === 'boolean') {
31265 return 'boolean';
31266 } else if (type === 'string') {
31267 return 'string';
31268 } else if (type === undefined) {
31269 return 'undefined';
31270 }
31271
31272 return type;
31273 }
31274 /**
31275 * @param {string} option
31276 * @param {Object} options
31277 * @param {Array.<string>} path
31278 * @static
31279 */
31280
31281 }, {
31282 key: "getSuggestion",
31283 value: function getSuggestion(option, options, path) {
31284 var localSearch = Validator.findInOptions(option, options, path, false);
31285 var globalSearch = Validator.findInOptions(option, allOptions, [], true);
31286 var localSearchThreshold = 8;
31287 var globalSearchThreshold = 4;
31288 var msg;
31289
31290 if (localSearch.indexMatch !== undefined) {
31291 msg = ' in ' + Validator.printLocation(localSearch.path, option, '') + 'Perhaps it was incomplete? Did you mean: "' + localSearch.indexMatch + '"?\n\n';
31292 } else if (globalSearch.distance <= globalSearchThreshold && localSearch.distance > globalSearch.distance) {
31293 msg = ' in ' + Validator.printLocation(localSearch.path, option, '') + 'Perhaps it was misplaced? Matching option found at: ' + Validator.printLocation(globalSearch.path, globalSearch.closestMatch, '');
31294 } else if (localSearch.distance <= localSearchThreshold) {
31295 msg = '. Did you mean "' + localSearch.closestMatch + '"?' + Validator.printLocation(localSearch.path, option);
31296 } else {
31297 msg = '. Did you mean one of these: ' + Validator.print(Object.keys(options)) + Validator.printLocation(path, option);
31298 }
31299
31300 console.log('%cUnknown option detected: "' + option + '"' + msg, printStyle);
31301 errorFound = true;
31302 }
31303 /**
31304 * traverse the options in search for a match.
31305 * @param {string} option
31306 * @param {Object} options
31307 * @param {Array} path | where to look for the actual option
31308 * @param {boolean} [recursive=false]
31309 * @returns {{closestMatch: string, path: Array, distance: number}}
31310 * @static
31311 */
31312
31313 }, {
31314 key: "findInOptions",
31315 value: function findInOptions(option, options, path) {
31316 var recursive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
31317 var min = 1e9;
31318 var closestMatch = '';
31319 var closestMatchPath = [];
31320 var lowerCaseOption = option.toLowerCase();
31321 var indexMatch = undefined;
31322
31323 for (var op in options) {
31324 // eslint-disable-line guard-for-in
31325 var distance = void 0;
31326
31327 if (options[op].__type__ !== undefined && recursive === true) {
31328 var result = Validator.findInOptions(option, options[op], copyAndExtendArray(path, op));
31329
31330 if (min > result.distance) {
31331 closestMatch = result.closestMatch;
31332 closestMatchPath = result.path;
31333 min = result.distance;
31334 indexMatch = result.indexMatch;
31335 }
31336 } else {
31337 if (op.toLowerCase().indexOf(lowerCaseOption) !== -1) {
31338 indexMatch = op;
31339 }
31340
31341 distance = Validator.levenshteinDistance(option, op);
31342
31343 if (min > distance) {
31344 closestMatch = op;
31345 closestMatchPath = copyArray(path);
31346 min = distance;
31347 }
31348 }
31349 }
31350
31351 return {
31352 closestMatch: closestMatch,
31353 path: closestMatchPath,
31354 distance: min,
31355 indexMatch: indexMatch
31356 };
31357 }
31358 /**
31359 * @param {Array.<string>} path
31360 * @param {Object} option
31361 * @param {string} prefix
31362 * @returns {String}
31363 * @static
31364 */
31365
31366 }, {
31367 key: "printLocation",
31368 value: function printLocation(path, option) {
31369 var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'Problem value found at: \n';
31370 var str = '\n\n' + prefix + 'options = {\n';
31371
31372 for (var i = 0; i < path.length; i++) {
31373 for (var j = 0; j < i + 1; j++) {
31374 str += ' ';
31375 }
31376
31377 str += path[i] + ': {\n';
31378 }
31379
31380 for (var _j = 0; _j < path.length + 1; _j++) {
31381 str += ' ';
31382 }
31383
31384 str += option + '\n';
31385
31386 for (var _i = 0; _i < path.length + 1; _i++) {
31387 for (var _j2 = 0; _j2 < path.length - _i; _j2++) {
31388 str += ' ';
31389 }
31390
31391 str += '}\n';
31392 }
31393
31394 return str + '\n\n';
31395 }
31396 /**
31397 * @param {Object} options
31398 * @returns {String}
31399 * @static
31400 */
31401
31402 }, {
31403 key: "print",
31404 value: function print(options) {
31405 return JSON.stringify(options).replace(/(\")|(\[)|(\])|(,"__type__")/g, "").replace(/(\,)/g, ', ');
31406 }
31407 /**
31408 * Compute the edit distance between the two given strings
31409 * http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
31410 *
31411 * Copyright (c) 2011 Andrei Mackenzie
31412 *
31413 * 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:
31414 *
31415 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
31416 *
31417 * 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.
31418 *
31419 * @param {string} a
31420 * @param {string} b
31421 * @returns {Array.<Array.<number>>}}
31422 * @static
31423 */
31424
31425 }, {
31426 key: "levenshteinDistance",
31427 value: function levenshteinDistance(a, b) {
31428 if (a.length === 0) return b.length;
31429 if (b.length === 0) return a.length;
31430 var matrix = []; // increment along the first column of each row
31431
31432 var i;
31433
31434 for (i = 0; i <= b.length; i++) {
31435 matrix[i] = [i];
31436 } // increment each column in the first row
31437
31438
31439 var j;
31440
31441 for (j = 0; j <= a.length; j++) {
31442 matrix[0][j] = j;
31443 } // Fill in the rest of the matrix
31444
31445
31446 for (i = 1; i <= b.length; i++) {
31447 for (j = 1; j <= a.length; j++) {
31448 if (b.charAt(i - 1) == a.charAt(j - 1)) {
31449 matrix[i][j] = matrix[i - 1][j - 1];
31450 } else {
31451 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
31452 Math.min(matrix[i][j - 1] + 1, // insertion
31453 matrix[i - 1][j] + 1)); // deletion
31454 }
31455 }
31456 }
31457
31458 return matrix[b.length][a.length];
31459 }
31460 }]);
31461
31462 return Validator;
31463 }();
31464
31465 /**
31466 * A node. A node can be connected to other nodes via one or multiple edges.
31467 */
31468
31469 var Node =
31470 /*#__PURE__*/
31471 function () {
31472 /**
31473 *
31474 * @param {object} options An object containing options for the node. All
31475 * options are optional, except for the id.
31476 * {number} id Id of the node. Required
31477 * {string} label Text label for the node
31478 * {number} x Horizontal position of the node
31479 * {number} y Vertical position of the node
31480 * {string} shape Node shape
31481 * {string} image An image url
31482 * {string} title A title text, can be HTML
31483 * {anytype} group A group name or number
31484 *
31485 * @param {Object} body Shared state of current network instance
31486 * @param {Network.Images} imagelist A list with images. Only needed when the node has an image
31487 * @param {Groups} grouplist A list with groups. Needed for retrieving group options
31488 * @param {Object} globalOptions Current global node options; these serve as defaults for the node instance
31489 * @param {Object} defaultOptions Global default options for nodes; note that this is also the prototype
31490 * for parameter `globalOptions`.
31491 */
31492 function Node(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
31493 _classCallCheck(this, Node);
31494
31495 this.options = bridgeObject(globalOptions);
31496 this.globalOptions = globalOptions;
31497 this.defaultOptions = defaultOptions;
31498 this.body = body;
31499 this.edges = []; // all edges connected to this node
31500 // set defaults for the options
31501
31502 this.id = undefined;
31503 this.imagelist = imagelist;
31504 this.grouplist = grouplist; // state options
31505
31506 this.x = undefined;
31507 this.y = undefined;
31508 this.baseSize = this.options.size;
31509 this.baseFontSize = this.options.font.size;
31510 this.predefinedPosition = false; // used to check if initial fit should just take the range or approximate
31511
31512 this.selected = false;
31513 this.hover = false;
31514 this.labelModule = new Label(this.body, this.options, false
31515 /* Not edge label */
31516 );
31517 this.setOptions(options);
31518 }
31519 /**
31520 * Attach a edge to the node
31521 * @param {Edge} edge
31522 */
31523
31524
31525 _createClass(Node, [{
31526 key: "attachEdge",
31527 value: function attachEdge(edge) {
31528 if (this.edges.indexOf(edge) === -1) {
31529 this.edges.push(edge);
31530 }
31531 }
31532 /**
31533 * Detach a edge from the node
31534 *
31535 * @param {Edge} edge
31536 */
31537
31538 }, {
31539 key: "detachEdge",
31540 value: function detachEdge(edge) {
31541 var index = this.edges.indexOf(edge);
31542
31543 if (index != -1) {
31544 this.edges.splice(index, 1);
31545 }
31546 }
31547 /**
31548 * Set or overwrite options for the node
31549 *
31550 * @param {Object} options an object with options
31551 * @returns {null|boolean}
31552 */
31553
31554 }, {
31555 key: "setOptions",
31556 value: function setOptions(options) {
31557 var currentShape = this.options.shape;
31558
31559 if (!options) {
31560 return; // Note that the return value will be 'undefined'! This is OK.
31561 } // Save the color for later.
31562 // This is necessary in order to prevent local color from being overwritten by group color.
31563 // TODO: To prevent such workarounds the way options are handled should be rewritten from scratch.
31564 // This is not the only problem with current options handling.
31565
31566
31567 if (typeof options.color !== 'undefined') {
31568 this._localColor = options.color;
31569 } // basic options
31570
31571
31572 if (options.id !== undefined) {
31573 this.id = options.id;
31574 }
31575
31576 if (this.id === undefined) {
31577 throw new Error("Node must have an id");
31578 }
31579
31580 Node.checkMass(options, this.id); // set these options locally
31581 // clear x and y positions
31582
31583 if (options.x !== undefined) {
31584 if (options.x === null) {
31585 this.x = undefined;
31586 this.predefinedPosition = false;
31587 } else {
31588 this.x = parseInt(options.x);
31589 this.predefinedPosition = true;
31590 }
31591 }
31592
31593 if (options.y !== undefined) {
31594 if (options.y === null) {
31595 this.y = undefined;
31596 this.predefinedPosition = false;
31597 } else {
31598 this.y = parseInt(options.y);
31599 this.predefinedPosition = true;
31600 }
31601 }
31602
31603 if (options.size !== undefined) {
31604 this.baseSize = options.size;
31605 }
31606
31607 if (options.value !== undefined) {
31608 options.value = parseFloat(options.value);
31609 } // this transforms all shorthands into fully defined options
31610
31611
31612 Node.parseOptions(this.options, options, true, this.globalOptions, this.grouplist);
31613 var pile = [options, this.options, this.defaultOptions];
31614 this.chooser = ComponentUtil.choosify('node', pile);
31615
31616 this._load_images();
31617
31618 this.updateLabelModule(options);
31619 this.updateShape(currentShape);
31620 return options.hidden !== undefined || options.physics !== undefined;
31621 }
31622 /**
31623 * Load the images from the options, for the nodes that need them.
31624 *
31625 * Images are always loaded, even if they are not used in the current shape.
31626 * The user may switch to an image shape later on.
31627 *
31628 * @private
31629 */
31630
31631 }, {
31632 key: "_load_images",
31633 value: function _load_images() {
31634 if (this.options.shape === 'circularImage' || this.options.shape === 'image') {
31635 if (this.options.image === undefined) {
31636 throw new Error("Option image must be defined for node type '" + this.options.shape + "'");
31637 }
31638 }
31639
31640 if (this.options.image === undefined) {
31641 return;
31642 }
31643
31644 if (this.imagelist === undefined) {
31645 throw new Error("Internal Error: No images provided");
31646 }
31647
31648 if (typeof this.options.image === 'string') {
31649 this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
31650 } else {
31651 if (this.options.image.unselected === undefined) {
31652 throw new Error("No unselected image provided");
31653 }
31654
31655 this.imageObj = this.imagelist.load(this.options.image.unselected, this.options.brokenImage, this.id);
31656
31657 if (this.options.image.selected !== undefined) {
31658 this.imageObjAlt = this.imagelist.load(this.options.image.selected, this.options.brokenImage, this.id);
31659 } else {
31660 this.imageObjAlt = undefined;
31661 }
31662 }
31663 }
31664 /**
31665 * Copy group option values into the node options.
31666 *
31667 * The group options override the global node options, so the copy of group options
31668 * must happen *after* the global node options have been set.
31669 *
31670 * This method must also be called also if the global node options have changed and the group options did not.
31671 *
31672 * @param {Object} parentOptions
31673 * @param {Object} newOptions new values for the options, currently only passed in for check
31674 * @param {Object} groupList
31675 */
31676
31677 }, {
31678 key: "getFormattingValues",
31679
31680 /**
31681 *
31682 * @returns {{color: *, borderWidth: *, borderColor: *, size: *, borderDashes: (boolean|Array|allOptions.nodes.shapeProperties.borderDashes|{boolean, array}), borderRadius: (number|allOptions.nodes.shapeProperties.borderRadius|{number}|Array), shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *}}
31683 */
31684 value: function getFormattingValues() {
31685 var values = {
31686 color: this.options.color.background,
31687 borderWidth: this.options.borderWidth,
31688 borderColor: this.options.color.border,
31689 size: this.options.size,
31690 borderDashes: this.options.shapeProperties.borderDashes,
31691 borderRadius: this.options.shapeProperties.borderRadius,
31692 shadow: this.options.shadow.enabled,
31693 shadowColor: this.options.shadow.color,
31694 shadowSize: this.options.shadow.size,
31695 shadowX: this.options.shadow.x,
31696 shadowY: this.options.shadow.y
31697 };
31698
31699 if (this.selected || this.hover) {
31700 if (this.chooser === true) {
31701 if (this.selected) {
31702 values.borderWidth *= 2;
31703 values.color = this.options.color.highlight.background;
31704 values.borderColor = this.options.color.highlight.border;
31705 values.shadow = this.options.shadow.enabled;
31706 } else if (this.hover) {
31707 values.color = this.options.color.hover.background;
31708 values.borderColor = this.options.color.hover.border;
31709 values.shadow = this.options.shadow.enabled;
31710 }
31711 } else if (typeof this.chooser === 'function') {
31712 this.chooser(values, this.options.id, this.selected, this.hover);
31713
31714 if (values.shadow === false) {
31715 if (values.shadowColor !== this.options.shadow.color || values.shadowSize !== this.options.shadow.size || values.shadowX !== this.options.shadow.x || values.shadowY !== this.options.shadow.y) {
31716 values.shadow = true;
31717 }
31718 }
31719 }
31720 } else {
31721 values.shadow = this.options.shadow.enabled;
31722 }
31723
31724 return values;
31725 }
31726 /**
31727 *
31728 * @param {Object} options
31729 */
31730
31731 }, {
31732 key: "updateLabelModule",
31733 value: function updateLabelModule(options) {
31734 if (this.options.label === undefined || this.options.label === null) {
31735 this.options.label = '';
31736 }
31737
31738 Node.updateGroupOptions(this.options, _objectSpread2$1({}, options, {
31739 color: options && options.color || this._localColor || undefined
31740 }), this.grouplist); //
31741 // Note:The prototype chain for this.options is:
31742 //
31743 // this.options -> NodesHandler.options -> NodesHandler.defaultOptions
31744 // (also: this.globalOptions)
31745 //
31746 // Note that the prototypes are mentioned explicitly in the pile list below;
31747 // WE DON'T WANT THE ORDER OF THE PROTOTYPES!!!! At least, not for font handling of labels.
31748 // This is a good indication that the prototype usage of options is deficient.
31749 //
31750
31751 var currentGroup = this.grouplist.get(this.options.group, false);
31752 var pile = [options, // new options
31753 this.options, // current node options, see comment above for prototype
31754 currentGroup, // group options, if any
31755 this.globalOptions, // Currently set global node options
31756 this.defaultOptions // Default global node options
31757 ];
31758 this.labelModule.update(this.options, pile);
31759
31760 if (this.labelModule.baseSize !== undefined) {
31761 this.baseFontSize = this.labelModule.baseSize;
31762 }
31763 }
31764 /**
31765 *
31766 * @param {string} currentShape
31767 */
31768
31769 }, {
31770 key: "updateShape",
31771 value: function updateShape(currentShape) {
31772 if (currentShape === this.options.shape && this.shape) {
31773 this.shape.setOptions(this.options, this.imageObj, this.imageObjAlt);
31774 } else {
31775 // choose draw method depending on the shape
31776 switch (this.options.shape) {
31777 case 'box':
31778 this.shape = new Box(this.options, this.body, this.labelModule);
31779 break;
31780
31781 case 'circle':
31782 this.shape = new Circle(this.options, this.body, this.labelModule);
31783 break;
31784
31785 case 'circularImage':
31786 this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
31787 break;
31788
31789 case 'database':
31790 this.shape = new Database(this.options, this.body, this.labelModule);
31791 break;
31792
31793 case 'diamond':
31794 this.shape = new Diamond(this.options, this.body, this.labelModule);
31795 break;
31796
31797 case 'dot':
31798 this.shape = new Dot(this.options, this.body, this.labelModule);
31799 break;
31800
31801 case 'ellipse':
31802 this.shape = new Ellipse(this.options, this.body, this.labelModule);
31803 break;
31804
31805 case 'icon':
31806 this.shape = new Icon(this.options, this.body, this.labelModule);
31807 break;
31808
31809 case 'image':
31810 this.shape = new Image$1(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
31811 break;
31812
31813 case 'square':
31814 this.shape = new Square(this.options, this.body, this.labelModule);
31815 break;
31816
31817 case 'hexagon':
31818 this.shape = new Hexagon(this.options, this.body, this.labelModule);
31819 break;
31820
31821 case 'star':
31822 this.shape = new Star(this.options, this.body, this.labelModule);
31823 break;
31824
31825 case 'text':
31826 this.shape = new Text(this.options, this.body, this.labelModule);
31827 break;
31828
31829 case 'triangle':
31830 this.shape = new Triangle(this.options, this.body, this.labelModule);
31831 break;
31832
31833 case 'triangleDown':
31834 this.shape = new TriangleDown(this.options, this.body, this.labelModule);
31835 break;
31836
31837 default:
31838 this.shape = new Ellipse(this.options, this.body, this.labelModule);
31839 break;
31840 }
31841 }
31842
31843 this.needsRefresh();
31844 }
31845 /**
31846 * select this node
31847 */
31848
31849 }, {
31850 key: "select",
31851 value: function select() {
31852 this.selected = true;
31853 this.needsRefresh();
31854 }
31855 /**
31856 * unselect this node
31857 */
31858
31859 }, {
31860 key: "unselect",
31861 value: function unselect() {
31862 this.selected = false;
31863 this.needsRefresh();
31864 }
31865 /**
31866 * Reset the calculated size of the node, forces it to recalculate its size
31867 */
31868
31869 }, {
31870 key: "needsRefresh",
31871 value: function needsRefresh() {
31872 this.shape.refreshNeeded = true;
31873 }
31874 /**
31875 * get the title of this node.
31876 * @return {string} title The title of the node, or undefined when no title
31877 * has been set.
31878 */
31879
31880 }, {
31881 key: "getTitle",
31882 value: function getTitle() {
31883 return this.options.title;
31884 }
31885 /**
31886 * Calculate the distance to the border of the Node
31887 * @param {CanvasRenderingContext2D} ctx
31888 * @param {number} angle Angle in radians
31889 * @returns {number} distance Distance to the border in pixels
31890 */
31891
31892 }, {
31893 key: "distanceToBorder",
31894 value: function distanceToBorder(ctx, angle) {
31895 return this.shape.distanceToBorder(ctx, angle);
31896 }
31897 /**
31898 * Check if this node has a fixed x and y position
31899 * @return {boolean} true if fixed, false if not
31900 */
31901
31902 }, {
31903 key: "isFixed",
31904 value: function isFixed() {
31905 return this.options.fixed.x && this.options.fixed.y;
31906 }
31907 /**
31908 * check if this node is selecte
31909 * @return {boolean} selected True if node is selected, else false
31910 */
31911
31912 }, {
31913 key: "isSelected",
31914 value: function isSelected() {
31915 return this.selected;
31916 }
31917 /**
31918 * Retrieve the value of the node. Can be undefined
31919 * @return {number} value
31920 */
31921
31922 }, {
31923 key: "getValue",
31924 value: function getValue() {
31925 return this.options.value;
31926 }
31927 /**
31928 * Get the current dimensions of the label
31929 *
31930 * @return {rect}
31931 */
31932
31933 }, {
31934 key: "getLabelSize",
31935 value: function getLabelSize() {
31936 return this.labelModule.size();
31937 }
31938 /**
31939 * Adjust the value range of the node. The node will adjust it's size
31940 * based on its value.
31941 * @param {number} min
31942 * @param {number} max
31943 * @param {number} total
31944 */
31945
31946 }, {
31947 key: "setValueRange",
31948 value: function setValueRange(min, max, total) {
31949 if (this.options.value !== undefined) {
31950 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
31951 var sizeDiff = this.options.scaling.max - this.options.scaling.min;
31952
31953 if (this.options.scaling.label.enabled === true) {
31954 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
31955 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
31956 }
31957
31958 this.options.size = this.options.scaling.min + scale * sizeDiff;
31959 } else {
31960 this.options.size = this.baseSize;
31961 this.options.font.size = this.baseFontSize;
31962 }
31963
31964 this.updateLabelModule();
31965 }
31966 /**
31967 * Draw this node in the given canvas
31968 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
31969 * @param {CanvasRenderingContext2D} ctx
31970 */
31971
31972 }, {
31973 key: "draw",
31974 value: function draw(ctx) {
31975 var values = this.getFormattingValues();
31976 this.shape.draw(ctx, this.x, this.y, this.selected, this.hover, values);
31977 }
31978 /**
31979 * Update the bounding box of the shape
31980 * @param {CanvasRenderingContext2D} ctx
31981 */
31982
31983 }, {
31984 key: "updateBoundingBox",
31985 value: function updateBoundingBox(ctx) {
31986 this.shape.updateBoundingBox(this.x, this.y, ctx);
31987 }
31988 /**
31989 * Recalculate the size of this node in the given canvas
31990 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
31991 * @param {CanvasRenderingContext2D} ctx
31992 */
31993
31994 }, {
31995 key: "resize",
31996 value: function resize(ctx) {
31997 var values = this.getFormattingValues();
31998 this.shape.resize(ctx, this.selected, this.hover, values);
31999 }
32000 /**
32001 * Determine all visual elements of this node instance, in which the given
32002 * point falls within the bounding shape.
32003 *
32004 * @param {point} point
32005 * @returns {Array.<nodeClickItem|nodeLabelClickItem>} list with the items which are on the point
32006 */
32007
32008 }, {
32009 key: "getItemsOnPoint",
32010 value: function getItemsOnPoint(point) {
32011 var ret = [];
32012
32013 if (this.labelModule.visible()) {
32014 if (ComponentUtil.pointInRect(this.labelModule.getSize(), point)) {
32015 ret.push({
32016 nodeId: this.id,
32017 labelId: 0
32018 });
32019 }
32020 }
32021
32022 if (ComponentUtil.pointInRect(this.shape.boundingBox, point)) {
32023 ret.push({
32024 nodeId: this.id
32025 });
32026 }
32027
32028 return ret;
32029 }
32030 /**
32031 * Check if this object is overlapping with the provided object
32032 * @param {Object} obj an object with parameters left, top, right, bottom
32033 * @return {boolean} True if location is located on node
32034 */
32035
32036 }, {
32037 key: "isOverlappingWith",
32038 value: function isOverlappingWith(obj) {
32039 return this.shape.left < obj.right && this.shape.left + this.shape.width > obj.left && this.shape.top < obj.bottom && this.shape.top + this.shape.height > obj.top;
32040 }
32041 /**
32042 * Check if this object is overlapping with the provided object
32043 * @param {Object} obj an object with parameters left, top, right, bottom
32044 * @return {boolean} True if location is located on node
32045 */
32046
32047 }, {
32048 key: "isBoundingBoxOverlappingWith",
32049 value: function isBoundingBoxOverlappingWith(obj) {
32050 return this.shape.boundingBox.left < obj.right && this.shape.boundingBox.right > obj.left && this.shape.boundingBox.top < obj.bottom && this.shape.boundingBox.bottom > obj.top;
32051 }
32052 /**
32053 * Check valid values for mass
32054 *
32055 * The mass may not be negative or zero. If it is, reset to 1
32056 *
32057 * @param {object} options
32058 * @param {Node.id} id
32059 * @static
32060 */
32061
32062 }], [{
32063 key: "updateGroupOptions",
32064 value: function updateGroupOptions(parentOptions, newOptions, groupList) {
32065 if (groupList === undefined) return; // No groups, nothing to do
32066
32067 var group = parentOptions.group; // paranoia: the selected group is already merged into node options, check.
32068
32069 if (newOptions !== undefined && newOptions.group !== undefined && group !== newOptions.group) {
32070 throw new Error("updateGroupOptions: group values in options don't match.");
32071 }
32072
32073 var hasGroup = typeof group === 'number' || typeof group === 'string' && group != '';
32074 if (!hasGroup) return; // current node has no group, no need to merge
32075
32076 var groupObj = groupList.get(group); // Skip merging of group font options into parent; these are required to be distinct for labels
32077 // Also skip mergin of color IF it is already defined in the node itself. This is to avoid the color of the
32078 // group overriding the color set at the node level
32079 // TODO: It might not be a good idea either to merge the rest of the options, investigate this.
32080
32081 var skipProperties = ['font'];
32082 if (newOptions !== undefined && newOptions.color !== undefined && newOptions.color != null) skipProperties.push('color');
32083 selectiveNotDeepExtend(skipProperties, parentOptions, groupObj); // the color object needs to be completely defined.
32084 // Since groups can partially overwrite the colors, we parse it again, just in case.
32085
32086 parentOptions.color = parseColor(parentOptions.color);
32087 }
32088 /**
32089 * This process all possible shorthands in the new options and makes sure that the parentOptions are fully defined.
32090 * Static so it can also be used by the handler.
32091 *
32092 * @param {Object} parentOptions
32093 * @param {Object} newOptions
32094 * @param {boolean} [allowDeletion=false]
32095 * @param {Object} [globalOptions={}]
32096 * @param {Object} [groupList]
32097 * @static
32098 */
32099
32100 }, {
32101 key: "parseOptions",
32102 value: function parseOptions(parentOptions, newOptions) {
32103 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
32104 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
32105 var groupList = arguments.length > 4 ? arguments[4] : undefined;
32106 var fields = ['color', 'fixed', 'shadow'];
32107 selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);
32108 Node.checkMass(newOptions); // merge the shadow options into the parent.
32109
32110 mergeOptions(parentOptions, newOptions, 'shadow', globalOptions); // individual shape newOptions
32111
32112 if (newOptions.color !== undefined && newOptions.color !== null) {
32113 var parsedColor = parseColor(newOptions.color);
32114 fillIfDefined(parentOptions.color, parsedColor);
32115 } else if (allowDeletion === true && newOptions.color === null) {
32116 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
32117 } // handle the fixed options
32118
32119
32120 if (newOptions.fixed !== undefined && newOptions.fixed !== null) {
32121 if (typeof newOptions.fixed === 'boolean') {
32122 parentOptions.fixed.x = newOptions.fixed;
32123 parentOptions.fixed.y = newOptions.fixed;
32124 } else {
32125 if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === 'boolean') {
32126 parentOptions.fixed.x = newOptions.fixed.x;
32127 }
32128
32129 if (newOptions.fixed.y !== undefined && typeof newOptions.fixed.y === 'boolean') {
32130 parentOptions.fixed.y = newOptions.fixed.y;
32131 }
32132 }
32133 }
32134
32135 if (allowDeletion === true && newOptions.font === null) {
32136 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
32137 }
32138
32139 Node.updateGroupOptions(parentOptions, newOptions, groupList); // handle the scaling options, specifically the label part
32140
32141 if (newOptions.scaling !== undefined) {
32142 mergeOptions(parentOptions.scaling, newOptions.scaling, 'label', globalOptions.scaling);
32143 }
32144 }
32145 }, {
32146 key: "checkMass",
32147 value: function checkMass(options, id) {
32148 if (options.mass !== undefined && options.mass <= 0) {
32149 var strId = '';
32150
32151 if (id !== undefined) {
32152 strId = ' in node id: ' + id;
32153 }
32154
32155 console.log('%cNegative or zero mass disallowed' + strId + ', setting mass to 1.', printStyle);
32156 options.mass = 1;
32157 }
32158 }
32159 }]);
32160
32161 return Node;
32162 }();
32163
32164 /**
32165 * Handler for Nodes
32166 */
32167
32168 var NodesHandler =
32169 /*#__PURE__*/
32170 function () {
32171 /**
32172 * @param {Object} body
32173 * @param {Images} images
32174 * @param {Array.<Group>} groups
32175 * @param {LayoutEngine} layoutEngine
32176 */
32177 function NodesHandler(body, images, groups, layoutEngine) {
32178 var _this = this;
32179
32180 _classCallCheck(this, NodesHandler);
32181
32182 this.body = body;
32183 this.images = images;
32184 this.groups = groups;
32185 this.layoutEngine = layoutEngine; // create the node API in the body container
32186
32187 this.body.functions.createNode = this.create.bind(this);
32188 this.nodesListeners = {
32189 add: function add(event, params) {
32190 _this.add(params.items);
32191 },
32192 update: function update(event, params) {
32193 _this.update(params.items, params.data, params.oldData);
32194 },
32195 remove: function remove(event, params) {
32196 _this.remove(params.items);
32197 }
32198 };
32199 this.defaultOptions = {
32200 borderWidth: 1,
32201 borderWidthSelected: 2,
32202 brokenImage: undefined,
32203 color: {
32204 border: '#2B7CE9',
32205 background: '#97C2FC',
32206 highlight: {
32207 border: '#2B7CE9',
32208 background: '#D2E5FF'
32209 },
32210 hover: {
32211 border: '#2B7CE9',
32212 background: '#D2E5FF'
32213 }
32214 },
32215 fixed: {
32216 x: false,
32217 y: false
32218 },
32219 font: {
32220 color: '#343434',
32221 size: 14,
32222 // px
32223 face: 'arial',
32224 background: 'none',
32225 strokeWidth: 0,
32226 // px
32227 strokeColor: '#ffffff',
32228 align: 'center',
32229 vadjust: 0,
32230 multi: false,
32231 bold: {
32232 mod: 'bold'
32233 },
32234 boldital: {
32235 mod: 'bold italic'
32236 },
32237 ital: {
32238 mod: 'italic'
32239 },
32240 mono: {
32241 mod: '',
32242 size: 15,
32243 // px
32244 face: 'monospace',
32245 vadjust: 2
32246 }
32247 },
32248 group: undefined,
32249 hidden: false,
32250 icon: {
32251 face: 'FontAwesome',
32252 //'FontAwesome',
32253 code: undefined,
32254 //'\uf007',
32255 size: 50,
32256 //50,
32257 color: '#2B7CE9' //'#aa00ff'
32258
32259 },
32260 image: undefined,
32261 // --> URL
32262 imagePadding: {
32263 // only for image shape
32264 top: 0,
32265 right: 0,
32266 bottom: 0,
32267 left: 0
32268 },
32269 label: undefined,
32270 labelHighlightBold: true,
32271 level: undefined,
32272 margin: {
32273 top: 5,
32274 right: 5,
32275 bottom: 5,
32276 left: 5
32277 },
32278 mass: 1,
32279 physics: true,
32280 scaling: {
32281 min: 10,
32282 max: 30,
32283 label: {
32284 enabled: false,
32285 min: 14,
32286 max: 30,
32287 maxVisible: 30,
32288 drawThreshold: 5
32289 },
32290 customScalingFunction: function customScalingFunction(min, max, total, value) {
32291 if (max === min) {
32292 return 0.5;
32293 } else {
32294 var scale = 1 / (max - min);
32295 return Math.max(0, (value - min) * scale);
32296 }
32297 }
32298 },
32299 shadow: {
32300 enabled: false,
32301 color: 'rgba(0,0,0,0.5)',
32302 size: 10,
32303 x: 5,
32304 y: 5
32305 },
32306 shape: 'ellipse',
32307 shapeProperties: {
32308 borderDashes: false,
32309 // only for borders
32310 borderRadius: 6,
32311 // only for box shape
32312 interpolation: true,
32313 // only for image and circularImage shapes
32314 useImageSize: false,
32315 // only for image and circularImage shapes
32316 useBorderWithImage: false // only for image shape
32317
32318 },
32319 size: 25,
32320 title: undefined,
32321 value: undefined,
32322 x: undefined,
32323 y: undefined
32324 }; // Protect from idiocy
32325
32326 if (this.defaultOptions.mass <= 0) {
32327 throw 'Internal error: mass in defaultOptions of NodesHandler may not be zero or negative';
32328 }
32329
32330 this.options = bridgeObject(this.defaultOptions);
32331 this.bindEventListeners();
32332 }
32333 /**
32334 * Binds event listeners
32335 */
32336
32337
32338 _createClass(NodesHandler, [{
32339 key: "bindEventListeners",
32340 value: function bindEventListeners() {
32341 var _this2 = this;
32342
32343 // refresh the nodes. Used when reverting from hierarchical layout
32344 this.body.emitter.on('refreshNodes', this.refresh.bind(this));
32345 this.body.emitter.on('refresh', this.refresh.bind(this));
32346 this.body.emitter.on('destroy', function () {
32347 forEach(_this2.nodesListeners, function (callback, event) {
32348 if (_this2.body.data.nodes) _this2.body.data.nodes.off(event, callback);
32349 });
32350 delete _this2.body.functions.createNode;
32351 delete _this2.nodesListeners.add;
32352 delete _this2.nodesListeners.update;
32353 delete _this2.nodesListeners.remove;
32354 delete _this2.nodesListeners;
32355 });
32356 }
32357 /**
32358 *
32359 * @param {Object} options
32360 */
32361
32362 }, {
32363 key: "setOptions",
32364 value: function setOptions(options) {
32365 if (options !== undefined) {
32366 Node.parseOptions(this.options, options); // update the shape in all nodes
32367
32368 if (options.shape !== undefined) {
32369 for (var nodeId in this.body.nodes) {
32370 if (this.body.nodes.hasOwnProperty(nodeId)) {
32371 this.body.nodes[nodeId].updateShape();
32372 }
32373 }
32374 } // update the font in all nodes
32375
32376
32377 if (options.font !== undefined) {
32378 for (var _nodeId in this.body.nodes) {
32379 if (this.body.nodes.hasOwnProperty(_nodeId)) {
32380 this.body.nodes[_nodeId].updateLabelModule();
32381
32382 this.body.nodes[_nodeId].needsRefresh();
32383 }
32384 }
32385 } // update the shape size in all nodes
32386
32387
32388 if (options.size !== undefined) {
32389 for (var _nodeId2 in this.body.nodes) {
32390 if (this.body.nodes.hasOwnProperty(_nodeId2)) {
32391 this.body.nodes[_nodeId2].needsRefresh();
32392 }
32393 }
32394 } // update the state of the variables if needed
32395
32396
32397 if (options.hidden !== undefined || options.physics !== undefined) {
32398 this.body.emitter.emit('_dataChanged');
32399 }
32400 }
32401 }
32402 /**
32403 * Set a data set with nodes for the network
32404 * @param {Array | DataSet | DataView} nodes The data containing the nodes.
32405 * @param {boolean} [doNotEmit=false]
32406 * @private
32407 */
32408
32409 }, {
32410 key: "setData",
32411 value: function setData(nodes) {
32412 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
32413 var oldNodesData = this.body.data.nodes;
32414
32415 if (nodes instanceof DataSet || nodes instanceof DataView$2) {
32416 this.body.data.nodes = nodes;
32417 } else if (Array.isArray(nodes)) {
32418 this.body.data.nodes = new DataSet();
32419 this.body.data.nodes.add(nodes);
32420 } else if (!nodes) {
32421 this.body.data.nodes = new DataSet();
32422 } else {
32423 throw new TypeError('Array or DataSet expected');
32424 }
32425
32426 if (oldNodesData) {
32427 // unsubscribe from old dataset
32428 forEach(this.nodesListeners, function (callback, event) {
32429 oldNodesData.off(event, callback);
32430 });
32431 } // remove drawn nodes
32432
32433
32434 this.body.nodes = {};
32435
32436 if (this.body.data.nodes) {
32437 // subscribe to new dataset
32438 var me = this;
32439 forEach(this.nodesListeners, function (callback, event) {
32440 me.body.data.nodes.on(event, callback);
32441 }); // draw all new nodes
32442
32443 var ids = this.body.data.nodes.getIds();
32444 this.add(ids, true);
32445 }
32446
32447 if (doNotEmit === false) {
32448 this.body.emitter.emit("_dataChanged");
32449 }
32450 }
32451 /**
32452 * Add nodes
32453 * @param {number[] | string[]} ids
32454 * @param {boolean} [doNotEmit=false]
32455 * @private
32456 */
32457
32458 }, {
32459 key: "add",
32460 value: function add(ids) {
32461 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
32462 var id;
32463 var newNodes = [];
32464
32465 for (var i = 0; i < ids.length; i++) {
32466 id = ids[i];
32467 var properties = this.body.data.nodes.get(id);
32468 var node = this.create(properties);
32469 newNodes.push(node);
32470 this.body.nodes[id] = node; // note: this may replace an existing node
32471 }
32472
32473 this.layoutEngine.positionInitially(newNodes);
32474
32475 if (doNotEmit === false) {
32476 this.body.emitter.emit("_dataChanged");
32477 }
32478 }
32479 /**
32480 * Update existing nodes, or create them when not yet existing
32481 * @param {number[] | string[]} ids id's of changed nodes
32482 * @param {Array} changedData array with changed data
32483 * @param {Array|undefined} oldData optional; array with previous data
32484 * @private
32485 */
32486
32487 }, {
32488 key: "update",
32489 value: function update(ids, changedData, oldData) {
32490 var nodes = this.body.nodes;
32491 var dataChanged = false;
32492
32493 for (var i = 0; i < ids.length; i++) {
32494 var id = ids[i];
32495 var node = nodes[id];
32496 var data = changedData[i];
32497
32498 if (node !== undefined) {
32499 // update node
32500 if (node.setOptions(data)) {
32501 dataChanged = true;
32502 }
32503 } else {
32504 dataChanged = true; // create node
32505
32506 node = this.create(data);
32507 nodes[id] = node;
32508 }
32509 }
32510
32511 if (!dataChanged && oldData !== undefined) {
32512 // Check for any changes which should trigger a layout recalculation
32513 // For now, this is just 'level' for hierarchical layout
32514 // Assumption: old and new data arranged in same order; at time of writing, this holds.
32515 dataChanged = changedData.some(function (newValue, index) {
32516 var oldValue = oldData[index];
32517 return oldValue && oldValue.level !== newValue.level;
32518 });
32519 }
32520
32521 if (dataChanged === true) {
32522 this.body.emitter.emit("_dataChanged");
32523 } else {
32524 this.body.emitter.emit("_dataUpdated");
32525 }
32526 }
32527 /**
32528 * Remove existing nodes. If nodes do not exist, the method will just ignore it.
32529 * @param {number[] | string[]} ids
32530 * @private
32531 */
32532
32533 }, {
32534 key: "remove",
32535 value: function remove(ids) {
32536 var nodes = this.body.nodes;
32537
32538 for (var i = 0; i < ids.length; i++) {
32539 var id = ids[i];
32540 delete nodes[id];
32541 }
32542
32543 this.body.emitter.emit("_dataChanged");
32544 }
32545 /**
32546 * create a node
32547 * @param {Object} properties
32548 * @param {class} [constructorClass=Node.default]
32549 * @returns {*}
32550 */
32551
32552 }, {
32553 key: "create",
32554 value: function create(properties) {
32555 var constructorClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Node;
32556 return new constructorClass(properties, this.body, this.images, this.groups, this.options, this.defaultOptions);
32557 }
32558 /**
32559 *
32560 * @param {boolean} [clearPositions=false]
32561 */
32562
32563 }, {
32564 key: "refresh",
32565 value: function refresh() {
32566 var _this3 = this;
32567
32568 var clearPositions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
32569 forEach(this.body.nodes, function (node, nodeId) {
32570 var data = _this3.body.data.nodes.get(nodeId);
32571
32572 if (data !== undefined) {
32573 if (clearPositions === true) {
32574 node.setOptions({
32575 x: null,
32576 y: null
32577 });
32578 }
32579
32580 node.setOptions({
32581 fixed: false
32582 });
32583 node.setOptions(data);
32584 }
32585 });
32586 }
32587 /**
32588 * Returns the positions of the nodes.
32589 * @param {Array.<Node.id>|String} [ids] --> optional, can be array of nodeIds, can be string
32590 * @returns {{}}
32591 */
32592
32593 }, {
32594 key: "getPositions",
32595 value: function getPositions(ids) {
32596 var dataArray = {};
32597
32598 if (ids !== undefined) {
32599 if (Array.isArray(ids) === true) {
32600 for (var i = 0; i < ids.length; i++) {
32601 if (this.body.nodes[ids[i]] !== undefined) {
32602 var node = this.body.nodes[ids[i]];
32603 dataArray[ids[i]] = {
32604 x: Math.round(node.x),
32605 y: Math.round(node.y)
32606 };
32607 }
32608 }
32609 } else {
32610 if (this.body.nodes[ids] !== undefined) {
32611 var _node = this.body.nodes[ids];
32612 dataArray[ids] = {
32613 x: Math.round(_node.x),
32614 y: Math.round(_node.y)
32615 };
32616 }
32617 }
32618 } else {
32619 for (var _i = 0; _i < this.body.nodeIndices.length; _i++) {
32620 var _node2 = this.body.nodes[this.body.nodeIndices[_i]];
32621 dataArray[this.body.nodeIndices[_i]] = {
32622 x: Math.round(_node2.x),
32623 y: Math.round(_node2.y)
32624 };
32625 }
32626 }
32627
32628 return dataArray;
32629 }
32630 /**
32631 * Load the XY positions of the nodes into the dataset.
32632 */
32633
32634 }, {
32635 key: "storePositions",
32636 value: function storePositions() {
32637 // todo: add support for clusters and hierarchical.
32638 var dataArray = [];
32639 var dataset = this.body.data.nodes.getDataSet();
32640
32641 for (var nodeId in dataset._data) {
32642 if (dataset._data.hasOwnProperty(nodeId)) {
32643 var node = this.body.nodes[nodeId];
32644
32645 if (dataset._data[nodeId].x != Math.round(node.x) || dataset._data[nodeId].y != Math.round(node.y)) {
32646 dataArray.push({
32647 id: node.id,
32648 x: Math.round(node.x),
32649 y: Math.round(node.y)
32650 });
32651 }
32652 }
32653 }
32654
32655 dataset.update(dataArray);
32656 }
32657 /**
32658 * get the bounding box of a node.
32659 * @param {Node.id} nodeId
32660 * @returns {j|*}
32661 */
32662
32663 }, {
32664 key: "getBoundingBox",
32665 value: function getBoundingBox(nodeId) {
32666 if (this.body.nodes[nodeId] !== undefined) {
32667 return this.body.nodes[nodeId].shape.boundingBox;
32668 }
32669 }
32670 /**
32671 * Get the Ids of nodes connected to this node.
32672 * @param {Node.id} nodeId
32673 * @param {'to'|'from'|undefined} direction values 'from' and 'to' select respectively parent and child nodes only.
32674 * Any other value returns both parent and child nodes.
32675 * @returns {Array}
32676 */
32677
32678 }, {
32679 key: "getConnectedNodes",
32680 value: function getConnectedNodes(nodeId, direction) {
32681 var nodeList = [];
32682
32683 if (this.body.nodes[nodeId] !== undefined) {
32684 var node = this.body.nodes[nodeId];
32685 var nodeObj = {}; // used to quickly check if node already exists
32686
32687 for (var i = 0; i < node.edges.length; i++) {
32688 var edge = node.edges[i];
32689
32690 if (direction !== 'to' && edge.toId == node.id) {
32691 // these are double equals since ids can be numeric or string
32692 if (nodeObj[edge.fromId] === undefined) {
32693 nodeList.push(edge.fromId);
32694 nodeObj[edge.fromId] = true;
32695 }
32696 } else if (direction !== 'from' && edge.fromId == node.id) {
32697 // these are double equals since ids can be numeric or string
32698 if (nodeObj[edge.toId] === undefined) {
32699 nodeList.push(edge.toId);
32700 nodeObj[edge.toId] = true;
32701 }
32702 }
32703 }
32704 }
32705
32706 return nodeList;
32707 }
32708 /**
32709 * Get the ids of the edges connected to this node.
32710 * @param {Node.id} nodeId
32711 * @returns {*}
32712 */
32713
32714 }, {
32715 key: "getConnectedEdges",
32716 value: function getConnectedEdges(nodeId) {
32717 var edgeList = [];
32718
32719 if (this.body.nodes[nodeId] !== undefined) {
32720 var node = this.body.nodes[nodeId];
32721
32722 for (var i = 0; i < node.edges.length; i++) {
32723 edgeList.push(node.edges[i].id);
32724 }
32725 } else {
32726 console.log("NodeId provided for getConnectedEdges does not exist. Provided: ", nodeId);
32727 }
32728
32729 return edgeList;
32730 }
32731 /**
32732 * Move a node.
32733 *
32734 * @param {Node.id} nodeId
32735 * @param {number} x
32736 * @param {number} y
32737 */
32738
32739 }, {
32740 key: "moveNode",
32741 value: function moveNode(nodeId, x, y) {
32742 var _this4 = this;
32743
32744 if (this.body.nodes[nodeId] !== undefined) {
32745 this.body.nodes[nodeId].x = Number(x);
32746 this.body.nodes[nodeId].y = Number(y);
32747 setTimeout(function () {
32748 _this4.body.emitter.emit("startSimulation");
32749 }, 0);
32750 } else {
32751 console.log("Node id supplied to moveNode does not exist. Provided: ", nodeId);
32752 }
32753 }
32754 }]);
32755
32756 return NodesHandler;
32757 }();
32758
32759 var $hypot = Math.hypot;
32760 var abs$2 = Math.abs;
32761 var sqrt = Math.sqrt; // Chrome 77 bug
32762 // https://bugs.chromium.org/p/v8/issues/detail?id=9546
32763
32764 var BUGGY$1 = !!$hypot && $hypot(Infinity, NaN) !== Infinity; // `Math.hypot` method
32765 // https://tc39.github.io/ecma262/#sec-math.hypot
32766
32767 _export({
32768 target: 'Math',
32769 stat: true,
32770 forced: BUGGY$1
32771 }, {
32772 hypot: function hypot(value1, value2) {
32773 // eslint-disable-line no-unused-vars
32774 var sum = 0;
32775 var i = 0;
32776 var aLen = arguments.length;
32777 var larg = 0;
32778 var arg, div;
32779
32780 while (i < aLen) {
32781 arg = abs$2(arguments[i++]);
32782
32783 if (larg < arg) {
32784 div = larg / arg;
32785 sum = sum * div * div + 1;
32786 larg = arg;
32787 } else if (arg > 0) {
32788 div = arg / larg;
32789 sum += div * div;
32790 } else sum += arg;
32791 }
32792
32793 return larg === Infinity ? Infinity : larg * sqrt(sum);
32794 }
32795 });
32796
32797 /** ============================================================================
32798 * Location of all the endpoint drawing routines.
32799 *
32800 * Every endpoint has its own drawing routine, which contains an endpoint definition.
32801 *
32802 * The endpoint definitions must have the following properies:
32803 *
32804 * - (0,0) is the connection point to the node it attaches to
32805 * - The endpoints are orientated to the positive x-direction
32806 * - The length of the endpoint is at most 1
32807 *
32808 * As long as the endpoint classes remain simple and not too numerous, they will
32809 * be contained within this module.
32810 * All classes here except `EndPoints` should be considered as private to this module.
32811 *
32812 * -----------------------------------------------------------------------------
32813 * ### Further Actions
32814 *
32815 * After adding a new endpoint here, you also need to do the following things:
32816 *
32817 * - Add the new endpoint name to `network/options.js` in array `endPoints`.
32818 * - Add the new endpoint name to the documentation.
32819 * Scan for 'arrows.to.type` and add it to the description.
32820 * - Add the endpoint to the examples. At the very least, add it to example
32821 * `edgeStyles/arrowTypes`.
32822 * ============================================================================= */
32823
32824 /**
32825 * Common methods for endpoints
32826 *
32827 * @class
32828 */
32829 var EndPoint =
32830 /*#__PURE__*/
32831 function () {
32832 function EndPoint() {
32833 _classCallCheck(this, EndPoint);
32834 }
32835
32836 _createClass(EndPoint, null, [{
32837 key: "transform",
32838
32839 /**
32840 * Apply transformation on points for display.
32841 *
32842 * The following is done:
32843 * - rotate by the specified angle
32844 * - multiply the (normalized) coordinates by the passed length
32845 * - offset by the target coordinates
32846 *
32847 * @param points - The point(s) to be transformed.
32848 * @param arrowData - The data determining the result of the transformation.
32849 */
32850 value: function transform(points, arrowData) {
32851 if (!Array.isArray(points)) {
32852 points = [points];
32853 }
32854
32855 var x = arrowData.point.x;
32856 var y = arrowData.point.y;
32857 var angle = arrowData.angle;
32858 var length = arrowData.length;
32859
32860 for (var i = 0; i < points.length; ++i) {
32861 var p = points[i];
32862 var xt = p.x * Math.cos(angle) - p.y * Math.sin(angle);
32863 var yt = p.x * Math.sin(angle) + p.y * Math.cos(angle);
32864 p.x = x + length * xt;
32865 p.y = y + length * yt;
32866 }
32867 }
32868 /**
32869 * Draw a closed path using the given real coordinates.
32870 *
32871 * @param ctx - The path will be rendered into this context.
32872 * @param points - The points of the path.
32873 */
32874
32875 }, {
32876 key: "drawPath",
32877 value: function drawPath(ctx, points) {
32878 ctx.beginPath();
32879 ctx.moveTo(points[0].x, points[0].y);
32880
32881 for (var i = 1; i < points.length; ++i) {
32882 ctx.lineTo(points[i].x, points[i].y);
32883 }
32884
32885 ctx.closePath();
32886 }
32887 }]);
32888
32889 return EndPoint;
32890 }();
32891 /**
32892 * Drawing methods for the arrow endpoint.
32893 */
32894
32895
32896 var Image$2 =
32897 /*#__PURE__*/
32898 function (_EndPoint) {
32899 _inherits(Image, _EndPoint);
32900
32901 function Image() {
32902 _classCallCheck(this, Image);
32903
32904 return _possibleConstructorReturn(this, _getPrototypeOf(Image).apply(this, arguments));
32905 }
32906
32907 _createClass(Image, null, [{
32908 key: "draw",
32909
32910 /**
32911 * Draw this shape at the end of a line.
32912 *
32913 * @param ctx - The shape will be rendered into this context.
32914 * @param arrowData - The data determining the shape.
32915 *
32916 * @returns False as there is no way to fill an image.
32917 */
32918 value: function draw(ctx, arrowData) {
32919 if (arrowData.image) {
32920 ctx.save();
32921 ctx.translate(arrowData.point.x, arrowData.point.y);
32922 ctx.rotate(Math.PI / 2 + arrowData.angle);
32923 var width = arrowData.imageWidth != null ? arrowData.imageWidth : arrowData.image.width;
32924 var height = arrowData.imageHeight != null ? arrowData.imageHeight : arrowData.image.height;
32925 arrowData.image.drawImageAtPosition(ctx, 1, // scale
32926 -width / 2, // x
32927 0, // y
32928 width, height);
32929 ctx.restore();
32930 }
32931
32932 return false;
32933 }
32934 }]);
32935
32936 return Image;
32937 }(EndPoint);
32938 /**
32939 * Drawing methods for the arrow endpoint.
32940 */
32941
32942
32943 var Arrow =
32944 /*#__PURE__*/
32945 function (_EndPoint2) {
32946 _inherits(Arrow, _EndPoint2);
32947
32948 function Arrow() {
32949 _classCallCheck(this, Arrow);
32950
32951 return _possibleConstructorReturn(this, _getPrototypeOf(Arrow).apply(this, arguments));
32952 }
32953
32954 _createClass(Arrow, null, [{
32955 key: "draw",
32956
32957 /**
32958 * Draw this shape at the end of a line.
32959 *
32960 * @param ctx - The shape will be rendered into this context.
32961 * @param arrowData - The data determining the shape.
32962 *
32963 * @returns True because ctx.fill() can be used to fill the arrow.
32964 */
32965 value: function draw(ctx, arrowData) {
32966 // Normalized points of closed path, in the order that they should be drawn.
32967 // (0, 0) is the attachment point, and the point around which should be rotated
32968 var points = [{
32969 x: 0,
32970 y: 0
32971 }, {
32972 x: -1,
32973 y: 0.3
32974 }, {
32975 x: -0.9,
32976 y: 0
32977 }, {
32978 x: -1,
32979 y: -0.3
32980 }];
32981 EndPoint.transform(points, arrowData);
32982 EndPoint.drawPath(ctx, points);
32983 return true;
32984 }
32985 }]);
32986
32987 return Arrow;
32988 }(EndPoint);
32989 /**
32990 * Drawing methods for the crow endpoint.
32991 */
32992
32993
32994 var Crow =
32995 /*#__PURE__*/
32996 function () {
32997 function Crow() {
32998 _classCallCheck(this, Crow);
32999 }
33000
33001 _createClass(Crow, null, [{
33002 key: "draw",
33003
33004 /**
33005 * Draw this shape at the end of a line.
33006 *
33007 * @param ctx - The shape will be rendered into this context.
33008 * @param arrowData - The data determining the shape.
33009 *
33010 * @returns True because ctx.fill() can be used to fill the arrow.
33011 */
33012 value: function draw(ctx, arrowData) {
33013 // Normalized points of closed path, in the order that they should be drawn.
33014 // (0, 0) is the attachment point, and the point around which should be rotated
33015 var points = [{
33016 x: -1,
33017 y: 0
33018 }, {
33019 x: 0,
33020 y: 0.3
33021 }, {
33022 x: -0.4,
33023 y: 0
33024 }, {
33025 x: 0,
33026 y: -0.3
33027 }];
33028 EndPoint.transform(points, arrowData);
33029 EndPoint.drawPath(ctx, points);
33030 return true;
33031 }
33032 }]);
33033
33034 return Crow;
33035 }();
33036 /**
33037 * Drawing methods for the curve endpoint.
33038 */
33039
33040
33041 var Curve =
33042 /*#__PURE__*/
33043 function () {
33044 function Curve() {
33045 _classCallCheck(this, Curve);
33046 }
33047
33048 _createClass(Curve, null, [{
33049 key: "draw",
33050
33051 /**
33052 * Draw this shape at the end of a line.
33053 *
33054 * @param ctx - The shape will be rendered into this context.
33055 * @param arrowData - The data determining the shape.
33056 *
33057 * @returns True because ctx.fill() can be used to fill the arrow.
33058 */
33059 value: function draw(ctx, arrowData) {
33060 // Normalized points of closed path, in the order that they should be drawn.
33061 // (0, 0) is the attachment point, and the point around which should be rotated
33062 var point = {
33063 x: -0.4,
33064 y: 0
33065 };
33066 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
33067
33068 ctx.strokeStyle = ctx.fillStyle;
33069 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define curve endpoint as semicircle.
33070
33071 var pi = Math.PI;
33072 var startAngle = arrowData.angle - pi / 2;
33073 var endAngle = arrowData.angle + pi / 2;
33074 ctx.beginPath();
33075 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
33076 ctx.stroke();
33077 return true;
33078 }
33079 }]);
33080
33081 return Curve;
33082 }();
33083 /**
33084 * Drawing methods for the inverted curve endpoint.
33085 */
33086
33087
33088 var InvertedCurve =
33089 /*#__PURE__*/
33090 function () {
33091 function InvertedCurve() {
33092 _classCallCheck(this, InvertedCurve);
33093 }
33094
33095 _createClass(InvertedCurve, null, [{
33096 key: "draw",
33097
33098 /**
33099 * Draw this shape at the end of a line.
33100 *
33101 * @param ctx - The shape will be rendered into this context.
33102 * @param arrowData - The data determining the shape.
33103 *
33104 * @returns True because ctx.fill() can be used to fill the arrow.
33105 */
33106 value: function draw(ctx, arrowData) {
33107 // Normalized points of closed path, in the order that they should be drawn.
33108 // (0, 0) is the attachment point, and the point around which should be rotated
33109 var point = {
33110 x: -0.3,
33111 y: 0
33112 };
33113 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
33114
33115 ctx.strokeStyle = ctx.fillStyle;
33116 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define inverted curve endpoint as semicircle.
33117
33118 var pi = Math.PI;
33119 var startAngle = arrowData.angle + pi / 2;
33120 var endAngle = arrowData.angle + 3 * pi / 2;
33121 ctx.beginPath();
33122 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
33123 ctx.stroke();
33124 return true;
33125 }
33126 }]);
33127
33128 return InvertedCurve;
33129 }();
33130 /**
33131 * Drawing methods for the trinagle endpoint.
33132 */
33133
33134
33135 var Triangle$1 =
33136 /*#__PURE__*/
33137 function () {
33138 function Triangle() {
33139 _classCallCheck(this, Triangle);
33140 }
33141
33142 _createClass(Triangle, null, [{
33143 key: "draw",
33144
33145 /**
33146 * Draw this shape at the end of a line.
33147 *
33148 * @param ctx - The shape will be rendered into this context.
33149 * @param arrowData - The data determining the shape.
33150 *
33151 * @returns True because ctx.fill() can be used to fill the arrow.
33152 */
33153 value: function draw(ctx, arrowData) {
33154 // Normalized points of closed path, in the order that they should be drawn.
33155 // (0, 0) is the attachment point, and the point around which should be rotated
33156 var points = [{
33157 x: 0.02,
33158 y: 0
33159 }, {
33160 x: -1,
33161 y: 0.3
33162 }, {
33163 x: -1,
33164 y: -0.3
33165 }];
33166 EndPoint.transform(points, arrowData);
33167 EndPoint.drawPath(ctx, points);
33168 return true;
33169 }
33170 }]);
33171
33172 return Triangle;
33173 }();
33174 /**
33175 * Drawing methods for the inverted trinagle endpoint.
33176 */
33177
33178
33179 var InvertedTriangle =
33180 /*#__PURE__*/
33181 function () {
33182 function InvertedTriangle() {
33183 _classCallCheck(this, InvertedTriangle);
33184 }
33185
33186 _createClass(InvertedTriangle, null, [{
33187 key: "draw",
33188
33189 /**
33190 * Draw this shape at the end of a line.
33191 *
33192 * @param ctx - The shape will be rendered into this context.
33193 * @param arrowData - The data determining the shape.
33194 *
33195 * @returns True because ctx.fill() can be used to fill the arrow.
33196 */
33197 value: function draw(ctx, arrowData) {
33198 // Normalized points of closed path, in the order that they should be drawn.
33199 // (0, 0) is the attachment point, and the point around which should be rotated
33200 var points = [{
33201 x: 0,
33202 y: 0.3
33203 }, {
33204 x: 0,
33205 y: -0.3
33206 }, {
33207 x: -1,
33208 y: 0
33209 }];
33210 EndPoint.transform(points, arrowData);
33211 EndPoint.drawPath(ctx, points);
33212 return true;
33213 }
33214 }]);
33215
33216 return InvertedTriangle;
33217 }();
33218 /**
33219 * Drawing methods for the circle endpoint.
33220 */
33221
33222
33223 var Circle$1 =
33224 /*#__PURE__*/
33225 function () {
33226 function Circle() {
33227 _classCallCheck(this, Circle);
33228 }
33229
33230 _createClass(Circle, null, [{
33231 key: "draw",
33232
33233 /**
33234 * Draw this shape at the end of a line.
33235 *
33236 * @param ctx - The shape will be rendered into this context.
33237 * @param arrowData - The data determining the shape.
33238 *
33239 * @returns True because ctx.fill() can be used to fill the arrow.
33240 */
33241 value: function draw(ctx, arrowData) {
33242 var point = {
33243 x: -0.4,
33244 y: 0
33245 };
33246 EndPoint.transform(point, arrowData);
33247 ctx.circle(point.x, point.y, arrowData.length * 0.4);
33248 return true;
33249 }
33250 }]);
33251
33252 return Circle;
33253 }();
33254 /**
33255 * Drawing methods for the bar endpoint.
33256 */
33257
33258
33259 var Bar =
33260 /*#__PURE__*/
33261 function () {
33262 function Bar() {
33263 _classCallCheck(this, Bar);
33264 }
33265
33266 _createClass(Bar, null, [{
33267 key: "draw",
33268
33269 /**
33270 * Draw this shape at the end of a line.
33271 *
33272 * @param ctx - The shape will be rendered into this context.
33273 * @param arrowData - The data determining the shape.
33274 *
33275 * @returns True because ctx.fill() can be used to fill the arrow.
33276 */
33277 value: function draw(ctx, arrowData) {
33278 /*
33279 var points = [
33280 {x:0, y:0.5},
33281 {x:0, y:-0.5}
33282 ];
33283 EndPoint.transform(points, arrowData);
33284 ctx.beginPath();
33285 ctx.moveTo(points[0].x, points[0].y);
33286 ctx.lineTo(points[1].x, points[1].y);
33287 ctx.stroke();
33288 */
33289 var points = [{
33290 x: 0,
33291 y: 0.5
33292 }, {
33293 x: 0,
33294 y: -0.5
33295 }, {
33296 x: -0.15,
33297 y: -0.5
33298 }, {
33299 x: -0.15,
33300 y: 0.5
33301 }];
33302 EndPoint.transform(points, arrowData);
33303 EndPoint.drawPath(ctx, points);
33304 return true;
33305 }
33306 }]);
33307
33308 return Bar;
33309 }();
33310 /**
33311 * Drawing methods for the box endpoint.
33312 */
33313
33314
33315 var Box$1 =
33316 /*#__PURE__*/
33317 function () {
33318 function Box() {
33319 _classCallCheck(this, Box);
33320 }
33321
33322 _createClass(Box, null, [{
33323 key: "draw",
33324
33325 /**
33326 * Draw this shape at the end of a line.
33327 *
33328 * @param ctx - The shape will be rendered into this context.
33329 * @param arrowData - The data determining the shape.
33330 *
33331 * @returns True because ctx.fill() can be used to fill the arrow.
33332 */
33333 value: function draw(ctx, arrowData) {
33334 var points = [{
33335 x: 0,
33336 y: 0.3
33337 }, {
33338 x: 0,
33339 y: -0.3
33340 }, {
33341 x: -0.6,
33342 y: -0.3
33343 }, {
33344 x: -0.6,
33345 y: 0.3
33346 }];
33347 EndPoint.transform(points, arrowData);
33348 EndPoint.drawPath(ctx, points);
33349 return true;
33350 }
33351 }]);
33352
33353 return Box;
33354 }();
33355 /**
33356 * Drawing methods for the diamond endpoint.
33357 */
33358
33359
33360 var Diamond$1 =
33361 /*#__PURE__*/
33362 function () {
33363 function Diamond() {
33364 _classCallCheck(this, Diamond);
33365 }
33366
33367 _createClass(Diamond, null, [{
33368 key: "draw",
33369
33370 /**
33371 * Draw this shape at the end of a line.
33372 *
33373 * @param ctx - The shape will be rendered into this context.
33374 * @param arrowData - The data determining the shape.
33375 *
33376 * @returns True because ctx.fill() can be used to fill the arrow.
33377 */
33378 value: function draw(ctx, arrowData) {
33379 var points = [{
33380 x: 0,
33381 y: 0
33382 }, {
33383 x: -0.5,
33384 y: -0.3
33385 }, {
33386 x: -1,
33387 y: 0
33388 }, {
33389 x: -0.5,
33390 y: 0.3
33391 }];
33392 EndPoint.transform(points, arrowData);
33393 EndPoint.drawPath(ctx, points);
33394 return true;
33395 }
33396 }]);
33397
33398 return Diamond;
33399 }();
33400 /**
33401 * Drawing methods for the vee endpoint.
33402 */
33403
33404
33405 var Vee =
33406 /*#__PURE__*/
33407 function () {
33408 function Vee() {
33409 _classCallCheck(this, Vee);
33410 }
33411
33412 _createClass(Vee, null, [{
33413 key: "draw",
33414
33415 /**
33416 * Draw this shape at the end of a line.
33417 *
33418 * @param ctx - The shape will be rendered into this context.
33419 * @param arrowData - The data determining the shape.
33420 *
33421 * @returns True because ctx.fill() can be used to fill the arrow.
33422 */
33423 value: function draw(ctx, arrowData) {
33424 // Normalized points of closed path, in the order that they should be drawn.
33425 // (0, 0) is the attachment point, and the point around which should be rotated
33426 var points = [{
33427 x: -1,
33428 y: 0.3
33429 }, {
33430 x: -0.5,
33431 y: 0
33432 }, {
33433 x: -1,
33434 y: -0.3
33435 }, {
33436 x: 0,
33437 y: 0
33438 }];
33439 EndPoint.transform(points, arrowData);
33440 EndPoint.drawPath(ctx, points);
33441 return true;
33442 }
33443 }]);
33444
33445 return Vee;
33446 }();
33447 /**
33448 * Drawing methods for the endpoints.
33449 */
33450
33451
33452 var EndPoints =
33453 /*#__PURE__*/
33454 function () {
33455 function EndPoints() {
33456 _classCallCheck(this, EndPoints);
33457 }
33458
33459 _createClass(EndPoints, null, [{
33460 key: "draw",
33461
33462 /**
33463 * Draw an endpoint.
33464 *
33465 * @param ctx - The shape will be rendered into this context.
33466 * @param arrowData - The data determining the shape.
33467 *
33468 * @returns True if ctx.fill() can be used to fill the arrow, false otherwise.
33469 */
33470 value: function draw(ctx, arrowData) {
33471 var type;
33472
33473 if (arrowData.type) {
33474 type = arrowData.type.toLowerCase();
33475 }
33476
33477 switch (type) {
33478 case "image":
33479 return Image$2.draw(ctx, arrowData);
33480
33481 case "circle":
33482 return Circle$1.draw(ctx, arrowData);
33483
33484 case "box":
33485 return Box$1.draw(ctx, arrowData);
33486
33487 case "crow":
33488 return Crow.draw(ctx, arrowData);
33489
33490 case "curve":
33491 return Curve.draw(ctx, arrowData);
33492
33493 case "diamond":
33494 return Diamond$1.draw(ctx, arrowData);
33495
33496 case "inv_curve":
33497 return InvertedCurve.draw(ctx, arrowData);
33498
33499 case "triangle":
33500 return Triangle$1.draw(ctx, arrowData);
33501
33502 case "inv_triangle":
33503 return InvertedTriangle.draw(ctx, arrowData);
33504
33505 case "bar":
33506 return Bar.draw(ctx, arrowData);
33507
33508 case "vee":
33509 return Vee.draw(ctx, arrowData);
33510
33511 case "arrow": // fall-through
33512
33513 default:
33514 return Arrow.draw(ctx, arrowData);
33515 }
33516 }
33517 }]);
33518
33519 return EndPoints;
33520 }();
33521
33522 /**
33523 * The Base Class for all edges.
33524 */
33525
33526 var EdgeBase =
33527 /*#__PURE__*/
33528 function () {
33529 /**
33530 * Create a new instance.
33531 *
33532 * @param options - The options object of given edge.
33533 * @param _body - The body of the network.
33534 * @param _labelModule - Label module.
33535 */
33536 function EdgeBase(options, _body, _labelModule) {
33537 _classCallCheck(this, EdgeBase);
33538
33539 this._body = _body;
33540 this._labelModule = _labelModule;
33541 this.color = {};
33542 this.colorDirty = true;
33543 this.hoverWidth = 1.5;
33544 this.selectionWidth = 2;
33545 this.setOptions(options);
33546 this.fromPoint = this.from;
33547 this.toPoint = this.to;
33548 }
33549 /** @inheritdoc */
33550
33551
33552 _createClass(EdgeBase, [{
33553 key: "connect",
33554 value: function connect() {
33555 this.from = this._body.nodes[this.options.from];
33556 this.to = this._body.nodes[this.options.to];
33557 }
33558 /** @inheritdoc */
33559
33560 }, {
33561 key: "cleanup",
33562 value: function cleanup() {
33563 return false;
33564 }
33565 /**
33566 * Set new edge options.
33567 *
33568 * @param options - The new edge options object.
33569 */
33570
33571 }, {
33572 key: "setOptions",
33573 value: function setOptions(options) {
33574 this.options = options;
33575 this.from = this._body.nodes[this.options.from];
33576 this.to = this._body.nodes[this.options.to];
33577 this.id = this.options.id;
33578 }
33579 /** @inheritdoc */
33580
33581 }, {
33582 key: "drawLine",
33583 value: function drawLine(ctx, values, _selected, _hover) {
33584 var viaNode = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : this.getViaNode();
33585 // set style
33586 ctx.strokeStyle = this.getColor(ctx, values);
33587 ctx.lineWidth = values.width;
33588
33589 if (values.dashes !== false) {
33590 this._drawDashedLine(ctx, values, viaNode);
33591 } else {
33592 this._drawLine(ctx, values, viaNode);
33593 }
33594 }
33595 /**
33596 * Draw a line with given style between two nodes through supplied node(s).
33597 *
33598 * @param ctx - The context that will be used for rendering.
33599 * @param values - Formatting values like color, opacity or shadow.
33600 * @param viaNode - Additional control point(s) for the edge.
33601 * @param fromPoint - TODO: Seems ignored, remove?
33602 * @param toPoint - TODO: Seems ignored, remove?
33603 */
33604
33605 }, {
33606 key: "_drawLine",
33607 value: function _drawLine(ctx, values, viaNode, fromPoint, toPoint) {
33608 if (this.from != this.to) {
33609 // draw line
33610 this._line(ctx, values, viaNode, fromPoint, toPoint);
33611 } else {
33612 var _this$_getCircleData = this._getCircleData(ctx),
33613 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
33614 x = _this$_getCircleData2[0],
33615 y = _this$_getCircleData2[1],
33616 radius = _this$_getCircleData2[2];
33617
33618 this._circle(ctx, values, x, y, radius);
33619 }
33620 }
33621 /**
33622 * Draw a dashed line with given style between two nodes through supplied node(s).
33623 *
33624 * @param ctx - The context that will be used for rendering.
33625 * @param values - Formatting values like color, opacity or shadow.
33626 * @param viaNode - Additional control point(s) for the edge.
33627 * @param _fromPoint - Ignored (TODO: remove in the future).
33628 * @param _toPoint - Ignored (TODO: remove in the future).
33629 */
33630
33631 }, {
33632 key: "_drawDashedLine",
33633 value: function _drawDashedLine(ctx, values, viaNode, _fromPoint, _toPoint) {
33634 ctx.lineCap = "round";
33635 var pattern = Array.isArray(values.dashes) ? values.dashes : [5, 5]; // only firefox and chrome support this method, else we use the legacy one.
33636
33637 if (ctx.setLineDash !== undefined) {
33638 ctx.save(); // set dash settings for chrome or firefox
33639
33640 ctx.setLineDash(pattern);
33641 ctx.lineDashOffset = 0; // draw the line
33642
33643 if (this.from != this.to) {
33644 // draw line
33645 this._line(ctx, values, viaNode);
33646 } else {
33647 var _this$_getCircleData3 = this._getCircleData(ctx),
33648 _this$_getCircleData4 = _slicedToArray(_this$_getCircleData3, 3),
33649 x = _this$_getCircleData4[0],
33650 y = _this$_getCircleData4[1],
33651 radius = _this$_getCircleData4[2];
33652
33653 this._circle(ctx, values, x, y, radius);
33654 } // restore the dash settings.
33655
33656
33657 ctx.setLineDash([0]);
33658 ctx.lineDashOffset = 0;
33659 ctx.restore();
33660 } else {
33661 // unsupporting smooth lines
33662 if (this.from != this.to) {
33663 // draw line
33664 ctx.dashedLine(this.from.x, this.from.y, this.to.x, this.to.y, pattern);
33665 } else {
33666 var _this$_getCircleData5 = this._getCircleData(ctx),
33667 _this$_getCircleData6 = _slicedToArray(_this$_getCircleData5, 3),
33668 _x = _this$_getCircleData6[0],
33669 _y = _this$_getCircleData6[1],
33670 _radius = _this$_getCircleData6[2];
33671
33672 this._circle(ctx, values, _x, _y, _radius);
33673 } // draw shadow if enabled
33674
33675
33676 this.enableShadow(ctx, values);
33677 ctx.stroke(); // disable shadows for other elements.
33678
33679 this.disableShadow(ctx, values);
33680 }
33681 }
33682 /**
33683 * Find the intersection between the border of the node and the edge.
33684 *
33685 * @param node - The node (either from or to node of the edge).
33686 * @param ctx - The context that will be used for rendering.
33687 * @param options - Additional options.
33688 *
33689 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
33690 */
33691
33692 }, {
33693 key: "findBorderPosition",
33694 value: function findBorderPosition(node, ctx, options) {
33695 if (this.from != this.to) {
33696 return this._findBorderPosition(node, ctx, options);
33697 } else {
33698 return this._findBorderPositionCircle(node, ctx, options);
33699 }
33700 }
33701 /** @inheritdoc */
33702
33703 }, {
33704 key: "findBorderPositions",
33705 value: function findBorderPositions(ctx) {
33706 if (this.from != this.to) {
33707 return {
33708 from: this._findBorderPosition(this.from, ctx),
33709 to: this._findBorderPosition(this.to, ctx)
33710 };
33711 } else {
33712 var _this$_getCircleData$ = this._getCircleData(ctx).slice(0, 2),
33713 _this$_getCircleData$2 = _slicedToArray(_this$_getCircleData$, 2),
33714 x = _this$_getCircleData$2[0],
33715 y = _this$_getCircleData$2[1];
33716
33717 return {
33718 from: this._findBorderPositionCircle(this.from, ctx, {
33719 x: x,
33720 y: y,
33721 low: 0.25,
33722 high: 0.6,
33723 direction: -1
33724 }),
33725 to: this._findBorderPositionCircle(this.from, ctx, {
33726 x: x,
33727 y: y,
33728 low: 0.6,
33729 high: 0.8,
33730 direction: 1
33731 })
33732 };
33733 }
33734 }
33735 /**
33736 * Compute the center point and radius of an edge connected to the same node at both ends.
33737 *
33738 * @param ctx - The context that will be used for rendering.
33739 *
33740 * @returns `[x, y, radius]`
33741 */
33742
33743 }, {
33744 key: "_getCircleData",
33745 value: function _getCircleData(ctx) {
33746 var x;
33747 var y;
33748 var node = this.from;
33749 var radius = this.options.selfReferenceSize;
33750
33751 if (ctx !== undefined) {
33752 if (node.shape.width === undefined) {
33753 node.shape.resize(ctx);
33754 }
33755 } // get circle coordinates
33756
33757
33758 if (node.shape.width > node.shape.height) {
33759 x = node.x + node.shape.width * 0.5;
33760 y = node.y - radius;
33761 } else {
33762 x = node.x + radius;
33763 y = node.y - node.shape.height * 0.5;
33764 }
33765
33766 return [x, y, radius];
33767 }
33768 /**
33769 * Get a point on a circle.
33770 *
33771 * @param x - Center of the circle on the x axis.
33772 * @param y - Center of the circle on the y axis.
33773 * @param radius - Radius of the circle.
33774 * @param position - Value between 0 (line start) and 1 (line end).
33775 *
33776 * @returns Cartesian coordinates of requested point on the circle.
33777 */
33778
33779 }, {
33780 key: "_pointOnCircle",
33781 value: function _pointOnCircle(x, y, radius, position) {
33782 var angle = position * 2 * Math.PI;
33783 return {
33784 x: x + radius * Math.cos(angle),
33785 y: y - radius * Math.sin(angle)
33786 };
33787 }
33788 /**
33789 * Find the intersection between the border of the node and the edge.
33790 *
33791 * @remarks
33792 * This function uses binary search to look for the point where the circle crosses the border of the node.
33793 *
33794 * @param nearNode - The node (either from or to node of the edge).
33795 * @param ctx - The context that will be used for rendering.
33796 * @param options - Additional options.
33797 *
33798 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
33799 */
33800
33801 }, {
33802 key: "_findBorderPositionCircle",
33803 value: function _findBorderPositionCircle(nearNode, ctx, options) {
33804 var x = options.x;
33805 var y = options.y;
33806 var low = options.low;
33807 var high = options.high;
33808 var direction = options.direction;
33809 var maxIterations = 10;
33810 var radius = this.options.selfReferenceSize;
33811 var threshold = 0.05;
33812 var pos;
33813 var middle = (low + high) * 0.5;
33814 var iteration = 0;
33815
33816 do {
33817 middle = (low + high) * 0.5;
33818 pos = this._pointOnCircle(x, y, radius, middle);
33819 var angle = Math.atan2(nearNode.y - pos.y, nearNode.x - pos.x);
33820 var distanceToBorder = nearNode.distanceToBorder(ctx, angle);
33821 var distanceToPoint = Math.sqrt(Math.pow(pos.x - nearNode.x, 2) + Math.pow(pos.y - nearNode.y, 2));
33822 var difference = distanceToBorder - distanceToPoint;
33823
33824 if (Math.abs(difference) < threshold) {
33825 break; // found
33826 } else if (difference > 0) {
33827 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
33828 if (direction > 0) {
33829 low = middle;
33830 } else {
33831 high = middle;
33832 }
33833 } else {
33834 if (direction > 0) {
33835 high = middle;
33836 } else {
33837 low = middle;
33838 }
33839 }
33840
33841 ++iteration;
33842 } while (low <= high && iteration < maxIterations);
33843
33844 return _objectSpread2$1({}, pos, {
33845 t: middle
33846 });
33847 }
33848 /**
33849 * Get the line width of the edge. Depends on width and whether one of the connected nodes is selected.
33850 *
33851 * @param selected - Determines wheter the line is selected.
33852 * @param hover - Determines wheter the line is being hovered, only applies if selected is false.
33853 *
33854 * @returns The width of the line.
33855 */
33856
33857 }, {
33858 key: "getLineWidth",
33859 value: function getLineWidth(selected, hover) {
33860 if (selected === true) {
33861 return Math.max(this.selectionWidth, 0.3 / this._body.view.scale);
33862 } else if (hover === true) {
33863 return Math.max(this.hoverWidth, 0.3 / this._body.view.scale);
33864 } else {
33865 return Math.max(this.options.width, 0.3 / this._body.view.scale);
33866 }
33867 }
33868 /**
33869 * Compute the color or gradient for given edge.
33870 *
33871 * @param ctx - The context that will be used for rendering.
33872 * @param values - Formatting values like color, opacity or shadow.
33873 * @param _selected - Ignored (TODO: remove in the future).
33874 * @param _hover - Ignored (TODO: remove in the future).
33875 *
33876 * @returns Color string if single color is inherited or gradient if two.
33877 */
33878
33879 }, {
33880 key: "getColor",
33881 value: function getColor(ctx, values) {
33882 if (values.inheritsColor !== false) {
33883 // when this is a loop edge, just use the 'from' method
33884 if (values.inheritsColor === "both" && this.from.id !== this.to.id) {
33885 var grd = ctx.createLinearGradient(this.from.x, this.from.y, this.to.x, this.to.y);
33886 var fromColor = this.from.options.color.highlight.border;
33887 var toColor = this.to.options.color.highlight.border;
33888
33889 if (this.from.selected === false && this.to.selected === false) {
33890 fromColor = overrideOpacity(this.from.options.color.border, values.opacity);
33891 toColor = overrideOpacity(this.to.options.color.border, values.opacity);
33892 } else if (this.from.selected === true && this.to.selected === false) {
33893 toColor = this.to.options.color.border;
33894 } else if (this.from.selected === false && this.to.selected === true) {
33895 fromColor = this.from.options.color.border;
33896 }
33897
33898 grd.addColorStop(0, fromColor);
33899 grd.addColorStop(1, toColor); // -------------------- this returns -------------------- //
33900
33901 return grd;
33902 }
33903
33904 if (values.inheritsColor === "to") {
33905 return overrideOpacity(this.to.options.color.border, values.opacity);
33906 } else {
33907 // "from"
33908 return overrideOpacity(this.from.options.color.border, values.opacity);
33909 }
33910 } else {
33911 return overrideOpacity(values.color, values.opacity);
33912 }
33913 }
33914 /**
33915 * Draw a line from a node to itself, a circle.
33916 *
33917 * @param ctx - The context that will be used for rendering.
33918 * @param values - Formatting values like color, opacity or shadow.
33919 * @param x - Center of the circle on the x axis.
33920 * @param y - Center of the circle on the y axis.
33921 * @param radius - Radius of the circle.
33922 */
33923
33924 }, {
33925 key: "_circle",
33926 value: function _circle(ctx, values, x, y, radius) {
33927 // draw shadow if enabled
33928 this.enableShadow(ctx, values); // draw a circle
33929
33930 ctx.beginPath();
33931 ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
33932 ctx.stroke(); // disable shadows for other elements.
33933
33934 this.disableShadow(ctx, values);
33935 }
33936 /**
33937 * @inheritdoc
33938 *
33939 * @remarks
33940 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
33941 */
33942
33943 }, {
33944 key: "getDistanceToEdge",
33945 value: function getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
33946 if (this.from != this.to) {
33947 return this._getDistanceToEdge(x1, y1, x2, y2, x3, y3);
33948 } else {
33949 var _this$_getCircleData7 = this._getCircleData(undefined),
33950 _this$_getCircleData8 = _slicedToArray(_this$_getCircleData7, 3),
33951 x = _this$_getCircleData8[0],
33952 y = _this$_getCircleData8[1],
33953 radius = _this$_getCircleData8[2];
33954
33955 var dx = x - x3;
33956 var dy = y - y3;
33957 return Math.abs(Math.sqrt(dx * dx + dy * dy) - radius);
33958 }
33959 }
33960 /**
33961 * Calculate the distance between a point (x3, y3) and a line segment from (x1, y1) to (x2, y2).
33962 *
33963 * @param x1 - First end of the line segment on the x axis.
33964 * @param y1 - First end of the line segment on the y axis.
33965 * @param x2 - Second end of the line segment on the x axis.
33966 * @param y2 - Second end of the line segment on the y axis.
33967 * @param x3 - Position of the point on the x axis.
33968 * @param y3 - Position of the point on the y axis.
33969 *
33970 * @returns The distance between the line segment and the point.
33971 */
33972
33973 }, {
33974 key: "_getDistanceToLine",
33975 value: function _getDistanceToLine(x1, y1, x2, y2, x3, y3) {
33976 var px = x2 - x1;
33977 var py = y2 - y1;
33978 var something = px * px + py * py;
33979 var u = ((x3 - x1) * px + (y3 - y1) * py) / something;
33980
33981 if (u > 1) {
33982 u = 1;
33983 } else if (u < 0) {
33984 u = 0;
33985 }
33986
33987 var x = x1 + u * px;
33988 var y = y1 + u * py;
33989 var dx = x - x3;
33990 var dy = y - y3; //# Note: If the actual distance does not matter,
33991 //# if you only want to compare what this function
33992 //# returns to other results of this function, you
33993 //# can just return the squared distance instead
33994 //# (i.e. remove the sqrt) to gain a little performance
33995
33996 return Math.sqrt(dx * dx + dy * dy);
33997 }
33998 /** @inheritdoc */
33999
34000 }, {
34001 key: "getArrowData",
34002 value: function getArrowData(ctx, position, viaNode, _selected, _hover, values) {
34003 // set lets
34004 var angle;
34005 var arrowPoint;
34006 var node1;
34007 var node2;
34008 var reversed;
34009 var scaleFactor;
34010 var type;
34011 var lineWidth = values.width;
34012
34013 if (position === "from") {
34014 node1 = this.from;
34015 node2 = this.to;
34016 reversed = values.fromArrowScale < 0;
34017 scaleFactor = Math.abs(values.fromArrowScale);
34018 type = values.fromArrowType;
34019 } else if (position === "to") {
34020 node1 = this.to;
34021 node2 = this.from;
34022 reversed = values.toArrowScale < 0;
34023 scaleFactor = Math.abs(values.toArrowScale);
34024 type = values.toArrowType;
34025 } else {
34026 node1 = this.to;
34027 node2 = this.from;
34028 reversed = values.middleArrowScale < 0;
34029 scaleFactor = Math.abs(values.middleArrowScale);
34030 type = values.middleArrowType;
34031 }
34032
34033 var length = 15 * scaleFactor + 3 * lineWidth; // 3* lineWidth is the width of the edge.
34034 // if not connected to itself
34035
34036 if (node1 != node2) {
34037 var approximateEdgeLength = Math.hypot(node1.x - node2.x, node1.y - node2.y);
34038 var relativeLength = length / approximateEdgeLength;
34039
34040 if (position !== "middle") {
34041 // draw arrow head
34042 if (this.options.smooth.enabled === true) {
34043 var pointT = this._findBorderPosition(node1, ctx, {
34044 via: viaNode
34045 });
34046
34047 var guidePos = this.getPoint(pointT.t + relativeLength * (position === "from" ? 1 : -1), viaNode);
34048 angle = Math.atan2(pointT.y - guidePos.y, pointT.x - guidePos.x);
34049 arrowPoint = pointT;
34050 } else {
34051 angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
34052 arrowPoint = this._findBorderPosition(node1, ctx);
34053 }
34054 } else {
34055 // Negative half length reverses arrow direction.
34056 var halfLength = (reversed ? -relativeLength : relativeLength) / 2;
34057 var guidePos1 = this.getPoint(0.5 + halfLength, viaNode);
34058 var guidePos2 = this.getPoint(0.5 - halfLength, viaNode);
34059 angle = Math.atan2(guidePos1.y - guidePos2.y, guidePos1.x - guidePos2.x);
34060 arrowPoint = this.getPoint(0.5, viaNode);
34061 }
34062 } else {
34063 // draw circle
34064 var _this$_getCircleData9 = this._getCircleData(ctx),
34065 _this$_getCircleData10 = _slicedToArray(_this$_getCircleData9, 3),
34066 x = _this$_getCircleData10[0],
34067 y = _this$_getCircleData10[1],
34068 radius = _this$_getCircleData10[2];
34069
34070 if (position === "from") {
34071 var _pointT = this._findBorderPositionCircle(this.from, ctx, {
34072 x: x,
34073 y: y,
34074 low: 0.25,
34075 high: 0.6,
34076 direction: -1
34077 });
34078
34079 angle = _pointT.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
34080 arrowPoint = _pointT;
34081 } else if (position === "to") {
34082 var _pointT2 = this._findBorderPositionCircle(this.from, ctx, {
34083 x: x,
34084 y: y,
34085 low: 0.6,
34086 high: 1.0,
34087 direction: 1
34088 });
34089
34090 angle = _pointT2.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI;
34091 arrowPoint = _pointT2;
34092 } else {
34093 arrowPoint = this._pointOnCircle(x, y, radius, 0.175);
34094 angle = 3.9269908169872414; // === 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
34095 }
34096 }
34097
34098 var xi = arrowPoint.x - length * 0.9 * Math.cos(angle);
34099 var yi = arrowPoint.y - length * 0.9 * Math.sin(angle);
34100 var arrowCore = {
34101 x: xi,
34102 y: yi
34103 };
34104 return {
34105 point: arrowPoint,
34106 core: arrowCore,
34107 angle: angle,
34108 length: length,
34109 type: type
34110 };
34111 }
34112 /** @inheritdoc */
34113
34114 }, {
34115 key: "drawArrowHead",
34116 value: function drawArrowHead(ctx, values, _selected, _hover, arrowData) {
34117 // set style
34118 ctx.strokeStyle = this.getColor(ctx, values);
34119 ctx.fillStyle = ctx.strokeStyle;
34120 ctx.lineWidth = values.width;
34121 var canFill = EndPoints.draw(ctx, arrowData);
34122
34123 if (canFill) {
34124 // draw shadow if enabled
34125 this.enableShadow(ctx, values);
34126 ctx.fill(); // disable shadows for other elements.
34127
34128 this.disableShadow(ctx, values);
34129 }
34130 }
34131 /**
34132 * Set the shadow formatting values in the context if enabled, do nothing otherwise.
34133 *
34134 * @param ctx - The context that will be used for rendering.
34135 * @param values - Formatting values for the shadow.
34136 */
34137
34138 }, {
34139 key: "enableShadow",
34140 value: function enableShadow(ctx, values) {
34141 if (values.shadow === true) {
34142 ctx.shadowColor = values.shadowColor;
34143 ctx.shadowBlur = values.shadowSize;
34144 ctx.shadowOffsetX = values.shadowX;
34145 ctx.shadowOffsetY = values.shadowY;
34146 }
34147 }
34148 /**
34149 * Reset the shadow formatting values in the context if enabled, do nothing otherwise.
34150 *
34151 * @param ctx - The context that will be used for rendering.
34152 * @param values - Formatting values for the shadow.
34153 */
34154
34155 }, {
34156 key: "disableShadow",
34157 value: function disableShadow(ctx, values) {
34158 if (values.shadow === true) {
34159 ctx.shadowColor = "rgba(0,0,0,0)";
34160 ctx.shadowBlur = 0;
34161 ctx.shadowOffsetX = 0;
34162 ctx.shadowOffsetY = 0;
34163 }
34164 }
34165 /**
34166 * Render the background according to the formatting values.
34167 *
34168 * @param ctx - The context that will be used for rendering.
34169 * @param values - Formatting values for the background.
34170 */
34171
34172 }, {
34173 key: "drawBackground",
34174 value: function drawBackground(ctx, values) {
34175 if (values.background !== false) {
34176 // save original line attrs
34177 var origCtxAttr = {
34178 strokeStyle: ctx.strokeStyle,
34179 lineWidth: ctx.lineWidth,
34180 dashes: ctx.dashes
34181 };
34182 ctx.strokeStyle = values.backgroundColor;
34183 ctx.lineWidth = values.backgroundSize;
34184 this.setStrokeDashed(ctx, values.backgroundDashes);
34185 ctx.stroke(); // restore original line attrs
34186
34187 ctx.strokeStyle = origCtxAttr.strokeStyle;
34188 ctx.lineWidth = origCtxAttr.lineWidth;
34189 ctx.dashes = origCtxAttr.dashes;
34190 this.setStrokeDashed(ctx, values.dashes);
34191 }
34192 }
34193 /**
34194 * Set the line dash pattern if supported. Logs a warning to the console if it isn't supported.
34195 *
34196 * @param ctx - The context that will be used for rendering.
34197 * @param dashes - The pattern [line, space, line…], true for default dashed line or false for normal line.
34198 */
34199
34200 }, {
34201 key: "setStrokeDashed",
34202 value: function setStrokeDashed(ctx, dashes) {
34203 if (dashes !== false) {
34204 if (ctx.setLineDash !== undefined) {
34205 var pattern = Array.isArray(dashes) ? dashes : [5, 5];
34206 ctx.setLineDash(pattern);
34207 } else {
34208 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
34209 }
34210 } else {
34211 if (ctx.setLineDash !== undefined) {
34212 ctx.setLineDash([]);
34213 } else {
34214 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
34215 }
34216 }
34217 }
34218 }]);
34219
34220 return EdgeBase;
34221 }();
34222
34223 /**
34224 * The Base Class for all Bezier edges.
34225 * Bezier curves are used to model smooth gradual curves in paths between nodes.
34226 */
34227
34228 var BezierEdgeBase =
34229 /*#__PURE__*/
34230 function (_EdgeBase) {
34231 _inherits(BezierEdgeBase, _EdgeBase);
34232
34233 /**
34234 * Create a new instance.
34235 *
34236 * @param options - The options object of given edge.
34237 * @param body - The body of the network.
34238 * @param labelModule - Label module.
34239 */
34240 function BezierEdgeBase(options, body, labelModule) {
34241 _classCallCheck(this, BezierEdgeBase);
34242
34243 return _possibleConstructorReturn(this, _getPrototypeOf(BezierEdgeBase).call(this, options, body, labelModule));
34244 }
34245 /**
34246 * Find the intersection between the border of the node and the edge.
34247 *
34248 * @remarks
34249 * This function uses binary search to look for the point where the bezier curve crosses the border of the node.
34250 *
34251 * @param nearNode - The node (either from or to node of the edge).
34252 * @param ctx - The context that will be used for rendering.
34253 * @param viaNode - Additional node(s) the edge passes through.
34254 *
34255 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
34256 */
34257
34258
34259 _createClass(BezierEdgeBase, [{
34260 key: "_findBorderPositionBezier",
34261 value: function _findBorderPositionBezier(nearNode, ctx) {
34262 var viaNode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this._getViaCoordinates();
34263 var maxIterations = 10;
34264 var threshold = 0.2;
34265 var from = false;
34266 var high = 1;
34267 var low = 0;
34268 var node = this.to;
34269 var pos;
34270 var middle;
34271
34272 if (nearNode.id === this.from.id) {
34273 node = this.from;
34274 from = true;
34275 }
34276
34277 var iteration = 0;
34278
34279 do {
34280 middle = (low + high) * 0.5;
34281 pos = this.getPoint(middle, viaNode);
34282 var angle = Math.atan2(node.y - pos.y, node.x - pos.x);
34283 var distanceToBorder = node.distanceToBorder(ctx, angle);
34284 var distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2));
34285 var difference = distanceToBorder - distanceToPoint;
34286
34287 if (Math.abs(difference) < threshold) {
34288 break; // found
34289 } else if (difference < 0) {
34290 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
34291 if (from === false) {
34292 low = middle;
34293 } else {
34294 high = middle;
34295 }
34296 } else {
34297 if (from === false) {
34298 high = middle;
34299 } else {
34300 low = middle;
34301 }
34302 }
34303
34304 ++iteration;
34305 } while (low <= high && iteration < maxIterations);
34306
34307 return _objectSpread2$1({}, pos, {
34308 t: middle
34309 });
34310 }
34311 /**
34312 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
34313 *
34314 * @remarks
34315 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
34316 *
34317 * @param x1 - First end of the line segment on the x axis.
34318 * @param y1 - First end of the line segment on the y axis.
34319 * @param x2 - Second end of the line segment on the x axis.
34320 * @param y2 - Second end of the line segment on the y axis.
34321 * @param x3 - Position of the point on the x axis.
34322 * @param y3 - Position of the point on the y axis.
34323 * @param via - The control point for the edge.
34324 *
34325 * @returns The distance between the line segment and the point.
34326 */
34327
34328 }, {
34329 key: "_getDistanceToBezierEdge",
34330 value: function _getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via) {
34331 // x3,y3 is the point
34332 var minDistance = 1e9;
34333 var distance;
34334 var i, t, x, y;
34335 var lastX = x1;
34336 var lastY = y1;
34337
34338 for (i = 1; i < 10; i++) {
34339 t = 0.1 * i;
34340 x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * via.x + Math.pow(t, 2) * x2;
34341 y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * via.y + Math.pow(t, 2) * y2;
34342
34343 if (i > 0) {
34344 distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
34345 minDistance = distance < minDistance ? distance : minDistance;
34346 }
34347
34348 lastX = x;
34349 lastY = y;
34350 }
34351
34352 return minDistance;
34353 }
34354 /**
34355 * Render a bezier curve between two nodes.
34356 *
34357 * @remarks
34358 * The method accepts zero, one or two control points.
34359 * Passing zero control points just draws a straight line.
34360 *
34361 * @param ctx - The context that will be used for rendering.
34362 * @param values - Style options for edge drawing.
34363 * @param viaNode1 - First control point for curve drawing.
34364 * @param viaNode2 - Second control point for curve drawing.
34365 */
34366
34367 }, {
34368 key: "_bezierCurve",
34369 value: function _bezierCurve(ctx, values, viaNode1, viaNode2) {
34370 ctx.beginPath();
34371 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
34372
34373 if (viaNode1 != null && viaNode1.x != null) {
34374 if (viaNode2 != null && viaNode2.x != null) {
34375 ctx.bezierCurveTo(viaNode1.x, viaNode1.y, viaNode2.x, viaNode2.y, this.toPoint.x, this.toPoint.y);
34376 } else {
34377 ctx.quadraticCurveTo(viaNode1.x, viaNode1.y, this.toPoint.x, this.toPoint.y);
34378 }
34379 } else {
34380 // fallback to normal straight edge
34381 ctx.lineTo(this.toPoint.x, this.toPoint.y);
34382 } // draw a background
34383
34384
34385 this.drawBackground(ctx, values); // draw shadow if enabled
34386
34387 this.enableShadow(ctx, values);
34388 ctx.stroke();
34389 this.disableShadow(ctx, values);
34390 }
34391 /** @inheritdoc */
34392
34393 }, {
34394 key: "getViaNode",
34395 value: function getViaNode() {
34396 return this._getViaCoordinates();
34397 }
34398 }]);
34399
34400 return BezierEdgeBase;
34401 }(EdgeBase);
34402
34403 /**
34404 * A Dynamic Bezier Edge. Bezier curves are used to model smooth gradual
34405 * curves in paths between nodes. The Dynamic piece refers to how the curve
34406 * reacts to physics changes.
34407 *
34408 * @extends BezierEdgeBase
34409 */
34410
34411 var BezierEdgeDynamic =
34412 /*#__PURE__*/
34413 function (_BezierEdgeBase) {
34414 _inherits(BezierEdgeDynamic, _BezierEdgeBase);
34415
34416 /**
34417 * Create a new instance.
34418 *
34419 * @param options - The options object of given edge.
34420 * @param body - The body of the network.
34421 * @param labelModule - Label module.
34422 */
34423 function BezierEdgeDynamic(options, body, labelModule) {
34424 var _this;
34425
34426 _classCallCheck(this, BezierEdgeDynamic);
34427
34428 //this.via = undefined; // Here for completeness but not allowed to defined before super() is invoked.
34429 _this = _possibleConstructorReturn(this, _getPrototypeOf(BezierEdgeDynamic).call(this, options, body, labelModule)); // --> this calls the setOptions below
34430
34431 _this.via = _this.via; // constructor → super → super → setOptions → setupSupportNode
34432
34433 _this._boundFunction = function () {
34434 _this.positionBezierNode();
34435 };
34436
34437 _this._body.emitter.on("_repositionBezierNodes", _this._boundFunction);
34438
34439 return _this;
34440 }
34441 /** @inheritdoc */
34442
34443
34444 _createClass(BezierEdgeDynamic, [{
34445 key: "setOptions",
34446 value: function setOptions(options) {
34447 _get(_getPrototypeOf(BezierEdgeDynamic.prototype), "setOptions", this).call(this, options); // check if the physics has changed.
34448
34449
34450 var physicsChange = false;
34451
34452 if (this.options.physics !== options.physics) {
34453 physicsChange = true;
34454 } // set the options and the to and from nodes
34455
34456
34457 this.options = options;
34458 this.id = this.options.id;
34459 this.from = this._body.nodes[this.options.from];
34460 this.to = this._body.nodes[this.options.to]; // setup the support node and connect
34461
34462 this.setupSupportNode();
34463 this.connect(); // when we change the physics state of the edge, we reposition the support node.
34464
34465 if (physicsChange === true) {
34466 this.via.setOptions({
34467 physics: this.options.physics
34468 });
34469 this.positionBezierNode();
34470 }
34471 }
34472 /** @inheritdoc */
34473
34474 }, {
34475 key: "connect",
34476 value: function connect() {
34477 this.from = this._body.nodes[this.options.from];
34478 this.to = this._body.nodes[this.options.to];
34479
34480 if (this.from === undefined || this.to === undefined || this.options.physics === false) {
34481 this.via.setOptions({
34482 physics: false
34483 });
34484 } else {
34485 // fix weird behaviour where a self referencing node has physics enabled
34486 if (this.from.id === this.to.id) {
34487 this.via.setOptions({
34488 physics: false
34489 });
34490 } else {
34491 this.via.setOptions({
34492 physics: true
34493 });
34494 }
34495 }
34496 }
34497 /** @inheritdoc */
34498
34499 }, {
34500 key: "cleanup",
34501 value: function cleanup() {
34502 this._body.emitter.off("_repositionBezierNodes", this._boundFunction);
34503
34504 if (this.via !== undefined) {
34505 delete this._body.nodes[this.via.id];
34506 this.via = undefined;
34507 return true;
34508 }
34509
34510 return false;
34511 }
34512 /**
34513 * Create and add a support node if not already present.
34514 *
34515 * @remarks
34516 * Bezier curves require an anchor point to calculate the smooth flow.
34517 * These points are nodes.
34518 * These nodes are invisible but are used for the force calculation.
34519 *
34520 * The changed data is not called, if needed, it is returned by the main edge constructor.
34521 */
34522
34523 }, {
34524 key: "setupSupportNode",
34525 value: function setupSupportNode() {
34526 if (this.via === undefined) {
34527 var nodeId = "edgeId:" + this.id;
34528
34529 var node = this._body.functions.createNode({
34530 id: nodeId,
34531 shape: "circle",
34532 physics: true,
34533 hidden: true
34534 });
34535
34536 this._body.nodes[nodeId] = node;
34537 this.via = node;
34538 this.via.parentEdgeId = this.id;
34539 this.positionBezierNode();
34540 }
34541 }
34542 /**
34543 * Position bezier node.
34544 */
34545
34546 }, {
34547 key: "positionBezierNode",
34548 value: function positionBezierNode() {
34549 if (this.via !== undefined && this.from !== undefined && this.to !== undefined) {
34550 this.via.x = 0.5 * (this.from.x + this.to.x);
34551 this.via.y = 0.5 * (this.from.y + this.to.y);
34552 } else if (this.via !== undefined) {
34553 this.via.x = 0;
34554 this.via.y = 0;
34555 }
34556 }
34557 /** @inheritdoc */
34558
34559 }, {
34560 key: "_line",
34561 value: function _line(ctx, values, viaNode) {
34562 this._bezierCurve(ctx, values, viaNode);
34563 }
34564 /** @inheritdoc */
34565
34566 }, {
34567 key: "_getViaCoordinates",
34568 value: function _getViaCoordinates() {
34569 return this.via;
34570 }
34571 /** @inheritdoc */
34572
34573 }, {
34574 key: "getViaNode",
34575 value: function getViaNode() {
34576 return this.via;
34577 }
34578 /** @inheritdoc */
34579
34580 }, {
34581 key: "getPoint",
34582 value: function getPoint(position) {
34583 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.via;
34584
34585 if (this.from === this.to) {
34586 var _this$_getCircleData = this._getCircleData(),
34587 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
34588 cx = _this$_getCircleData2[0],
34589 cy = _this$_getCircleData2[1],
34590 cr = _this$_getCircleData2[2];
34591
34592 var a = 2 * Math.PI * (1 - position);
34593 return {
34594 x: cx + cr * Math.sin(a),
34595 y: cy + cr - cr * (1 - Math.cos(a))
34596 };
34597 } else {
34598 return {
34599 x: Math.pow(1 - position, 2) * this.fromPoint.x + 2 * position * (1 - position) * viaNode.x + Math.pow(position, 2) * this.toPoint.x,
34600 y: Math.pow(1 - position, 2) * this.fromPoint.y + 2 * position * (1 - position) * viaNode.y + Math.pow(position, 2) * this.toPoint.y
34601 };
34602 }
34603 }
34604 /** @inheritdoc */
34605
34606 }, {
34607 key: "_findBorderPosition",
34608 value: function _findBorderPosition(nearNode, ctx) {
34609 return this._findBorderPositionBezier(nearNode, ctx, this.via);
34610 }
34611 /** @inheritdoc */
34612
34613 }, {
34614 key: "_getDistanceToEdge",
34615 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
34616 // x3,y3 is the point
34617 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, this.via);
34618 }
34619 }]);
34620
34621 return BezierEdgeDynamic;
34622 }(BezierEdgeBase);
34623
34624 /**
34625 * A Static Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
34626 */
34627
34628 var BezierEdgeStatic =
34629 /*#__PURE__*/
34630 function (_BezierEdgeBase) {
34631 _inherits(BezierEdgeStatic, _BezierEdgeBase);
34632
34633 /**
34634 * Create a new instance.
34635 *
34636 * @param options - The options object of given edge.
34637 * @param body - The body of the network.
34638 * @param labelModule - Label module.
34639 */
34640 function BezierEdgeStatic(options, body, labelModule) {
34641 _classCallCheck(this, BezierEdgeStatic);
34642
34643 return _possibleConstructorReturn(this, _getPrototypeOf(BezierEdgeStatic).call(this, options, body, labelModule));
34644 }
34645 /** @inheritdoc */
34646
34647
34648 _createClass(BezierEdgeStatic, [{
34649 key: "_line",
34650 value: function _line(ctx, values, viaNode) {
34651 this._bezierCurve(ctx, values, viaNode);
34652 }
34653 /** @inheritdoc */
34654
34655 }, {
34656 key: "getViaNode",
34657 value: function getViaNode() {
34658 return this._getViaCoordinates();
34659 }
34660 /**
34661 * Compute the coordinates of the via node.
34662 *
34663 * @remarks
34664 * We do not use the to and fromPoints here to make the via nodes the same as edges without arrows.
34665 *
34666 * @returns Cartesian coordinates of the via node.
34667 */
34668
34669 }, {
34670 key: "_getViaCoordinates",
34671 value: function _getViaCoordinates() {
34672 // Assumption: x/y coordinates in from/to always defined
34673 var factor = this.options.smooth.roundness;
34674 var type = this.options.smooth.type;
34675 var dx = Math.abs(this.from.x - this.to.x);
34676 var dy = Math.abs(this.from.y - this.to.y);
34677
34678 if (type === "discrete" || type === "diagonalCross") {
34679 var stepX;
34680 var stepY;
34681
34682 if (dx <= dy) {
34683 stepX = stepY = factor * dy;
34684 } else {
34685 stepX = stepY = factor * dx;
34686 }
34687
34688 if (this.from.x > this.to.x) {
34689 stepX = -stepX;
34690 }
34691
34692 if (this.from.y >= this.to.y) {
34693 stepY = -stepY;
34694 }
34695
34696 var xVia = this.from.x + stepX;
34697 var yVia = this.from.y + stepY;
34698
34699 if (type === "discrete") {
34700 if (dx <= dy) {
34701 xVia = dx < factor * dy ? this.from.x : xVia;
34702 } else {
34703 yVia = dy < factor * dx ? this.from.y : yVia;
34704 }
34705 }
34706
34707 return {
34708 x: xVia,
34709 y: yVia
34710 };
34711 } else if (type === "straightCross") {
34712 var _stepX = (1 - factor) * dx;
34713
34714 var _stepY = (1 - factor) * dy;
34715
34716 if (dx <= dy) {
34717 // up - down
34718 _stepX = 0;
34719
34720 if (this.from.y < this.to.y) {
34721 _stepY = -_stepY;
34722 }
34723 } else {
34724 // left - right
34725 if (this.from.x < this.to.x) {
34726 _stepX = -_stepX;
34727 }
34728
34729 _stepY = 0;
34730 }
34731
34732 return {
34733 x: this.to.x + _stepX,
34734 y: this.to.y + _stepY
34735 };
34736 } else if (type === "horizontal") {
34737 var _stepX2 = (1 - factor) * dx;
34738
34739 if (this.from.x < this.to.x) {
34740 _stepX2 = -_stepX2;
34741 }
34742
34743 return {
34744 x: this.to.x + _stepX2,
34745 y: this.from.y
34746 };
34747 } else if (type === "vertical") {
34748 var _stepY2 = (1 - factor) * dy;
34749
34750 if (this.from.y < this.to.y) {
34751 _stepY2 = -_stepY2;
34752 }
34753
34754 return {
34755 x: this.from.x,
34756 y: this.to.y + _stepY2
34757 };
34758 } else if (type === "curvedCW") {
34759 dx = this.to.x - this.from.x;
34760 dy = this.from.y - this.to.y;
34761 var radius = Math.sqrt(dx * dx + dy * dy);
34762 var pi = Math.PI;
34763 var originalAngle = Math.atan2(dy, dx);
34764 var myAngle = (originalAngle + (factor * 0.5 + 0.5) * pi) % (2 * pi);
34765 return {
34766 x: this.from.x + (factor * 0.5 + 0.5) * radius * Math.sin(myAngle),
34767 y: this.from.y + (factor * 0.5 + 0.5) * radius * Math.cos(myAngle)
34768 };
34769 } else if (type === "curvedCCW") {
34770 dx = this.to.x - this.from.x;
34771 dy = this.from.y - this.to.y;
34772
34773 var _radius = Math.sqrt(dx * dx + dy * dy);
34774
34775 var _pi = Math.PI;
34776
34777 var _originalAngle = Math.atan2(dy, dx);
34778
34779 var _myAngle = (_originalAngle + (-factor * 0.5 + 0.5) * _pi) % (2 * _pi);
34780
34781 return {
34782 x: this.from.x + (factor * 0.5 + 0.5) * _radius * Math.sin(_myAngle),
34783 y: this.from.y + (factor * 0.5 + 0.5) * _radius * Math.cos(_myAngle)
34784 };
34785 } else {
34786 // continuous
34787 var _stepX3;
34788
34789 var _stepY3;
34790
34791 if (dx <= dy) {
34792 _stepX3 = _stepY3 = factor * dy;
34793 } else {
34794 _stepX3 = _stepY3 = factor * dx;
34795 }
34796
34797 if (this.from.x > this.to.x) {
34798 _stepX3 = -_stepX3;
34799 }
34800
34801 if (this.from.y >= this.to.y) {
34802 _stepY3 = -_stepY3;
34803 }
34804
34805 var _xVia = this.from.x + _stepX3;
34806
34807 var _yVia = this.from.y + _stepY3;
34808
34809 if (dx <= dy) {
34810 if (this.from.x <= this.to.x) {
34811 _xVia = this.to.x < _xVia ? this.to.x : _xVia;
34812 } else {
34813 _xVia = this.to.x > _xVia ? this.to.x : _xVia;
34814 }
34815 } else {
34816 if (this.from.y >= this.to.y) {
34817 _yVia = this.to.y > _yVia ? this.to.y : _yVia;
34818 } else {
34819 _yVia = this.to.y < _yVia ? this.to.y : _yVia;
34820 }
34821 }
34822
34823 return {
34824 x: _xVia,
34825 y: _yVia
34826 };
34827 }
34828 }
34829 /** @inheritdoc */
34830
34831 }, {
34832 key: "_findBorderPosition",
34833 value: function _findBorderPosition(nearNode, ctx) {
34834 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
34835 return this._findBorderPositionBezier(nearNode, ctx, options.via);
34836 }
34837 /** @inheritdoc */
34838
34839 }, {
34840 key: "_getDistanceToEdge",
34841 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
34842 var viaNode = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates();
34843 // x3,y3 is the point
34844 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, viaNode);
34845 }
34846 /** @inheritdoc */
34847
34848 }, {
34849 key: "getPoint",
34850 value: function getPoint(position) {
34851 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates();
34852 var t = position;
34853 var x = Math.pow(1 - t, 2) * this.fromPoint.x + 2 * t * (1 - t) * viaNode.x + Math.pow(t, 2) * this.toPoint.x;
34854 var y = Math.pow(1 - t, 2) * this.fromPoint.y + 2 * t * (1 - t) * viaNode.y + Math.pow(t, 2) * this.toPoint.y;
34855 return {
34856 x: x,
34857 y: y
34858 };
34859 }
34860 }]);
34861
34862 return BezierEdgeStatic;
34863 }(BezierEdgeBase);
34864
34865 /**
34866 * A Base Class for all Cubic Bezier Edges. Bezier curves are used to model
34867 * smooth gradual curves in paths between nodes.
34868 *
34869 * @extends BezierEdgeBase
34870 */
34871
34872 var CubicBezierEdgeBase =
34873 /*#__PURE__*/
34874 function (_BezierEdgeBase) {
34875 _inherits(CubicBezierEdgeBase, _BezierEdgeBase);
34876
34877 /**
34878 * Create a new instance.
34879 *
34880 * @param options - The options object of given edge.
34881 * @param body - The body of the network.
34882 * @param labelModule - Label module.
34883 */
34884 function CubicBezierEdgeBase(options, body, labelModule) {
34885 _classCallCheck(this, CubicBezierEdgeBase);
34886
34887 return _possibleConstructorReturn(this, _getPrototypeOf(CubicBezierEdgeBase).call(this, options, body, labelModule));
34888 }
34889 /**
34890 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
34891 *
34892 * @remarks
34893 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
34894 * https://en.wikipedia.org/wiki/B%C3%A9zier_curve
34895 *
34896 * @param x1 - First end of the line segment on the x axis.
34897 * @param y1 - First end of the line segment on the y axis.
34898 * @param x2 - Second end of the line segment on the x axis.
34899 * @param y2 - Second end of the line segment on the y axis.
34900 * @param x3 - Position of the point on the x axis.
34901 * @param y3 - Position of the point on the y axis.
34902 * @param via1 - The first point this edge passes through.
34903 * @param via2 - The second point this edge passes through.
34904 *
34905 * @returns The distance between the line segment and the point.
34906 */
34907
34908
34909 _createClass(CubicBezierEdgeBase, [{
34910 key: "_getDistanceToBezierEdge2",
34911 value: function _getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2) {
34912 // x3,y3 is the point
34913 var minDistance = 1e9;
34914 var lastX = x1;
34915 var lastY = y1;
34916 var vec = [0, 0, 0, 0];
34917
34918 for (var i = 1; i < 10; i++) {
34919 var t = 0.1 * i;
34920 vec[0] = Math.pow(1 - t, 3);
34921 vec[1] = 3 * t * Math.pow(1 - t, 2);
34922 vec[2] = 3 * Math.pow(t, 2) * (1 - t);
34923 vec[3] = Math.pow(t, 3);
34924 var x = vec[0] * x1 + vec[1] * via1.x + vec[2] * via2.x + vec[3] * x2;
34925 var y = vec[0] * y1 + vec[1] * via1.y + vec[2] * via2.y + vec[3] * y2;
34926
34927 if (i > 0) {
34928 var distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
34929
34930 minDistance = distance < minDistance ? distance : minDistance;
34931 }
34932
34933 lastX = x;
34934 lastY = y;
34935 }
34936
34937 return minDistance;
34938 }
34939 }]);
34940
34941 return CubicBezierEdgeBase;
34942 }(BezierEdgeBase);
34943
34944 /**
34945 * A Cubic Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
34946 */
34947
34948 var CubicBezierEdge =
34949 /*#__PURE__*/
34950 function (_CubicBezierEdgeBase) {
34951 _inherits(CubicBezierEdge, _CubicBezierEdgeBase);
34952
34953 /**
34954 * Create a new instance.
34955 *
34956 * @param options - The options object of given edge.
34957 * @param body - The body of the network.
34958 * @param labelModule - Label module.
34959 */
34960 function CubicBezierEdge(options, body, labelModule) {
34961 _classCallCheck(this, CubicBezierEdge);
34962
34963 return _possibleConstructorReturn(this, _getPrototypeOf(CubicBezierEdge).call(this, options, body, labelModule));
34964 }
34965 /** @inheritdoc */
34966
34967
34968 _createClass(CubicBezierEdge, [{
34969 key: "_line",
34970 value: function _line(ctx, values, viaNodes) {
34971 // get the coordinates of the support points.
34972 var via1 = viaNodes[0];
34973 var via2 = viaNodes[1];
34974
34975 this._bezierCurve(ctx, values, via1, via2);
34976 }
34977 /**
34978 * Compute the additional points the edge passes through.
34979 *
34980 * @returns Cartesian coordinates of the points the edge passes through.
34981 */
34982
34983 }, {
34984 key: "_getViaCoordinates",
34985 value: function _getViaCoordinates() {
34986 var dx = this.from.x - this.to.x;
34987 var dy = this.from.y - this.to.y;
34988 var x1;
34989 var y1;
34990 var x2;
34991 var y2;
34992 var roundness = this.options.smooth.roundness; // horizontal if x > y or if direction is forced or if direction is horizontal
34993
34994 if ((Math.abs(dx) > Math.abs(dy) || this.options.smooth.forceDirection === true || this.options.smooth.forceDirection === "horizontal") && this.options.smooth.forceDirection !== "vertical") {
34995 y1 = this.from.y;
34996 y2 = this.to.y;
34997 x1 = this.from.x - roundness * dx;
34998 x2 = this.to.x + roundness * dx;
34999 } else {
35000 y1 = this.from.y - roundness * dy;
35001 y2 = this.to.y + roundness * dy;
35002 x1 = this.from.x;
35003 x2 = this.to.x;
35004 }
35005
35006 return [{
35007 x: x1,
35008 y: y1
35009 }, {
35010 x: x2,
35011 y: y2
35012 }];
35013 }
35014 /** @inheritdoc */
35015
35016 }, {
35017 key: "getViaNode",
35018 value: function getViaNode() {
35019 return this._getViaCoordinates();
35020 }
35021 /** @inheritdoc */
35022
35023 }, {
35024 key: "_findBorderPosition",
35025 value: function _findBorderPosition(nearNode, ctx) {
35026 return this._findBorderPositionBezier(nearNode, ctx);
35027 }
35028 /** @inheritdoc */
35029
35030 }, {
35031 key: "_getDistanceToEdge",
35032 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
35033 var _ref = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates(),
35034 _ref2 = _slicedToArray(_ref, 2),
35035 via1 = _ref2[0],
35036 via2 = _ref2[1];
35037
35038 // x3,y3 is the point
35039 return this._getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2);
35040 }
35041 /** @inheritdoc */
35042
35043 }, {
35044 key: "getPoint",
35045 value: function getPoint(position) {
35046 var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates(),
35047 _ref4 = _slicedToArray(_ref3, 2),
35048 via1 = _ref4[0],
35049 via2 = _ref4[1];
35050
35051 var t = position;
35052 var vec = [Math.pow(1 - t, 3), 3 * t * Math.pow(1 - t, 2), 3 * Math.pow(t, 2) * (1 - t), Math.pow(t, 3)];
35053 var x = vec[0] * this.fromPoint.x + vec[1] * via1.x + vec[2] * via2.x + vec[3] * this.toPoint.x;
35054 var y = vec[0] * this.fromPoint.y + vec[1] * via1.y + vec[2] * via2.y + vec[3] * this.toPoint.y;
35055 return {
35056 x: x,
35057 y: y
35058 };
35059 }
35060 }]);
35061
35062 return CubicBezierEdge;
35063 }(CubicBezierEdgeBase);
35064
35065 /**
35066 * A Straight Edge.
35067 */
35068
35069 var StraightEdge =
35070 /*#__PURE__*/
35071 function (_EdgeBase) {
35072 _inherits(StraightEdge, _EdgeBase);
35073
35074 /**
35075 * Create a new instance.
35076 *
35077 * @param options - The options object of given edge.
35078 * @param body - The body of the network.
35079 * @param labelModule - Label module.
35080 */
35081 function StraightEdge(options, body, labelModule) {
35082 _classCallCheck(this, StraightEdge);
35083
35084 return _possibleConstructorReturn(this, _getPrototypeOf(StraightEdge).call(this, options, body, labelModule));
35085 }
35086 /** @inheritdoc */
35087
35088
35089 _createClass(StraightEdge, [{
35090 key: "_line",
35091 value: function _line(ctx, values) {
35092 // draw a straight line
35093 ctx.beginPath();
35094 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
35095 ctx.lineTo(this.toPoint.x, this.toPoint.y); // draw shadow if enabled
35096
35097 this.enableShadow(ctx, values);
35098 ctx.stroke();
35099 this.disableShadow(ctx, values);
35100 }
35101 /** @inheritdoc */
35102
35103 }, {
35104 key: "getViaNode",
35105 value: function getViaNode() {
35106 return undefined;
35107 }
35108 /** @inheritdoc */
35109
35110 }, {
35111 key: "getPoint",
35112 value: function getPoint(position) {
35113 return {
35114 x: (1 - position) * this.fromPoint.x + position * this.toPoint.x,
35115 y: (1 - position) * this.fromPoint.y + position * this.toPoint.y
35116 };
35117 }
35118 /** @inheritdoc */
35119
35120 }, {
35121 key: "_findBorderPosition",
35122 value: function _findBorderPosition(nearNode, ctx) {
35123 var node1 = this.to;
35124 var node2 = this.from;
35125
35126 if (nearNode.id === this.from.id) {
35127 node1 = this.from;
35128 node2 = this.to;
35129 }
35130
35131 var angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
35132 var dx = node1.x - node2.x;
35133 var dy = node1.y - node2.y;
35134 var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
35135 var toBorderDist = nearNode.distanceToBorder(ctx, angle);
35136 var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
35137 return {
35138 x: (1 - toBorderPoint) * node2.x + toBorderPoint * node1.x,
35139 y: (1 - toBorderPoint) * node2.y + toBorderPoint * node1.y,
35140 t: 0
35141 };
35142 }
35143 /** @inheritdoc */
35144
35145 }, {
35146 key: "_getDistanceToEdge",
35147 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
35148 // x3,y3 is the point
35149 return this._getDistanceToLine(x1, y1, x2, y2, x3, y3);
35150 }
35151 }]);
35152
35153 return StraightEdge;
35154 }(EdgeBase);
35155
35156 /**
35157 * An edge connects two nodes and has a specific direction.
35158 */
35159
35160 var Edge =
35161 /*#__PURE__*/
35162 function () {
35163 /**
35164 * @param {Object} options values specific to this edge, must contain at least 'from' and 'to'
35165 * @param {Object} body shared state from Network instance
35166 * @param {Network.Images} imagelist A list with images. Only needed when the edge has image arrows.
35167 * @param {Object} globalOptions options from the EdgesHandler instance
35168 * @param {Object} defaultOptions default options from the EdgeHandler instance. Value and reference are constant
35169 */
35170 function Edge(options, body, imagelist, globalOptions, defaultOptions) {
35171 _classCallCheck(this, Edge);
35172
35173 if (body === undefined) {
35174 throw new Error("No body provided");
35175 } // Since globalOptions is constant in values as well as reference,
35176 // Following needs to be done only once.
35177
35178
35179 this.options = bridgeObject(globalOptions);
35180 this.globalOptions = globalOptions;
35181 this.defaultOptions = defaultOptions;
35182 this.body = body;
35183 this.imagelist = imagelist; // initialize variables
35184
35185 this.id = undefined;
35186 this.fromId = undefined;
35187 this.toId = undefined;
35188 this.selected = false;
35189 this.hover = false;
35190 this.labelDirty = true;
35191 this.baseWidth = this.options.width;
35192 this.baseFontSize = this.options.font.size;
35193 this.from = undefined; // a node
35194
35195 this.to = undefined; // a node
35196
35197 this.edgeType = undefined;
35198 this.connected = false;
35199 this.labelModule = new Label(this.body, this.options, true
35200 /* It's an edge label */
35201 );
35202 this.setOptions(options);
35203 }
35204 /**
35205 * Set or overwrite options for the edge
35206 * @param {Object} options an object with options
35207 * @returns {undefined|boolean} undefined if no options, true if layout affecting data changed, false otherwise.
35208 */
35209
35210
35211 _createClass(Edge, [{
35212 key: "setOptions",
35213 value: function setOptions(options) {
35214 if (!options) {
35215 return;
35216 } // Following options if changed affect the layout.
35217
35218
35219 var affectsLayout = typeof options.physics !== "undefined" && this.options.physics !== options.physics || typeof options.hidden !== "undefined" && (this.options.hidden || false) !== (options.hidden || false) || typeof options.from !== "undefined" && this.options.from !== options.from || typeof options.to !== "undefined" && this.options.to !== options.to;
35220 Edge.parseOptions(this.options, options, true, this.globalOptions);
35221
35222 if (options.id !== undefined) {
35223 this.id = options.id;
35224 }
35225
35226 if (options.from !== undefined) {
35227 this.fromId = options.from;
35228 }
35229
35230 if (options.to !== undefined) {
35231 this.toId = options.to;
35232 }
35233
35234 if (options.title !== undefined) {
35235 this.title = options.title;
35236 }
35237
35238 if (options.value !== undefined) {
35239 options.value = parseFloat(options.value);
35240 }
35241
35242 var pile = [options, this.options, this.defaultOptions];
35243 this.chooser = ComponentUtil.choosify('edge', pile); // update label Module
35244
35245 this.updateLabelModule(options); // Update edge type, this if changed affects the layout.
35246
35247 affectsLayout = this.updateEdgeType() || affectsLayout; // if anything has been updates, reset the selection width and the hover width
35248
35249 this._setInteractionWidths(); // A node is connected when it has a from and to node that both exist in the network.body.nodes.
35250
35251
35252 this.connect();
35253 return affectsLayout;
35254 }
35255 /**
35256 *
35257 * @param {Object} parentOptions
35258 * @param {Object} newOptions
35259 * @param {boolean} [allowDeletion=false]
35260 * @param {Object} [globalOptions={}]
35261 * @param {boolean} [copyFromGlobals=false]
35262 */
35263
35264 }, {
35265 key: "getFormattingValues",
35266
35267 /**
35268 *
35269 * @returns {ArrowOptions}
35270 */
35271 value: function getFormattingValues() {
35272 var toArrow = this.options.arrows.to === true || this.options.arrows.to.enabled === true;
35273 var fromArrow = this.options.arrows.from === true || this.options.arrows.from.enabled === true;
35274 var middleArrow = this.options.arrows.middle === true || this.options.arrows.middle.enabled === true;
35275 var inheritsColor = this.options.color.inherit;
35276 var values = {
35277 toArrow: toArrow,
35278 toArrowScale: this.options.arrows.to.scaleFactor,
35279 toArrowType: this.options.arrows.to.type,
35280 toArrowSrc: this.options.arrows.to.src,
35281 toArrowImageWidth: this.options.arrows.to.imageWidth,
35282 toArrowImageHeight: this.options.arrows.to.imageHeight,
35283 middleArrow: middleArrow,
35284 middleArrowScale: this.options.arrows.middle.scaleFactor,
35285 middleArrowType: this.options.arrows.middle.type,
35286 middleArrowSrc: this.options.arrows.middle.src,
35287 middleArrowImageWidth: this.options.arrows.middle.imageWidth,
35288 middleArrowImageHeight: this.options.arrows.middle.imageHeight,
35289 fromArrow: fromArrow,
35290 fromArrowScale: this.options.arrows.from.scaleFactor,
35291 fromArrowType: this.options.arrows.from.type,
35292 fromArrowSrc: this.options.arrows.from.src,
35293 fromArrowImageWidth: this.options.arrows.from.imageWidth,
35294 fromArrowImageHeight: this.options.arrows.from.imageHeight,
35295 arrowStrikethrough: this.options.arrowStrikethrough,
35296 color: inheritsColor ? undefined : this.options.color.color,
35297 inheritsColor: inheritsColor,
35298 opacity: this.options.color.opacity,
35299 hidden: this.options.hidden,
35300 length: this.options.length,
35301 shadow: this.options.shadow.enabled,
35302 shadowColor: this.options.shadow.color,
35303 shadowSize: this.options.shadow.size,
35304 shadowX: this.options.shadow.x,
35305 shadowY: this.options.shadow.y,
35306 dashes: this.options.dashes,
35307 width: this.options.width,
35308 background: this.options.background.enabled,
35309 backgroundColor: this.options.background.color,
35310 backgroundSize: this.options.background.size,
35311 backgroundDashes: this.options.background.dashes
35312 };
35313
35314 if (this.selected || this.hover) {
35315 if (this.chooser === true) {
35316 if (this.selected) {
35317 var selectedWidth = this.options.selectionWidth;
35318
35319 if (typeof selectedWidth === 'function') {
35320 values.width = selectedWidth(values.width);
35321 } else if (typeof selectedWidth === 'number') {
35322 values.width += selectedWidth;
35323 }
35324
35325 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
35326 values.color = this.options.color.highlight;
35327 values.shadow = this.options.shadow.enabled;
35328 } else if (this.hover) {
35329 var hoverWidth = this.options.hoverWidth;
35330
35331 if (typeof hoverWidth === 'function') {
35332 values.width = hoverWidth(values.width);
35333 } else if (typeof hoverWidth === 'number') {
35334 values.width += hoverWidth;
35335 }
35336
35337 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
35338 values.color = this.options.color.hover;
35339 values.shadow = this.options.shadow.enabled;
35340 }
35341 } else if (typeof this.chooser === 'function') {
35342 this.chooser(values, this.options.id, this.selected, this.hover);
35343
35344 if (values.color !== undefined) {
35345 values.inheritsColor = false;
35346 }
35347
35348 if (values.shadow === false) {
35349 if (values.shadowColor !== this.options.shadow.color || values.shadowSize !== this.options.shadow.size || values.shadowX !== this.options.shadow.x || values.shadowY !== this.options.shadow.y) {
35350 values.shadow = true;
35351 }
35352 }
35353 }
35354 } else {
35355 values.shadow = this.options.shadow.enabled;
35356 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
35357 }
35358
35359 return values;
35360 }
35361 /**
35362 * update the options in the label module
35363 *
35364 * @param {Object} options
35365 */
35366
35367 }, {
35368 key: "updateLabelModule",
35369 value: function updateLabelModule(options) {
35370 var pile = [options, this.options, this.globalOptions, // Currently set global edge options
35371 this.defaultOptions];
35372 this.labelModule.update(this.options, pile);
35373
35374 if (this.labelModule.baseSize !== undefined) {
35375 this.baseFontSize = this.labelModule.baseSize;
35376 }
35377 }
35378 /**
35379 * update the edge type, set the options
35380 * @returns {boolean}
35381 */
35382
35383 }, {
35384 key: "updateEdgeType",
35385 value: function updateEdgeType() {
35386 var smooth = this.options.smooth;
35387 var dataChanged = false;
35388 var changeInType = true;
35389
35390 if (this.edgeType !== undefined) {
35391 if (this.edgeType instanceof BezierEdgeDynamic && smooth.enabled === true && smooth.type === 'dynamic' || this.edgeType instanceof CubicBezierEdge && smooth.enabled === true && smooth.type === 'cubicBezier' || this.edgeType instanceof BezierEdgeStatic && smooth.enabled === true && smooth.type !== 'dynamic' && smooth.type !== 'cubicBezier' || this.edgeType instanceof StraightEdge && smooth.type.enabled === false) {
35392 changeInType = false;
35393 }
35394
35395 if (changeInType === true) {
35396 dataChanged = this.cleanup();
35397 }
35398 }
35399
35400 if (changeInType === true) {
35401 if (smooth.enabled === true) {
35402 if (smooth.type === 'dynamic') {
35403 dataChanged = true;
35404 this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
35405 } else if (smooth.type === 'cubicBezier') {
35406 this.edgeType = new CubicBezierEdge(this.options, this.body, this.labelModule);
35407 } else {
35408 this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
35409 }
35410 } else {
35411 this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
35412 }
35413 } else {
35414 // if nothing changes, we just set the options.
35415 this.edgeType.setOptions(this.options);
35416 }
35417
35418 return dataChanged;
35419 }
35420 /**
35421 * Connect an edge to its nodes
35422 */
35423
35424 }, {
35425 key: "connect",
35426 value: function connect() {
35427 this.disconnect();
35428 this.from = this.body.nodes[this.fromId] || undefined;
35429 this.to = this.body.nodes[this.toId] || undefined;
35430 this.connected = this.from !== undefined && this.to !== undefined;
35431
35432 if (this.connected === true) {
35433 this.from.attachEdge(this);
35434 this.to.attachEdge(this);
35435 } else {
35436 if (this.from) {
35437 this.from.detachEdge(this);
35438 }
35439
35440 if (this.to) {
35441 this.to.detachEdge(this);
35442 }
35443 }
35444
35445 this.edgeType.connect();
35446 }
35447 /**
35448 * Disconnect an edge from its nodes
35449 */
35450
35451 }, {
35452 key: "disconnect",
35453 value: function disconnect() {
35454 if (this.from) {
35455 this.from.detachEdge(this);
35456 this.from = undefined;
35457 }
35458
35459 if (this.to) {
35460 this.to.detachEdge(this);
35461 this.to = undefined;
35462 }
35463
35464 this.connected = false;
35465 }
35466 /**
35467 * get the title of this edge.
35468 * @return {string} title The title of the edge, or undefined when no title
35469 * has been set.
35470 */
35471
35472 }, {
35473 key: "getTitle",
35474 value: function getTitle() {
35475 return this.title;
35476 }
35477 /**
35478 * check if this node is selecte
35479 * @return {boolean} selected True if node is selected, else false
35480 */
35481
35482 }, {
35483 key: "isSelected",
35484 value: function isSelected() {
35485 return this.selected;
35486 }
35487 /**
35488 * Retrieve the value of the edge. Can be undefined
35489 * @return {number} value
35490 */
35491
35492 }, {
35493 key: "getValue",
35494 value: function getValue() {
35495 return this.options.value;
35496 }
35497 /**
35498 * Adjust the value range of the edge. The edge will adjust it's width
35499 * based on its value.
35500 * @param {number} min
35501 * @param {number} max
35502 * @param {number} total
35503 */
35504
35505 }, {
35506 key: "setValueRange",
35507 value: function setValueRange(min, max, total) {
35508 if (this.options.value !== undefined) {
35509 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
35510 var widthDiff = this.options.scaling.max - this.options.scaling.min;
35511
35512 if (this.options.scaling.label.enabled === true) {
35513 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
35514 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
35515 }
35516
35517 this.options.width = this.options.scaling.min + scale * widthDiff;
35518 } else {
35519 this.options.width = this.baseWidth;
35520 this.options.font.size = this.baseFontSize;
35521 }
35522
35523 this._setInteractionWidths();
35524
35525 this.updateLabelModule();
35526 }
35527 /**
35528 *
35529 * @private
35530 */
35531
35532 }, {
35533 key: "_setInteractionWidths",
35534 value: function _setInteractionWidths() {
35535 if (typeof this.options.hoverWidth === 'function') {
35536 this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
35537 } else {
35538 this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
35539 }
35540
35541 if (typeof this.options.selectionWidth === 'function') {
35542 this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
35543 } else {
35544 this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
35545 }
35546 }
35547 /**
35548 * Redraw a edge
35549 * Draw this edge in the given canvas
35550 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
35551 * @param {CanvasRenderingContext2D} ctx
35552 */
35553
35554 }, {
35555 key: "draw",
35556 value: function draw(ctx) {
35557 var values = this.getFormattingValues();
35558
35559 if (values.hidden) {
35560 return;
35561 } // get the via node from the edge type
35562
35563
35564 var viaNode = this.edgeType.getViaNode();
35565 var arrowData = {}; // restore edge targets to defaults
35566
35567 this.edgeType.fromPoint = this.edgeType.from;
35568 this.edgeType.toPoint = this.edgeType.to; // from and to arrows give a different end point for edges. we set them here
35569
35570 if (values.fromArrow) {
35571 arrowData.from = this.edgeType.getArrowData(ctx, "from", viaNode, this.selected, this.hover, values);
35572 if (values.arrowStrikethrough === false) this.edgeType.fromPoint = arrowData.from.core;
35573
35574 if (values.fromArrowSrc) {
35575 arrowData.from.image = this.imagelist.load(values.fromArrowSrc);
35576 }
35577
35578 if (values.fromArrowImageWidth) {
35579 arrowData.from.imageWidth = values.fromArrowImageWidth;
35580 }
35581
35582 if (values.fromArrowImageHeight) {
35583 arrowData.from.imageHeight = values.fromArrowImageHeight;
35584 }
35585 }
35586
35587 if (values.toArrow) {
35588 arrowData.to = this.edgeType.getArrowData(ctx, "to", viaNode, this.selected, this.hover, values);
35589 if (values.arrowStrikethrough === false) this.edgeType.toPoint = arrowData.to.core;
35590
35591 if (values.toArrowSrc) {
35592 arrowData.to.image = this.imagelist.load(values.toArrowSrc);
35593 }
35594
35595 if (values.toArrowImageWidth) {
35596 arrowData.to.imageWidth = values.toArrowImageWidth;
35597 }
35598
35599 if (values.toArrowImageHeight) {
35600 arrowData.to.imageHeight = values.toArrowImageHeight;
35601 }
35602 } // the middle arrow depends on the line, which can depend on the to and from arrows so we do this one lastly.
35603
35604
35605 if (values.middleArrow) {
35606 arrowData.middle = this.edgeType.getArrowData(ctx, "middle", viaNode, this.selected, this.hover, values);
35607
35608 if (values.middleArrowSrc) {
35609 arrowData.middle.image = this.imagelist.load(values.middleArrowSrc);
35610 }
35611
35612 if (values.middleArrowImageWidth) {
35613 arrowData.middle.imageWidth = values.middleArrowImageWidth;
35614 }
35615
35616 if (values.middleArrowImageHeight) {
35617 arrowData.middle.imageHeight = values.middleArrowImageHeight;
35618 }
35619 } // draw everything
35620
35621
35622 this.edgeType.drawLine(ctx, values, this.selected, this.hover, viaNode);
35623 this.drawArrows(ctx, arrowData, values);
35624 this.drawLabel(ctx, viaNode);
35625 }
35626 /**
35627 *
35628 * @param {CanvasRenderingContext2D} ctx
35629 * @param {Object} arrowData
35630 * @param {ArrowOptions} values
35631 */
35632
35633 }, {
35634 key: "drawArrows",
35635 value: function drawArrows(ctx, arrowData, values) {
35636 if (values.fromArrow) {
35637 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.from);
35638 }
35639
35640 if (values.middleArrow) {
35641 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.middle);
35642 }
35643
35644 if (values.toArrow) {
35645 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.to);
35646 }
35647 }
35648 /**
35649 *
35650 * @param {CanvasRenderingContext2D} ctx
35651 * @param {Node} viaNode
35652 */
35653
35654 }, {
35655 key: "drawLabel",
35656 value: function drawLabel(ctx, viaNode) {
35657 if (this.options.label !== undefined) {
35658 // set style
35659 var node1 = this.from;
35660 var node2 = this.to;
35661
35662 if (this.labelModule.differentState(this.selected, this.hover)) {
35663 this.labelModule.getTextSize(ctx, this.selected, this.hover);
35664 }
35665
35666 if (node1.id != node2.id) {
35667 this.labelModule.pointToSelf = false;
35668 var point = this.edgeType.getPoint(0.5, viaNode);
35669 ctx.save();
35670
35671 var rotationPoint = this._getRotation(ctx);
35672
35673 if (rotationPoint.angle != 0) {
35674 ctx.translate(rotationPoint.x, rotationPoint.y);
35675 ctx.rotate(rotationPoint.angle);
35676 } // draw the label
35677
35678
35679 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
35680 /*
35681 // Useful debug code: draw a border around the label
35682 // This should **not** be enabled in production!
35683 var size = this.labelModule.getSize();; // ;; intentional so lint catches it
35684 ctx.strokeStyle = "#ff0000";
35685 ctx.strokeRect(size.left, size.top, size.width, size.height);
35686 // End debug code
35687 */
35688
35689 ctx.restore();
35690 } else {
35691 // Ignore the orientations.
35692 this.labelModule.pointToSelf = true;
35693 var x, y;
35694 var radius = this.options.selfReferenceSize;
35695
35696 if (node1.shape.width > node1.shape.height) {
35697 x = node1.x + node1.shape.width * 0.5;
35698 y = node1.y - radius;
35699 } else {
35700 x = node1.x + radius;
35701 y = node1.y - node1.shape.height * 0.5;
35702 }
35703
35704 point = this._pointOnCircle(x, y, radius, 0.125);
35705 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
35706 }
35707 }
35708 }
35709 /**
35710 * Determine all visual elements of this edge instance, in which the given
35711 * point falls within the bounding shape.
35712 *
35713 * @param {point} point
35714 * @returns {Array.<edgeClickItem|edgeLabelClickItem>} list with the items which are on the point
35715 */
35716
35717 }, {
35718 key: "getItemsOnPoint",
35719 value: function getItemsOnPoint(point) {
35720 var ret = [];
35721
35722 if (this.labelModule.visible()) {
35723 var rotationPoint = this._getRotation();
35724
35725 if (ComponentUtil.pointInRect(this.labelModule.getSize(), point, rotationPoint)) {
35726 ret.push({
35727 edgeId: this.id,
35728 labelId: 0
35729 });
35730 }
35731 }
35732
35733 var obj = {
35734 left: point.x,
35735 top: point.y
35736 };
35737
35738 if (this.isOverlappingWith(obj)) {
35739 ret.push({
35740 edgeId: this.id
35741 });
35742 }
35743
35744 return ret;
35745 }
35746 /**
35747 * Check if this object is overlapping with the provided object
35748 * @param {Object} obj an object with parameters left, top
35749 * @return {boolean} True if location is located on the edge
35750 */
35751
35752 }, {
35753 key: "isOverlappingWith",
35754 value: function isOverlappingWith(obj) {
35755 if (this.connected) {
35756 var distMax = 10;
35757 var xFrom = this.from.x;
35758 var yFrom = this.from.y;
35759 var xTo = this.to.x;
35760 var yTo = this.to.y;
35761 var xObj = obj.left;
35762 var yObj = obj.top;
35763 var dist = this.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);
35764 return dist < distMax;
35765 } else {
35766 return false;
35767 }
35768 }
35769 /**
35770 * Determine the rotation point, if any.
35771 *
35772 * @param {CanvasRenderingContext2D} [ctx] if passed, do a recalculation of the label size
35773 * @returns {rotationPoint} the point to rotate around and the angle in radians to rotate
35774 * @private
35775 */
35776
35777 }, {
35778 key: "_getRotation",
35779 value: function _getRotation(ctx) {
35780 var viaNode = this.edgeType.getViaNode();
35781 var point = this.edgeType.getPoint(0.5, viaNode);
35782
35783 if (ctx !== undefined) {
35784 this.labelModule.calculateLabelSize(ctx, this.selected, this.hover, point.x, point.y);
35785 }
35786
35787 var ret = {
35788 x: point.x,
35789 y: this.labelModule.size.yLine,
35790 angle: 0
35791 };
35792
35793 if (!this.labelModule.visible()) {
35794 return ret; // Don't even bother doing the atan2, there's nothing to draw
35795 }
35796
35797 if (this.options.font.align === "horizontal") {
35798 return ret; // No need to calculate angle
35799 }
35800
35801 var dy = this.from.y - this.to.y;
35802 var dx = this.from.x - this.to.x;
35803 var angle = Math.atan2(dy, dx); // radians
35804 // rotate so that label is readable
35805
35806 if (angle < -1 && dx < 0 || angle > 0 && dx < 0) {
35807 angle += Math.PI;
35808 }
35809
35810 ret.angle = angle;
35811 return ret;
35812 }
35813 /**
35814 * Get a point on a circle
35815 * @param {number} x
35816 * @param {number} y
35817 * @param {number} radius
35818 * @param {number} percentage Value between 0 (line start) and 1 (line end)
35819 * @return {Object} point
35820 * @private
35821 */
35822
35823 }, {
35824 key: "_pointOnCircle",
35825 value: function _pointOnCircle(x, y, radius, percentage) {
35826 var angle = percentage * 2 * Math.PI;
35827 return {
35828 x: x + radius * Math.cos(angle),
35829 y: y - radius * Math.sin(angle)
35830 };
35831 }
35832 /**
35833 * Sets selected state to true
35834 */
35835
35836 }, {
35837 key: "select",
35838 value: function select() {
35839 this.selected = true;
35840 }
35841 /**
35842 * Sets selected state to false
35843 */
35844
35845 }, {
35846 key: "unselect",
35847 value: function unselect() {
35848 this.selected = false;
35849 }
35850 /**
35851 * cleans all required things on delete
35852 * @returns {*}
35853 */
35854
35855 }, {
35856 key: "cleanup",
35857 value: function cleanup() {
35858 return this.edgeType.cleanup();
35859 }
35860 /**
35861 * Remove edge from the list and perform necessary cleanup.
35862 */
35863
35864 }, {
35865 key: "remove",
35866 value: function remove() {
35867 this.cleanup();
35868 this.disconnect();
35869 delete this.body.edges[this.id];
35870 }
35871 /**
35872 * Check if both connecting nodes exist
35873 * @returns {boolean}
35874 */
35875
35876 }, {
35877 key: "endPointsValid",
35878 value: function endPointsValid() {
35879 return this.body.nodes[this.fromId] !== undefined && this.body.nodes[this.toId] !== undefined;
35880 }
35881 }], [{
35882 key: "parseOptions",
35883 value: function parseOptions(parentOptions, newOptions) {
35884 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
35885 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
35886 var copyFromGlobals = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
35887 var fields = ['arrowStrikethrough', 'id', 'from', 'hidden', 'hoverWidth', 'labelHighlightBold', 'length', 'line', 'opacity', 'physics', 'scaling', 'selectionWidth', 'selfReferenceSize', 'to', 'title', 'value', 'width', 'font', 'chosen', 'widthConstraint']; // only deep extend the items in the field array. These do not have shorthand.
35888
35889 selectiveDeepExtend(fields, parentOptions, newOptions, allowDeletion); // Only copy label if it's a legal value.
35890
35891 if (ComponentUtil.isValidLabel(newOptions.label)) {
35892 parentOptions.label = newOptions.label;
35893 } else if (!ComponentUtil.isValidLabel(parentOptions.label)) {
35894 parentOptions.label = undefined;
35895 }
35896
35897 mergeOptions(parentOptions, newOptions, 'smooth', globalOptions);
35898 mergeOptions(parentOptions, newOptions, 'shadow', globalOptions);
35899 mergeOptions(parentOptions, newOptions, 'background', globalOptions);
35900
35901 if (newOptions.dashes !== undefined && newOptions.dashes !== null) {
35902 parentOptions.dashes = newOptions.dashes;
35903 } else if (allowDeletion === true && newOptions.dashes === null) {
35904 parentOptions.dashes = Object.create(globalOptions.dashes); // this sets the pointer of the option back to the global option.
35905 } // set the scaling newOptions
35906
35907
35908 if (newOptions.scaling !== undefined && newOptions.scaling !== null) {
35909 if (newOptions.scaling.min !== undefined) {
35910 parentOptions.scaling.min = newOptions.scaling.min;
35911 }
35912
35913 if (newOptions.scaling.max !== undefined) {
35914 parentOptions.scaling.max = newOptions.scaling.max;
35915 }
35916
35917 mergeOptions(parentOptions.scaling, newOptions.scaling, 'label', globalOptions.scaling);
35918 } else if (allowDeletion === true && newOptions.scaling === null) {
35919 parentOptions.scaling = Object.create(globalOptions.scaling); // this sets the pointer of the option back to the global option.
35920 } // handle multiple input cases for arrows
35921
35922
35923 if (newOptions.arrows !== undefined && newOptions.arrows !== null) {
35924 if (typeof newOptions.arrows === 'string') {
35925 var arrows = newOptions.arrows.toLowerCase();
35926 parentOptions.arrows.to.enabled = arrows.indexOf("to") != -1;
35927 parentOptions.arrows.middle.enabled = arrows.indexOf("middle") != -1;
35928 parentOptions.arrows.from.enabled = arrows.indexOf("from") != -1;
35929 } else if (_typeof$1(newOptions.arrows) === 'object') {
35930 mergeOptions(parentOptions.arrows, newOptions.arrows, 'to', globalOptions.arrows);
35931 mergeOptions(parentOptions.arrows, newOptions.arrows, 'middle', globalOptions.arrows);
35932 mergeOptions(parentOptions.arrows, newOptions.arrows, 'from', globalOptions.arrows);
35933 } else {
35934 throw new Error("The arrow newOptions can only be an object or a string. Refer to the documentation. You used:" + JSON.stringify(newOptions.arrows));
35935 }
35936 } else if (allowDeletion === true && newOptions.arrows === null) {
35937 parentOptions.arrows = Object.create(globalOptions.arrows); // this sets the pointer of the option back to the global option.
35938 } // handle multiple input cases for color
35939
35940
35941 if (newOptions.color !== undefined && newOptions.color !== null) {
35942 var fromColor = isString(newOptions.color) ? {
35943 color: newOptions.color,
35944 highlight: newOptions.color,
35945 hover: newOptions.color,
35946 inherit: false,
35947 opacity: 1
35948 } : newOptions.color;
35949 var toColor = parentOptions.color; // If passed, fill in values from default options - required in the case of no prototype bridging
35950
35951 if (copyFromGlobals) {
35952 deepExtend(toColor, globalOptions.color, false, allowDeletion);
35953 } else {
35954 // Clear local properties - need to do it like this in order to retain prototype bridges
35955 for (var i in toColor) {
35956 if (toColor.hasOwnProperty(i)) {
35957 delete toColor[i];
35958 }
35959 }
35960 }
35961
35962 if (isString(toColor)) {
35963 toColor.color = toColor;
35964 toColor.highlight = toColor;
35965 toColor.hover = toColor;
35966 toColor.inherit = false;
35967
35968 if (fromColor.opacity === undefined) {
35969 toColor.opacity = 1.0; // set default
35970 }
35971 } else {
35972 var colorsDefined = false;
35973
35974 if (fromColor.color !== undefined) {
35975 toColor.color = fromColor.color;
35976 colorsDefined = true;
35977 }
35978
35979 if (fromColor.highlight !== undefined) {
35980 toColor.highlight = fromColor.highlight;
35981 colorsDefined = true;
35982 }
35983
35984 if (fromColor.hover !== undefined) {
35985 toColor.hover = fromColor.hover;
35986 colorsDefined = true;
35987 }
35988
35989 if (fromColor.inherit !== undefined) {
35990 toColor.inherit = fromColor.inherit;
35991 }
35992
35993 if (fromColor.opacity !== undefined) {
35994 toColor.opacity = Math.min(1, Math.max(0, fromColor.opacity));
35995 }
35996
35997 if (colorsDefined === true) {
35998 toColor.inherit = false;
35999 } else {
36000 if (toColor.inherit === undefined) {
36001 toColor.inherit = 'from'; // Set default
36002 }
36003 }
36004 }
36005 } else if (allowDeletion === true && newOptions.color === null) {
36006 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
36007 }
36008
36009 if (allowDeletion === true && newOptions.font === null) {
36010 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
36011 }
36012 }
36013 }]);
36014
36015 return Edge;
36016 }();
36017
36018 /**
36019 * Handler for Edges
36020 */
36021
36022 var EdgesHandler =
36023 /*#__PURE__*/
36024 function () {
36025 /**
36026 * @param {Object} body
36027 * @param {Array.<Image>} images
36028 * @param {Array.<Group>} groups
36029 */
36030 function EdgesHandler(body, images, groups) {
36031 var _this = this;
36032
36033 _classCallCheck(this, EdgesHandler);
36034
36035 this.body = body;
36036 this.images = images;
36037 this.groups = groups; // create the edge API in the body container
36038
36039 this.body.functions.createEdge = this.create.bind(this);
36040 this.edgesListeners = {
36041 add: function add(event, params) {
36042 _this.add(params.items);
36043 },
36044 update: function update(event, params) {
36045 _this.update(params.items);
36046 },
36047 remove: function remove(event, params) {
36048 _this.remove(params.items);
36049 }
36050 };
36051 this.options = {};
36052 this.defaultOptions = {
36053 arrows: {
36054 to: {
36055 enabled: false,
36056 scaleFactor: 1,
36057 type: 'arrow'
36058 },
36059 // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
36060 middle: {
36061 enabled: false,
36062 scaleFactor: 1,
36063 type: 'arrow'
36064 },
36065 from: {
36066 enabled: false,
36067 scaleFactor: 1,
36068 type: 'arrow'
36069 }
36070 },
36071 arrowStrikethrough: true,
36072 color: {
36073 color: '#848484',
36074 highlight: '#848484',
36075 hover: '#848484',
36076 inherit: 'from',
36077 opacity: 1.0
36078 },
36079 dashes: false,
36080 font: {
36081 color: '#343434',
36082 size: 14,
36083 // px
36084 face: 'arial',
36085 background: 'none',
36086 strokeWidth: 2,
36087 // px
36088 strokeColor: '#ffffff',
36089 align: 'horizontal',
36090 multi: false,
36091 vadjust: 0,
36092 bold: {
36093 mod: 'bold'
36094 },
36095 boldital: {
36096 mod: 'bold italic'
36097 },
36098 ital: {
36099 mod: 'italic'
36100 },
36101 mono: {
36102 mod: '',
36103 size: 15,
36104 // px
36105 face: 'courier new',
36106 vadjust: 2
36107 }
36108 },
36109 hidden: false,
36110 hoverWidth: 1.5,
36111 label: undefined,
36112 labelHighlightBold: true,
36113 length: undefined,
36114 physics: true,
36115 scaling: {
36116 min: 1,
36117 max: 15,
36118 label: {
36119 enabled: true,
36120 min: 14,
36121 max: 30,
36122 maxVisible: 30,
36123 drawThreshold: 5
36124 },
36125 customScalingFunction: function customScalingFunction(min, max, total, value) {
36126 if (max === min) {
36127 return 0.5;
36128 } else {
36129 var scale = 1 / (max - min);
36130 return Math.max(0, (value - min) * scale);
36131 }
36132 }
36133 },
36134 selectionWidth: 1.5,
36135 selfReferenceSize: 20,
36136 shadow: {
36137 enabled: false,
36138 color: 'rgba(0,0,0,0.5)',
36139 size: 10,
36140 x: 5,
36141 y: 5
36142 },
36143 background: {
36144 enabled: false,
36145 color: 'rgba(111,111,111,1)',
36146 size: 10,
36147 dashes: false
36148 },
36149 smooth: {
36150 enabled: true,
36151 type: "dynamic",
36152 forceDirection: 'none',
36153 roundness: 0.5
36154 },
36155 title: undefined,
36156 width: 1,
36157 value: undefined
36158 };
36159 deepExtend(this.options, this.defaultOptions);
36160 this.bindEventListeners();
36161 }
36162 /**
36163 * Binds event listeners
36164 */
36165
36166
36167 _createClass(EdgesHandler, [{
36168 key: "bindEventListeners",
36169 value: function bindEventListeners() {
36170 var _this2 = this;
36171
36172 // this allows external modules to force all dynamic curves to turn static.
36173 this.body.emitter.on("_forceDisableDynamicCurves", function (type) {
36174 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
36175
36176 if (type === 'dynamic') {
36177 type = 'continuous';
36178 }
36179
36180 var dataChanged = false;
36181
36182 for (var edgeId in _this2.body.edges) {
36183 if (_this2.body.edges.hasOwnProperty(edgeId)) {
36184 var edge = _this2.body.edges[edgeId];
36185 var edgeData = _this2.body.data.edges._data[edgeId]; // only forcibly remove the smooth curve if the data has been set of the edge has the smooth curves defined.
36186 // this is because a change in the global would not affect these curves.
36187
36188 if (edgeData !== undefined) {
36189 var smoothOptions = edgeData.smooth;
36190
36191 if (smoothOptions !== undefined) {
36192 if (smoothOptions.enabled === true && smoothOptions.type === 'dynamic') {
36193 if (type === undefined) {
36194 edge.setOptions({
36195 smooth: false
36196 });
36197 } else {
36198 edge.setOptions({
36199 smooth: {
36200 type: type
36201 }
36202 });
36203 }
36204
36205 dataChanged = true;
36206 }
36207 }
36208 }
36209 }
36210 }
36211
36212 if (emit === true && dataChanged === true) {
36213 _this2.body.emitter.emit("_dataChanged");
36214 }
36215 }); // this is called when options of EXISTING nodes or edges have changed.
36216 //
36217 // NOTE: Not true, called when options have NOT changed, for both existing as well as new nodes.
36218 // See update() for logic.
36219 // TODO: Verify and examine the consequences of this. It might still trigger when
36220 // non-option fields have changed, but then reconnecting edges is still useless.
36221 // Alternatively, it might also be called when edges are removed.
36222 //
36223
36224 this.body.emitter.on("_dataUpdated", function () {
36225 _this2.reconnectEdges();
36226 }); // refresh the edges. Used when reverting from hierarchical layout
36227
36228 this.body.emitter.on("refreshEdges", this.refresh.bind(this));
36229 this.body.emitter.on("refresh", this.refresh.bind(this));
36230 this.body.emitter.on("destroy", function () {
36231 forEach(_this2.edgesListeners, function (callback, event) {
36232 if (_this2.body.data.edges) _this2.body.data.edges.off(event, callback);
36233 });
36234 delete _this2.body.functions.createEdge;
36235 delete _this2.edgesListeners.add;
36236 delete _this2.edgesListeners.update;
36237 delete _this2.edgesListeners.remove;
36238 delete _this2.edgesListeners;
36239 });
36240 }
36241 /**
36242 *
36243 * @param {Object} options
36244 */
36245
36246 }, {
36247 key: "setOptions",
36248 value: function setOptions(options) {
36249 if (options !== undefined) {
36250 // use the parser from the Edge class to fill in all shorthand notations
36251 Edge.parseOptions(this.options, options, true, this.defaultOptions, true); // update smooth settings in all edges
36252
36253 var dataChanged = false;
36254
36255 if (options.smooth !== undefined) {
36256 for (var edgeId in this.body.edges) {
36257 if (this.body.edges.hasOwnProperty(edgeId)) {
36258 dataChanged = this.body.edges[edgeId].updateEdgeType() || dataChanged;
36259 }
36260 }
36261 } // update fonts in all edges
36262
36263
36264 if (options.font !== undefined) {
36265 for (var _edgeId in this.body.edges) {
36266 if (this.body.edges.hasOwnProperty(_edgeId)) {
36267 this.body.edges[_edgeId].updateLabelModule();
36268 }
36269 }
36270 } // update the state of the variables if needed
36271
36272
36273 if (options.hidden !== undefined || options.physics !== undefined || dataChanged === true) {
36274 this.body.emitter.emit('_dataChanged');
36275 }
36276 }
36277 }
36278 /**
36279 * Load edges by reading the data table
36280 * @param {Array | DataSet | DataView} edges The data containing the edges.
36281 * @param {boolean} [doNotEmit=false]
36282 * @private
36283 */
36284
36285 }, {
36286 key: "setData",
36287 value: function setData(edges) {
36288 var _this3 = this;
36289
36290 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
36291 var oldEdgesData = this.body.data.edges;
36292
36293 if (edges instanceof DataSet || edges instanceof DataView$2) {
36294 this.body.data.edges = edges;
36295 } else if (Array.isArray(edges)) {
36296 this.body.data.edges = new DataSet();
36297 this.body.data.edges.add(edges);
36298 } else if (!edges) {
36299 this.body.data.edges = new DataSet();
36300 } else {
36301 throw new TypeError('Array or DataSet expected');
36302 } // TODO: is this null or undefined or false?
36303
36304
36305 if (oldEdgesData) {
36306 // unsubscribe from old dataset
36307 forEach(this.edgesListeners, function (callback, event) {
36308 oldEdgesData.off(event, callback);
36309 });
36310 } // remove drawn edges
36311
36312
36313 this.body.edges = {}; // TODO: is this null or undefined or false?
36314
36315 if (this.body.data.edges) {
36316 // subscribe to new dataset
36317 forEach(this.edgesListeners, function (callback, event) {
36318 _this3.body.data.edges.on(event, callback);
36319 }); // draw all new nodes
36320
36321 var ids = this.body.data.edges.getIds();
36322 this.add(ids, true);
36323 }
36324
36325 this.body.emitter.emit('_adjustEdgesForHierarchicalLayout');
36326
36327 if (doNotEmit === false) {
36328 this.body.emitter.emit("_dataChanged");
36329 }
36330 }
36331 /**
36332 * Add edges
36333 * @param {number[] | string[]} ids
36334 * @param {boolean} [doNotEmit=false]
36335 * @private
36336 */
36337
36338 }, {
36339 key: "add",
36340 value: function add(ids) {
36341 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
36342 var edges = this.body.edges;
36343 var edgesData = this.body.data.edges;
36344
36345 for (var i = 0; i < ids.length; i++) {
36346 var id = ids[i];
36347 var oldEdge = edges[id];
36348
36349 if (oldEdge) {
36350 oldEdge.disconnect();
36351 }
36352
36353 var data = edgesData.get(id, {
36354 "showInternalIds": true
36355 });
36356 edges[id] = this.create(data);
36357 }
36358
36359 this.body.emitter.emit('_adjustEdgesForHierarchicalLayout');
36360
36361 if (doNotEmit === false) {
36362 this.body.emitter.emit("_dataChanged");
36363 }
36364 }
36365 /**
36366 * Update existing edges, or create them when not yet existing
36367 * @param {number[] | string[]} ids
36368 * @private
36369 */
36370
36371 }, {
36372 key: "update",
36373 value: function update(ids) {
36374 var edges = this.body.edges;
36375 var edgesData = this.body.data.edges;
36376 var dataChanged = false;
36377
36378 for (var i = 0; i < ids.length; i++) {
36379 var id = ids[i];
36380 var data = edgesData.get(id);
36381 var edge = edges[id];
36382
36383 if (edge !== undefined) {
36384 // update edge
36385 edge.disconnect();
36386 dataChanged = edge.setOptions(data) || dataChanged; // if a support node is added, data can be changed.
36387
36388 edge.connect();
36389 } else {
36390 // create edge
36391 this.body.edges[id] = this.create(data);
36392 dataChanged = true;
36393 }
36394 }
36395
36396 if (dataChanged === true) {
36397 this.body.emitter.emit('_adjustEdgesForHierarchicalLayout');
36398 this.body.emitter.emit("_dataChanged");
36399 } else {
36400 this.body.emitter.emit("_dataUpdated");
36401 }
36402 }
36403 /**
36404 * Remove existing edges. Non existing ids will be ignored
36405 * @param {number[] | string[]} ids
36406 * @param {boolean} [emit=true]
36407 * @private
36408 */
36409
36410 }, {
36411 key: "remove",
36412 value: function remove(ids) {
36413 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
36414 if (ids.length === 0) return; // early out
36415
36416 var edges = this.body.edges;
36417 forEach(ids, function (id) {
36418 var edge = edges[id];
36419
36420 if (edge !== undefined) {
36421 edge.remove();
36422 }
36423 });
36424
36425 if (emit) {
36426 this.body.emitter.emit("_dataChanged");
36427 }
36428 }
36429 /**
36430 * Refreshes Edge Handler
36431 */
36432
36433 }, {
36434 key: "refresh",
36435 value: function refresh() {
36436 var _this4 = this;
36437
36438 forEach(this.body.edges, function (edge, edgeId) {
36439 var data = _this4.body.data.edges._data[edgeId];
36440
36441 if (data !== undefined) {
36442 edge.setOptions(data);
36443 }
36444 });
36445 }
36446 /**
36447 *
36448 * @param {Object} properties
36449 * @returns {Edge}
36450 */
36451
36452 }, {
36453 key: "create",
36454 value: function create(properties) {
36455 return new Edge(properties, this.body, this.images, this.options, this.defaultOptions);
36456 }
36457 /**
36458 * Reconnect all edges
36459 * @private
36460 */
36461
36462 }, {
36463 key: "reconnectEdges",
36464 value: function reconnectEdges() {
36465 var id;
36466 var nodes = this.body.nodes;
36467 var edges = this.body.edges;
36468
36469 for (id in nodes) {
36470 if (nodes.hasOwnProperty(id)) {
36471 nodes[id].edges = [];
36472 }
36473 }
36474
36475 for (id in edges) {
36476 if (edges.hasOwnProperty(id)) {
36477 var edge = edges[id];
36478 edge.from = null;
36479 edge.to = null;
36480 edge.connect();
36481 }
36482 }
36483 }
36484 /**
36485 *
36486 * @param {Edge.id} edgeId
36487 * @returns {Array}
36488 */
36489
36490 }, {
36491 key: "getConnectedNodes",
36492 value: function getConnectedNodes(edgeId) {
36493 var nodeList = [];
36494
36495 if (this.body.edges[edgeId] !== undefined) {
36496 var edge = this.body.edges[edgeId];
36497
36498 if (edge.fromId !== undefined) {
36499 nodeList.push(edge.fromId);
36500 }
36501
36502 if (edge.toId !== undefined) {
36503 nodeList.push(edge.toId);
36504 }
36505 }
36506
36507 return nodeList;
36508 }
36509 /**
36510 * There is no direct relation between the nodes and the edges DataSet,
36511 * so the right place to do call this is in the handler for event `_dataUpdated`.
36512 */
36513
36514 }, {
36515 key: "_updateState",
36516 value: function _updateState() {
36517 this._addMissingEdges();
36518
36519 this._removeInvalidEdges();
36520 }
36521 /**
36522 * Scan for missing nodes and remove corresponding edges, if any.
36523 * @private
36524 */
36525
36526 }, {
36527 key: "_removeInvalidEdges",
36528 value: function _removeInvalidEdges() {
36529 var _this5 = this;
36530
36531 var edgesToDelete = [];
36532 forEach(this.body.edges, function (edge, id) {
36533 var toNode = _this5.body.nodes[edge.toId];
36534 var fromNode = _this5.body.nodes[edge.fromId]; // Skip clustering edges here, let the Clustering module handle those
36535
36536 if (toNode !== undefined && toNode.isCluster === true || fromNode !== undefined && fromNode.isCluster === true) {
36537 return;
36538 }
36539
36540 if (toNode === undefined || fromNode === undefined) {
36541 edgesToDelete.push(id);
36542 }
36543 });
36544 this.remove(edgesToDelete, false);
36545 }
36546 /**
36547 * add all edges from dataset that are not in the cached state
36548 * @private
36549 */
36550
36551 }, {
36552 key: "_addMissingEdges",
36553 value: function _addMissingEdges() {
36554 var edgesData = this.body.data.edges;
36555
36556 if (edgesData === undefined || edgesData === null) {
36557 return; // No edges DataSet yet; can happen on startup
36558 }
36559
36560 var edges = this.body.edges;
36561 var addIds = [];
36562 edgesData.forEach(function (edgeData, edgeId) {
36563 var edge = edges[edgeId];
36564
36565 if (edge === undefined) {
36566 addIds.push(edgeId);
36567 }
36568 });
36569 this.add(addIds, true);
36570 }
36571 }]);
36572
36573 return EdgesHandler;
36574 }();
36575
36576 /**
36577 * Barnes Hut Solver
36578 */
36579 var BarnesHutSolver =
36580 /*#__PURE__*/
36581 function () {
36582 /**
36583 * @param {Object} body
36584 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
36585 * @param {Object} options
36586 */
36587 function BarnesHutSolver(body, physicsBody, options) {
36588 _classCallCheck(this, BarnesHutSolver);
36589
36590 this.body = body;
36591 this.physicsBody = physicsBody;
36592 this.barnesHutTree;
36593 this.setOptions(options);
36594 this.randomSeed = 5; // debug: show grid
36595 // this.body.emitter.on("afterDrawing", (ctx) => {this._debug(ctx,'#ff0000')})
36596 }
36597 /**
36598 *
36599 * @param {Object} options
36600 */
36601
36602
36603 _createClass(BarnesHutSolver, [{
36604 key: "setOptions",
36605 value: function setOptions(options) {
36606 this.options = options;
36607 this.thetaInversed = 1 / this.options.theta; // if 1 then min distance = 0.5, if 0.5 then min distance = 0.5 + 0.5*node.shape.radius
36608
36609 this.overlapAvoidanceFactor = 1 - Math.max(0, Math.min(1, this.options.avoidOverlap));
36610 }
36611 /**
36612 *
36613 * @returns {number} random integer
36614 */
36615
36616 }, {
36617 key: "seededRandom",
36618 value: function seededRandom() {
36619 var x = Math.sin(this.randomSeed++) * 10000;
36620 return x - Math.floor(x);
36621 }
36622 /**
36623 * This function calculates the forces the nodes apply on each other based on a gravitational model.
36624 * The Barnes Hut method is used to speed up this N-body simulation.
36625 *
36626 * @private
36627 */
36628
36629 }, {
36630 key: "solve",
36631 value: function solve() {
36632 if (this.options.gravitationalConstant !== 0 && this.physicsBody.physicsNodeIndices.length > 0) {
36633 var node;
36634 var nodes = this.body.nodes;
36635 var nodeIndices = this.physicsBody.physicsNodeIndices;
36636 var nodeCount = nodeIndices.length; // create the tree
36637
36638 var barnesHutTree = this._formBarnesHutTree(nodes, nodeIndices); // for debugging
36639
36640
36641 this.barnesHutTree = barnesHutTree; // place the nodes one by one recursively
36642
36643 for (var i = 0; i < nodeCount; i++) {
36644 node = nodes[nodeIndices[i]];
36645
36646 if (node.options.mass > 0) {
36647 // starting with root is irrelevant, it never passes the BarnesHutSolver condition
36648 this._getForceContributions(barnesHutTree.root, node);
36649 }
36650 }
36651 }
36652 }
36653 /**
36654 * @param {Object} parentBranch
36655 * @param {Node} node
36656 * @private
36657 */
36658
36659 }, {
36660 key: "_getForceContributions",
36661 value: function _getForceContributions(parentBranch, node) {
36662 this._getForceContribution(parentBranch.children.NW, node);
36663
36664 this._getForceContribution(parentBranch.children.NE, node);
36665
36666 this._getForceContribution(parentBranch.children.SW, node);
36667
36668 this._getForceContribution(parentBranch.children.SE, node);
36669 }
36670 /**
36671 * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass.
36672 * If a region contains a single node, we check if it is not itself, then we apply the force.
36673 *
36674 * @param {Object} parentBranch
36675 * @param {Node} node
36676 * @private
36677 */
36678
36679 }, {
36680 key: "_getForceContribution",
36681 value: function _getForceContribution(parentBranch, node) {
36682 // we get no force contribution from an empty region
36683 if (parentBranch.childrenCount > 0) {
36684 var dx, dy, distance; // get the distance from the center of mass to the node.
36685
36686 dx = parentBranch.centerOfMass.x - node.x;
36687 dy = parentBranch.centerOfMass.y - node.y;
36688 distance = Math.sqrt(dx * dx + dy * dy); // BarnesHutSolver condition
36689 // original condition : s/d < theta = passed === d/s > 1/theta = passed
36690 // calcSize = 1/s --> d * 1/s > 1/theta = passed
36691
36692 if (distance * parentBranch.calcSize > this.thetaInversed) {
36693 this._calculateForces(distance, dx, dy, node, parentBranch);
36694 } else {
36695 // Did not pass the condition, go into children if available
36696 if (parentBranch.childrenCount === 4) {
36697 this._getForceContributions(parentBranch, node);
36698 } else {
36699 // parentBranch must have only one node, if it was empty we wouldnt be here
36700 if (parentBranch.children.data.id != node.id) {
36701 // if it is not self
36702 this._calculateForces(distance, dx, dy, node, parentBranch);
36703 }
36704 }
36705 }
36706 }
36707 }
36708 /**
36709 * Calculate the forces based on the distance.
36710 *
36711 * @param {number} distance
36712 * @param {number} dx
36713 * @param {number} dy
36714 * @param {Node} node
36715 * @param {Object} parentBranch
36716 * @private
36717 */
36718
36719 }, {
36720 key: "_calculateForces",
36721 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
36722 if (distance === 0) {
36723 distance = 0.1;
36724 dx = distance;
36725 }
36726
36727 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
36728 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
36729 } // the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
36730 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
36731
36732
36733 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass / Math.pow(distance, 3);
36734 var fx = dx * gravityForce;
36735 var fy = dy * gravityForce;
36736 this.physicsBody.forces[node.id].x += fx;
36737 this.physicsBody.forces[node.id].y += fy;
36738 }
36739 /**
36740 * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes.
36741 *
36742 * @param {Array.<Node>} nodes
36743 * @param {Array.<number>} nodeIndices
36744 * @returns {{root: {centerOfMass: {x: number, y: number}, mass: number, range: {minX: number, maxX: number, minY: number, maxY: number}, size: number, calcSize: number, children: {data: null}, maxWidth: number, level: number, childrenCount: number}}} BarnesHutTree
36745 * @private
36746 */
36747
36748 }, {
36749 key: "_formBarnesHutTree",
36750 value: function _formBarnesHutTree(nodes, nodeIndices) {
36751 var node;
36752 var nodeCount = nodeIndices.length;
36753 var minX = nodes[nodeIndices[0]].x;
36754 var minY = nodes[nodeIndices[0]].y;
36755 var maxX = nodes[nodeIndices[0]].x;
36756 var maxY = nodes[nodeIndices[0]].y; // get the range of the nodes
36757
36758 for (var i = 1; i < nodeCount; i++) {
36759 var _node = nodes[nodeIndices[i]];
36760 var x = _node.x;
36761 var y = _node.y;
36762
36763 if (_node.options.mass > 0) {
36764 if (x < minX) {
36765 minX = x;
36766 }
36767
36768 if (x > maxX) {
36769 maxX = x;
36770 }
36771
36772 if (y < minY) {
36773 minY = y;
36774 }
36775
36776 if (y > maxY) {
36777 maxY = y;
36778 }
36779 }
36780 } // make the range a square
36781
36782
36783 var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
36784
36785 if (sizeDiff > 0) {
36786 minY -= 0.5 * sizeDiff;
36787 maxY += 0.5 * sizeDiff;
36788 } // xSize > ySize
36789 else {
36790 minX += 0.5 * sizeDiff;
36791 maxX -= 0.5 * sizeDiff;
36792 } // xSize < ySize
36793
36794
36795 var minimumTreeSize = 1e-5;
36796 var rootSize = Math.max(minimumTreeSize, Math.abs(maxX - minX));
36797 var halfRootSize = 0.5 * rootSize;
36798 var centerX = 0.5 * (minX + maxX),
36799 centerY = 0.5 * (minY + maxY); // construct the barnesHutTree
36800
36801 var barnesHutTree = {
36802 root: {
36803 centerOfMass: {
36804 x: 0,
36805 y: 0
36806 },
36807 mass: 0,
36808 range: {
36809 minX: centerX - halfRootSize,
36810 maxX: centerX + halfRootSize,
36811 minY: centerY - halfRootSize,
36812 maxY: centerY + halfRootSize
36813 },
36814 size: rootSize,
36815 calcSize: 1 / rootSize,
36816 children: {
36817 data: null
36818 },
36819 maxWidth: 0,
36820 level: 0,
36821 childrenCount: 4
36822 }
36823 };
36824
36825 this._splitBranch(barnesHutTree.root); // place the nodes one by one recursively
36826
36827
36828 for (var _i = 0; _i < nodeCount; _i++) {
36829 node = nodes[nodeIndices[_i]];
36830
36831 if (node.options.mass > 0) {
36832 this._placeInTree(barnesHutTree.root, node);
36833 }
36834 } // make global
36835
36836
36837 return barnesHutTree;
36838 }
36839 /**
36840 * this updates the mass of a branch. this is increased by adding a node.
36841 *
36842 * @param {Object} parentBranch
36843 * @param {Node} node
36844 * @private
36845 */
36846
36847 }, {
36848 key: "_updateBranchMass",
36849 value: function _updateBranchMass(parentBranch, node) {
36850 var centerOfMass = parentBranch.centerOfMass;
36851 var totalMass = parentBranch.mass + node.options.mass;
36852 var totalMassInv = 1 / totalMass;
36853 centerOfMass.x = centerOfMass.x * parentBranch.mass + node.x * node.options.mass;
36854 centerOfMass.x *= totalMassInv;
36855 centerOfMass.y = centerOfMass.y * parentBranch.mass + node.y * node.options.mass;
36856 centerOfMass.y *= totalMassInv;
36857 parentBranch.mass = totalMass;
36858 var biggestSize = Math.max(Math.max(node.height, node.radius), node.width);
36859 parentBranch.maxWidth = parentBranch.maxWidth < biggestSize ? biggestSize : parentBranch.maxWidth;
36860 }
36861 /**
36862 * determine in which branch the node will be placed.
36863 *
36864 * @param {Object} parentBranch
36865 * @param {Node} node
36866 * @param {boolean} skipMassUpdate
36867 * @private
36868 */
36869
36870 }, {
36871 key: "_placeInTree",
36872 value: function _placeInTree(parentBranch, node, skipMassUpdate) {
36873 if (skipMassUpdate != true || skipMassUpdate === undefined) {
36874 // update the mass of the branch.
36875 this._updateBranchMass(parentBranch, node);
36876 }
36877
36878 var range = parentBranch.children.NW.range;
36879 var region;
36880
36881 if (range.maxX > node.x) {
36882 // in NW or SW
36883 if (range.maxY > node.y) {
36884 region = "NW";
36885 } else {
36886 region = "SW";
36887 }
36888 } else {
36889 // in NE or SE
36890 if (range.maxY > node.y) {
36891 region = "NE";
36892 } else {
36893 region = "SE";
36894 }
36895 }
36896
36897 this._placeInRegion(parentBranch, node, region);
36898 }
36899 /**
36900 * actually place the node in a region (or branch)
36901 *
36902 * @param {Object} parentBranch
36903 * @param {Node} node
36904 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
36905 * @private
36906 */
36907
36908 }, {
36909 key: "_placeInRegion",
36910 value: function _placeInRegion(parentBranch, node, region) {
36911 var children = parentBranch.children[region];
36912
36913 switch (children.childrenCount) {
36914 case 0:
36915 // place node here
36916 children.children.data = node;
36917 children.childrenCount = 1;
36918
36919 this._updateBranchMass(children, node);
36920
36921 break;
36922
36923 case 1:
36924 // convert into children
36925 // if there are two nodes exactly overlapping (on init, on opening of cluster etc.)
36926 // we move one node a little bit and we do not put it in the tree.
36927 if (children.children.data.x === node.x && children.children.data.y === node.y) {
36928 node.x += this.seededRandom();
36929 node.y += this.seededRandom();
36930 } else {
36931 this._splitBranch(children);
36932
36933 this._placeInTree(children, node);
36934 }
36935
36936 break;
36937
36938 case 4:
36939 // place in branch
36940 this._placeInTree(children, node);
36941
36942 break;
36943 }
36944 }
36945 /**
36946 * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch
36947 * after the split is complete.
36948 *
36949 * @param {Object} parentBranch
36950 * @private
36951 */
36952
36953 }, {
36954 key: "_splitBranch",
36955 value: function _splitBranch(parentBranch) {
36956 // if the branch is shaded with a node, replace the node in the new subset.
36957 var containedNode = null;
36958
36959 if (parentBranch.childrenCount === 1) {
36960 containedNode = parentBranch.children.data;
36961 parentBranch.mass = 0;
36962 parentBranch.centerOfMass.x = 0;
36963 parentBranch.centerOfMass.y = 0;
36964 }
36965
36966 parentBranch.childrenCount = 4;
36967 parentBranch.children.data = null;
36968
36969 this._insertRegion(parentBranch, "NW");
36970
36971 this._insertRegion(parentBranch, "NE");
36972
36973 this._insertRegion(parentBranch, "SW");
36974
36975 this._insertRegion(parentBranch, "SE");
36976
36977 if (containedNode != null) {
36978 this._placeInTree(parentBranch, containedNode);
36979 }
36980 }
36981 /**
36982 * This function subdivides the region into four new segments.
36983 * Specifically, this inserts a single new segment.
36984 * It fills the children section of the parentBranch
36985 *
36986 * @param {Object} parentBranch
36987 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
36988 * @private
36989 */
36990
36991 }, {
36992 key: "_insertRegion",
36993 value: function _insertRegion(parentBranch, region) {
36994 var minX, maxX, minY, maxY;
36995 var childSize = 0.5 * parentBranch.size;
36996
36997 switch (region) {
36998 case "NW":
36999 minX = parentBranch.range.minX;
37000 maxX = parentBranch.range.minX + childSize;
37001 minY = parentBranch.range.minY;
37002 maxY = parentBranch.range.minY + childSize;
37003 break;
37004
37005 case "NE":
37006 minX = parentBranch.range.minX + childSize;
37007 maxX = parentBranch.range.maxX;
37008 minY = parentBranch.range.minY;
37009 maxY = parentBranch.range.minY + childSize;
37010 break;
37011
37012 case "SW":
37013 minX = parentBranch.range.minX;
37014 maxX = parentBranch.range.minX + childSize;
37015 minY = parentBranch.range.minY + childSize;
37016 maxY = parentBranch.range.maxY;
37017 break;
37018
37019 case "SE":
37020 minX = parentBranch.range.minX + childSize;
37021 maxX = parentBranch.range.maxX;
37022 minY = parentBranch.range.minY + childSize;
37023 maxY = parentBranch.range.maxY;
37024 break;
37025 }
37026
37027 parentBranch.children[region] = {
37028 centerOfMass: {
37029 x: 0,
37030 y: 0
37031 },
37032 mass: 0,
37033 range: {
37034 minX: minX,
37035 maxX: maxX,
37036 minY: minY,
37037 maxY: maxY
37038 },
37039 size: 0.5 * parentBranch.size,
37040 calcSize: 2 * parentBranch.calcSize,
37041 children: {
37042 data: null
37043 },
37044 maxWidth: 0,
37045 level: parentBranch.level + 1,
37046 childrenCount: 0
37047 };
37048 } //--------------------------- DEBUGGING BELOW ---------------------------//
37049
37050 /**
37051 * This function is for debugging purposed, it draws the tree.
37052 *
37053 * @param {CanvasRenderingContext2D} ctx
37054 * @param {string} color
37055 * @private
37056 */
37057
37058 }, {
37059 key: "_debug",
37060 value: function _debug(ctx, color) {
37061 if (this.barnesHutTree !== undefined) {
37062 ctx.lineWidth = 1;
37063
37064 this._drawBranch(this.barnesHutTree.root, ctx, color);
37065 }
37066 }
37067 /**
37068 * This function is for debugging purposes. It draws the branches recursively.
37069 *
37070 * @param {Object} branch
37071 * @param {CanvasRenderingContext2D} ctx
37072 * @param {string} color
37073 * @private
37074 */
37075
37076 }, {
37077 key: "_drawBranch",
37078 value: function _drawBranch(branch, ctx, color) {
37079 if (color === undefined) {
37080 color = "#FF0000";
37081 }
37082
37083 if (branch.childrenCount === 4) {
37084 this._drawBranch(branch.children.NW, ctx);
37085
37086 this._drawBranch(branch.children.NE, ctx);
37087
37088 this._drawBranch(branch.children.SE, ctx);
37089
37090 this._drawBranch(branch.children.SW, ctx);
37091 }
37092
37093 ctx.strokeStyle = color;
37094 ctx.beginPath();
37095 ctx.moveTo(branch.range.minX, branch.range.minY);
37096 ctx.lineTo(branch.range.maxX, branch.range.minY);
37097 ctx.stroke();
37098 ctx.beginPath();
37099 ctx.moveTo(branch.range.maxX, branch.range.minY);
37100 ctx.lineTo(branch.range.maxX, branch.range.maxY);
37101 ctx.stroke();
37102 ctx.beginPath();
37103 ctx.moveTo(branch.range.maxX, branch.range.maxY);
37104 ctx.lineTo(branch.range.minX, branch.range.maxY);
37105 ctx.stroke();
37106 ctx.beginPath();
37107 ctx.moveTo(branch.range.minX, branch.range.maxY);
37108 ctx.lineTo(branch.range.minX, branch.range.minY);
37109 ctx.stroke();
37110 /*
37111 if (branch.mass > 0) {
37112 ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass);
37113 ctx.stroke();
37114 }
37115 */
37116 }
37117 }]);
37118
37119 return BarnesHutSolver;
37120 }();
37121
37122 /**
37123 * Repulsion Solver
37124 */
37125 var RepulsionSolver =
37126 /*#__PURE__*/
37127 function () {
37128 /**
37129 * @param {Object} body
37130 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37131 * @param {Object} options
37132 */
37133 function RepulsionSolver(body, physicsBody, options) {
37134 _classCallCheck(this, RepulsionSolver);
37135
37136 this.body = body;
37137 this.physicsBody = physicsBody;
37138 this.setOptions(options);
37139 }
37140 /**
37141 *
37142 * @param {Object} options
37143 */
37144
37145
37146 _createClass(RepulsionSolver, [{
37147 key: "setOptions",
37148 value: function setOptions(options) {
37149 this.options = options;
37150 }
37151 /**
37152 * Calculate the forces the nodes apply on each other based on a repulsion field.
37153 * This field is linearly approximated.
37154 *
37155 * @private
37156 */
37157
37158 }, {
37159 key: "solve",
37160 value: function solve() {
37161 var dx, dy, distance, fx, fy, repulsingForce, node1, node2;
37162 var nodes = this.body.nodes;
37163 var nodeIndices = this.physicsBody.physicsNodeIndices;
37164 var forces = this.physicsBody.forces; // repulsing forces between nodes
37165
37166 var nodeDistance = this.options.nodeDistance; // approximation constants
37167
37168 var a = -2 / 3 / nodeDistance;
37169 var b = 4 / 3; // we loop from i over all but the last entree in the array
37170 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
37171
37172 for (var i = 0; i < nodeIndices.length - 1; i++) {
37173 node1 = nodes[nodeIndices[i]];
37174
37175 for (var j = i + 1; j < nodeIndices.length; j++) {
37176 node2 = nodes[nodeIndices[j]];
37177 dx = node2.x - node1.x;
37178 dy = node2.y - node1.y;
37179 distance = Math.sqrt(dx * dx + dy * dy); // same condition as BarnesHutSolver, making sure nodes are never 100% overlapping.
37180
37181 if (distance === 0) {
37182 distance = 0.1 * Math.random();
37183 dx = distance;
37184 }
37185
37186 if (distance < 2 * nodeDistance) {
37187 if (distance < 0.5 * nodeDistance) {
37188 repulsingForce = 1.0;
37189 } else {
37190 repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / nodeDistance - 1) * steepness))
37191 }
37192
37193 repulsingForce = repulsingForce / distance;
37194 fx = dx * repulsingForce;
37195 fy = dy * repulsingForce;
37196 forces[node1.id].x -= fx;
37197 forces[node1.id].y -= fy;
37198 forces[node2.id].x += fx;
37199 forces[node2.id].y += fy;
37200 }
37201 }
37202 }
37203 }
37204 }]);
37205
37206 return RepulsionSolver;
37207 }();
37208
37209 /**
37210 * Hierarchical Repulsion Solver
37211 */
37212 var HierarchicalRepulsionSolver =
37213 /*#__PURE__*/
37214 function () {
37215 /**
37216 * @param {Object} body
37217 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37218 * @param {Object} options
37219 */
37220 function HierarchicalRepulsionSolver(body, physicsBody, options) {
37221 _classCallCheck(this, HierarchicalRepulsionSolver);
37222
37223 this.body = body;
37224 this.physicsBody = physicsBody;
37225 this.setOptions(options);
37226 }
37227 /**
37228 *
37229 * @param {Object} options
37230 */
37231
37232
37233 _createClass(HierarchicalRepulsionSolver, [{
37234 key: "setOptions",
37235 value: function setOptions(options) {
37236 this.options = options;
37237 this.overlapAvoidanceFactor = Math.max(0, Math.min(1, this.options.avoidOverlap || 0));
37238 }
37239 /**
37240 * Calculate the forces the nodes apply on each other based on a repulsion field.
37241 * This field is linearly approximated.
37242 *
37243 * @private
37244 */
37245
37246 }, {
37247 key: "solve",
37248 value: function solve() {
37249 var nodes = this.body.nodes;
37250 var nodeIndices = this.physicsBody.physicsNodeIndices;
37251 var forces = this.physicsBody.forces; // repulsing forces between nodes
37252
37253 var nodeDistance = this.options.nodeDistance; // we loop from i over all but the last entree in the array
37254 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
37255
37256 for (var i = 0; i < nodeIndices.length - 1; i++) {
37257 var node1 = nodes[nodeIndices[i]];
37258
37259 for (var j = i + 1; j < nodeIndices.length; j++) {
37260 var node2 = nodes[nodeIndices[j]]; // nodes only affect nodes on their level
37261
37262 if (node1.level === node2.level) {
37263 var theseNodesDistance = nodeDistance + this.overlapAvoidanceFactor * ((node1.shape.radius || 0) / 2 + (node2.shape.radius || 0) / 2);
37264 var dx = node2.x - node1.x;
37265 var dy = node2.y - node1.y;
37266 var distance = Math.sqrt(dx * dx + dy * dy);
37267 var steepness = 0.05;
37268 var repulsingForce = void 0;
37269
37270 if (distance < theseNodesDistance) {
37271 repulsingForce = -Math.pow(steepness * distance, 2) + Math.pow(steepness * theseNodesDistance, 2);
37272 } else {
37273 repulsingForce = 0;
37274 } // normalize force with
37275
37276
37277 if (distance === 0) {
37278 distance = (_readOnlyError("distance"), 0.01);
37279 } else {
37280 repulsingForce = repulsingForce / distance;
37281 }
37282
37283 var fx = dx * repulsingForce;
37284 var fy = dy * repulsingForce;
37285 forces[node1.id].x -= fx;
37286 forces[node1.id].y -= fy;
37287 forces[node2.id].x += fx;
37288 forces[node2.id].y += fy;
37289 }
37290 }
37291 }
37292 }
37293 }]);
37294
37295 return HierarchicalRepulsionSolver;
37296 }();
37297
37298 /**
37299 * Spring Solver
37300 */
37301 var SpringSolver =
37302 /*#__PURE__*/
37303 function () {
37304 /**
37305 * @param {Object} body
37306 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37307 * @param {Object} options
37308 */
37309 function SpringSolver(body, physicsBody, options) {
37310 _classCallCheck(this, SpringSolver);
37311
37312 this.body = body;
37313 this.physicsBody = physicsBody;
37314 this.setOptions(options);
37315 }
37316 /**
37317 *
37318 * @param {Object} options
37319 */
37320
37321
37322 _createClass(SpringSolver, [{
37323 key: "setOptions",
37324 value: function setOptions(options) {
37325 this.options = options;
37326 }
37327 /**
37328 * This function calculates the springforces on the nodes, accounting for the support nodes.
37329 *
37330 * @private
37331 */
37332
37333 }, {
37334 key: "solve",
37335 value: function solve() {
37336 var edgeLength, edge;
37337 var edgeIndices = this.physicsBody.physicsEdgeIndices;
37338 var edges = this.body.edges;
37339 var node1, node2, node3; // forces caused by the edges, modelled as springs
37340
37341 for (var i = 0; i < edgeIndices.length; i++) {
37342 edge = edges[edgeIndices[i]];
37343
37344 if (edge.connected === true && edge.toId !== edge.fromId) {
37345 // only calculate forces if nodes are in the same sector
37346 if (this.body.nodes[edge.toId] !== undefined && this.body.nodes[edge.fromId] !== undefined) {
37347 if (edge.edgeType.via !== undefined) {
37348 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
37349 node1 = edge.to;
37350 node2 = edge.edgeType.via;
37351 node3 = edge.from;
37352
37353 this._calculateSpringForce(node1, node2, 0.5 * edgeLength);
37354
37355 this._calculateSpringForce(node2, node3, 0.5 * edgeLength);
37356 } else {
37357 // the * 1.5 is here so the edge looks as large as a smooth edge. It does not initially because the smooth edges use
37358 // the support nodes which exert a repulsive force on the to and from nodes, making the edge appear larger.
37359 edgeLength = edge.options.length === undefined ? this.options.springLength * 1.5 : edge.options.length;
37360
37361 this._calculateSpringForce(edge.from, edge.to, edgeLength);
37362 }
37363 }
37364 }
37365 }
37366 }
37367 /**
37368 * This is the code actually performing the calculation for the function above.
37369 *
37370 * @param {Node} node1
37371 * @param {Node} node2
37372 * @param {number} edgeLength
37373 * @private
37374 */
37375
37376 }, {
37377 key: "_calculateSpringForce",
37378 value: function _calculateSpringForce(node1, node2, edgeLength) {
37379 var dx = node1.x - node2.x;
37380 var dy = node1.y - node2.y;
37381 var distance = Math.max(Math.sqrt(dx * dx + dy * dy), 0.01); // the 1/distance is so the fx and fy can be calculated without sine or cosine.
37382
37383 var springForce = this.options.springConstant * (edgeLength - distance) / distance;
37384 var fx = dx * springForce;
37385 var fy = dy * springForce; // handle the case where one node is not part of the physcis
37386
37387 if (this.physicsBody.forces[node1.id] !== undefined) {
37388 this.physicsBody.forces[node1.id].x += fx;
37389 this.physicsBody.forces[node1.id].y += fy;
37390 }
37391
37392 if (this.physicsBody.forces[node2.id] !== undefined) {
37393 this.physicsBody.forces[node2.id].x -= fx;
37394 this.physicsBody.forces[node2.id].y -= fy;
37395 }
37396 }
37397 }]);
37398
37399 return SpringSolver;
37400 }();
37401
37402 /**
37403 * Hierarchical Spring Solver
37404 */
37405 var HierarchicalSpringSolver =
37406 /*#__PURE__*/
37407 function () {
37408 /**
37409 * @param {Object} body
37410 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37411 * @param {Object} options
37412 */
37413 function HierarchicalSpringSolver(body, physicsBody, options) {
37414 _classCallCheck(this, HierarchicalSpringSolver);
37415
37416 this.body = body;
37417 this.physicsBody = physicsBody;
37418 this.setOptions(options);
37419 }
37420 /**
37421 *
37422 * @param {Object} options
37423 */
37424
37425
37426 _createClass(HierarchicalSpringSolver, [{
37427 key: "setOptions",
37428 value: function setOptions(options) {
37429 this.options = options;
37430 }
37431 /**
37432 * This function calculates the springforces on the nodes, accounting for the support nodes.
37433 *
37434 * @private
37435 */
37436
37437 }, {
37438 key: "solve",
37439 value: function solve() {
37440 var edgeLength, edge;
37441 var dx, dy, fx, fy, springForce, distance;
37442 var edges = this.body.edges;
37443 var factor = 0.5;
37444 var edgeIndices = this.physicsBody.physicsEdgeIndices;
37445 var nodeIndices = this.physicsBody.physicsNodeIndices;
37446 var forces = this.physicsBody.forces; // initialize the spring force counters
37447
37448 for (var i = 0; i < nodeIndices.length; i++) {
37449 var nodeId = nodeIndices[i];
37450 forces[nodeId].springFx = 0;
37451 forces[nodeId].springFy = 0;
37452 } // forces caused by the edges, modelled as springs
37453
37454
37455 for (var _i = 0; _i < edgeIndices.length; _i++) {
37456 edge = edges[edgeIndices[_i]];
37457
37458 if (edge.connected === true) {
37459 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
37460 dx = edge.from.x - edge.to.x;
37461 dy = edge.from.y - edge.to.y;
37462 distance = Math.sqrt(dx * dx + dy * dy);
37463 distance = distance === 0 ? 0.01 : distance; // the 1/distance is so the fx and fy can be calculated without sine or cosine.
37464
37465 springForce = this.options.springConstant * (edgeLength - distance) / distance;
37466 fx = dx * springForce;
37467 fy = dy * springForce;
37468
37469 if (edge.to.level != edge.from.level) {
37470 if (forces[edge.toId] !== undefined) {
37471 forces[edge.toId].springFx -= fx;
37472 forces[edge.toId].springFy -= fy;
37473 }
37474
37475 if (forces[edge.fromId] !== undefined) {
37476 forces[edge.fromId].springFx += fx;
37477 forces[edge.fromId].springFy += fy;
37478 }
37479 } else {
37480 if (forces[edge.toId] !== undefined) {
37481 forces[edge.toId].x -= factor * fx;
37482 forces[edge.toId].y -= factor * fy;
37483 }
37484
37485 if (forces[edge.fromId] !== undefined) {
37486 forces[edge.fromId].x += factor * fx;
37487 forces[edge.fromId].y += factor * fy;
37488 }
37489 }
37490 }
37491 } // normalize spring forces
37492
37493
37494 springForce = 1;
37495 var springFx, springFy;
37496
37497 for (var _i2 = 0; _i2 < nodeIndices.length; _i2++) {
37498 var _nodeId = nodeIndices[_i2];
37499 springFx = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFx));
37500 springFy = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFy));
37501 forces[_nodeId].x += springFx;
37502 forces[_nodeId].y += springFy;
37503 } // retain energy balance
37504
37505
37506 var totalFx = 0;
37507 var totalFy = 0;
37508
37509 for (var _i3 = 0; _i3 < nodeIndices.length; _i3++) {
37510 var _nodeId2 = nodeIndices[_i3];
37511 totalFx += forces[_nodeId2].x;
37512 totalFy += forces[_nodeId2].y;
37513 }
37514
37515 var correctionFx = totalFx / nodeIndices.length;
37516 var correctionFy = totalFy / nodeIndices.length;
37517
37518 for (var _i4 = 0; _i4 < nodeIndices.length; _i4++) {
37519 var _nodeId3 = nodeIndices[_i4];
37520 forces[_nodeId3].x -= correctionFx;
37521 forces[_nodeId3].y -= correctionFy;
37522 }
37523 }
37524 }]);
37525
37526 return HierarchicalSpringSolver;
37527 }();
37528
37529 /**
37530 * Central Gravity Solver
37531 */
37532 var CentralGravitySolver =
37533 /*#__PURE__*/
37534 function () {
37535 /**
37536 * @param {Object} body
37537 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37538 * @param {Object} options
37539 */
37540 function CentralGravitySolver(body, physicsBody, options) {
37541 _classCallCheck(this, CentralGravitySolver);
37542
37543 this.body = body;
37544 this.physicsBody = physicsBody;
37545 this.setOptions(options);
37546 }
37547 /**
37548 *
37549 * @param {Object} options
37550 */
37551
37552
37553 _createClass(CentralGravitySolver, [{
37554 key: "setOptions",
37555 value: function setOptions(options) {
37556 this.options = options;
37557 }
37558 /**
37559 * Calculates forces for each node
37560 */
37561
37562 }, {
37563 key: "solve",
37564 value: function solve() {
37565 var dx, dy, distance, node;
37566 var nodes = this.body.nodes;
37567 var nodeIndices = this.physicsBody.physicsNodeIndices;
37568 var forces = this.physicsBody.forces;
37569
37570 for (var i = 0; i < nodeIndices.length; i++) {
37571 var nodeId = nodeIndices[i];
37572 node = nodes[nodeId];
37573 dx = -node.x;
37574 dy = -node.y;
37575 distance = Math.sqrt(dx * dx + dy * dy);
37576
37577 this._calculateForces(distance, dx, dy, forces, node);
37578 }
37579 }
37580 /**
37581 * Calculate the forces based on the distance.
37582 * @param {number} distance
37583 * @param {number} dx
37584 * @param {number} dy
37585 * @param {Object<Node.id, vis.Node>} forces
37586 * @param {Node} node
37587 * @private
37588 */
37589
37590 }, {
37591 key: "_calculateForces",
37592 value: function _calculateForces(distance, dx, dy, forces, node) {
37593 var gravityForce = distance === 0 ? 0 : this.options.centralGravity / distance;
37594 forces[node.id].x = dx * gravityForce;
37595 forces[node.id].y = dy * gravityForce;
37596 }
37597 }]);
37598
37599 return CentralGravitySolver;
37600 }();
37601
37602 /**
37603 * @extends BarnesHutSolver
37604 */
37605
37606 var ForceAtlas2BasedRepulsionSolver =
37607 /*#__PURE__*/
37608 function (_BarnesHutSolver) {
37609 _inherits(ForceAtlas2BasedRepulsionSolver, _BarnesHutSolver);
37610
37611 /**
37612 * @param {Object} body
37613 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37614 * @param {Object} options
37615 */
37616 function ForceAtlas2BasedRepulsionSolver(body, physicsBody, options) {
37617 _classCallCheck(this, ForceAtlas2BasedRepulsionSolver);
37618
37619 return _possibleConstructorReturn(this, _getPrototypeOf(ForceAtlas2BasedRepulsionSolver).call(this, body, physicsBody, options));
37620 }
37621 /**
37622 * Calculate the forces based on the distance.
37623 *
37624 * @param {number} distance
37625 * @param {number} dx
37626 * @param {number} dy
37627 * @param {Node} node
37628 * @param {Object} parentBranch
37629 * @private
37630 */
37631
37632
37633 _createClass(ForceAtlas2BasedRepulsionSolver, [{
37634 key: "_calculateForces",
37635 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
37636 if (distance === 0) {
37637 distance = 0.1 * Math.random();
37638 dx = distance;
37639 }
37640
37641 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
37642 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
37643 }
37644
37645 var degree = node.edges.length + 1; // the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
37646 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
37647
37648 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass * degree / Math.pow(distance, 2);
37649 var fx = dx * gravityForce;
37650 var fy = dy * gravityForce;
37651 this.physicsBody.forces[node.id].x += fx;
37652 this.physicsBody.forces[node.id].y += fy;
37653 }
37654 }]);
37655
37656 return ForceAtlas2BasedRepulsionSolver;
37657 }(BarnesHutSolver);
37658
37659 /**
37660 * @extends CentralGravitySolver
37661 */
37662
37663 var ForceAtlas2BasedCentralGravitySolver =
37664 /*#__PURE__*/
37665 function (_CentralGravitySolver) {
37666 _inherits(ForceAtlas2BasedCentralGravitySolver, _CentralGravitySolver);
37667
37668 /**
37669 * @param {Object} body
37670 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37671 * @param {Object} options
37672 */
37673 function ForceAtlas2BasedCentralGravitySolver(body, physicsBody, options) {
37674 _classCallCheck(this, ForceAtlas2BasedCentralGravitySolver);
37675
37676 return _possibleConstructorReturn(this, _getPrototypeOf(ForceAtlas2BasedCentralGravitySolver).call(this, body, physicsBody, options));
37677 }
37678 /**
37679 * Calculate the forces based on the distance.
37680 *
37681 * @param {number} distance
37682 * @param {number} dx
37683 * @param {number} dy
37684 * @param {Object<Node.id, Node>} forces
37685 * @param {Node} node
37686 * @private
37687 */
37688
37689
37690 _createClass(ForceAtlas2BasedCentralGravitySolver, [{
37691 key: "_calculateForces",
37692 value: function _calculateForces(distance, dx, dy, forces, node) {
37693 if (distance > 0) {
37694 var degree = node.edges.length + 1;
37695 var gravityForce = this.options.centralGravity * degree * node.options.mass;
37696 forces[node.id].x = dx * gravityForce;
37697 forces[node.id].y = dy * gravityForce;
37698 }
37699 }
37700 }]);
37701
37702 return ForceAtlas2BasedCentralGravitySolver;
37703 }(CentralGravitySolver);
37704
37705 /**
37706 * The physics engine
37707 */
37708
37709 var PhysicsEngine =
37710 /*#__PURE__*/
37711 function () {
37712 /**
37713 * @param {Object} body
37714 */
37715 function PhysicsEngine(body) {
37716 _classCallCheck(this, PhysicsEngine);
37717
37718 this.body = body;
37719 this.physicsBody = {
37720 physicsNodeIndices: [],
37721 physicsEdgeIndices: [],
37722 forces: {},
37723 velocities: {}
37724 };
37725 this.physicsEnabled = true;
37726 this.simulationInterval = 1000 / 60;
37727 this.requiresTimeout = true;
37728 this.previousStates = {};
37729 this.referenceState = {};
37730 this.freezeCache = {};
37731 this.renderTimer = undefined; // parameters for the adaptive timestep
37732
37733 this.adaptiveTimestep = false;
37734 this.adaptiveTimestepEnabled = false;
37735 this.adaptiveCounter = 0;
37736 this.adaptiveInterval = 3;
37737 this.stabilized = false;
37738 this.startedStabilization = false;
37739 this.stabilizationIterations = 0;
37740 this.ready = false; // will be set to true if the stabilize
37741 // default options
37742
37743 this.options = {};
37744 this.defaultOptions = {
37745 enabled: true,
37746 barnesHut: {
37747 theta: 0.5,
37748 gravitationalConstant: -2000,
37749 centralGravity: 0.3,
37750 springLength: 95,
37751 springConstant: 0.04,
37752 damping: 0.09,
37753 avoidOverlap: 0
37754 },
37755 forceAtlas2Based: {
37756 theta: 0.5,
37757 gravitationalConstant: -50,
37758 centralGravity: 0.01,
37759 springConstant: 0.08,
37760 springLength: 100,
37761 damping: 0.4,
37762 avoidOverlap: 0
37763 },
37764 repulsion: {
37765 centralGravity: 0.2,
37766 springLength: 200,
37767 springConstant: 0.05,
37768 nodeDistance: 100,
37769 damping: 0.09,
37770 avoidOverlap: 0
37771 },
37772 hierarchicalRepulsion: {
37773 centralGravity: 0.0,
37774 springLength: 100,
37775 springConstant: 0.01,
37776 nodeDistance: 120,
37777 damping: 0.09
37778 },
37779 maxVelocity: 50,
37780 minVelocity: 0.75,
37781 // px/s
37782 solver: 'barnesHut',
37783 stabilization: {
37784 enabled: true,
37785 iterations: 1000,
37786 // maximum number of iteration to stabilize
37787 updateInterval: 50,
37788 onlyDynamicEdges: false,
37789 fit: true
37790 },
37791 timestep: 0.5,
37792 adaptiveTimestep: true
37793 };
37794 extend(this.options, this.defaultOptions);
37795 this.timestep = 0.5;
37796 this.layoutFailed = false;
37797 this.bindEventListeners();
37798 }
37799 /**
37800 * Binds event listeners
37801 */
37802
37803
37804 _createClass(PhysicsEngine, [{
37805 key: "bindEventListeners",
37806 value: function bindEventListeners() {
37807 var _this = this;
37808
37809 this.body.emitter.on('initPhysics', function () {
37810 _this.initPhysics();
37811 });
37812 this.body.emitter.on('_layoutFailed', function () {
37813 _this.layoutFailed = true;
37814 });
37815 this.body.emitter.on('resetPhysics', function () {
37816 _this.stopSimulation();
37817
37818 _this.ready = false;
37819 });
37820 this.body.emitter.on('disablePhysics', function () {
37821 _this.physicsEnabled = false;
37822
37823 _this.stopSimulation();
37824 });
37825 this.body.emitter.on('restorePhysics', function () {
37826 _this.setOptions(_this.options);
37827
37828 if (_this.ready === true) {
37829 _this.startSimulation();
37830 }
37831 });
37832 this.body.emitter.on('startSimulation', function () {
37833 if (_this.ready === true) {
37834 _this.startSimulation();
37835 }
37836 });
37837 this.body.emitter.on('stopSimulation', function () {
37838 _this.stopSimulation();
37839 });
37840 this.body.emitter.on('destroy', function () {
37841 _this.stopSimulation(false);
37842
37843 _this.body.emitter.off();
37844 });
37845 this.body.emitter.on("_dataChanged", function () {
37846 // Nodes and/or edges have been added or removed, update shortcut lists.
37847 _this.updatePhysicsData();
37848 }); // debug: show forces
37849 // this.body.emitter.on("afterDrawing", (ctx) => {this._drawForces(ctx);});
37850 }
37851 /**
37852 * set the physics options
37853 * @param {Object} options
37854 */
37855
37856 }, {
37857 key: "setOptions",
37858 value: function setOptions(options) {
37859 if (options !== undefined) {
37860 if (options === false) {
37861 this.options.enabled = false;
37862 this.physicsEnabled = false;
37863 this.stopSimulation();
37864 } else if (options === true) {
37865 this.options.enabled = true;
37866 this.physicsEnabled = true;
37867 this.startSimulation();
37868 } else {
37869 this.physicsEnabled = true;
37870 selectiveNotDeepExtend(['stabilization'], this.options, options);
37871 mergeOptions(this.options, options, 'stabilization');
37872
37873 if (options.enabled === undefined) {
37874 this.options.enabled = true;
37875 }
37876
37877 if (this.options.enabled === false) {
37878 this.physicsEnabled = false;
37879 this.stopSimulation();
37880 } // set the timestep
37881
37882
37883 this.timestep = this.options.timestep;
37884 }
37885 }
37886
37887 this.init();
37888 }
37889 /**
37890 * configure the engine.
37891 */
37892
37893 }, {
37894 key: "init",
37895 value: function init() {
37896 var options;
37897
37898 if (this.options.solver === 'forceAtlas2Based') {
37899 options = this.options.forceAtlas2Based;
37900 this.nodesSolver = new ForceAtlas2BasedRepulsionSolver(this.body, this.physicsBody, options);
37901 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
37902 this.gravitySolver = new ForceAtlas2BasedCentralGravitySolver(this.body, this.physicsBody, options);
37903 } else if (this.options.solver === 'repulsion') {
37904 options = this.options.repulsion;
37905 this.nodesSolver = new RepulsionSolver(this.body, this.physicsBody, options);
37906 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
37907 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
37908 } else if (this.options.solver === 'hierarchicalRepulsion') {
37909 options = this.options.hierarchicalRepulsion;
37910 this.nodesSolver = new HierarchicalRepulsionSolver(this.body, this.physicsBody, options);
37911 this.edgesSolver = new HierarchicalSpringSolver(this.body, this.physicsBody, options);
37912 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
37913 } else {
37914 // barnesHut
37915 options = this.options.barnesHut;
37916 this.nodesSolver = new BarnesHutSolver(this.body, this.physicsBody, options);
37917 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
37918 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
37919 }
37920
37921 this.modelOptions = options;
37922 }
37923 /**
37924 * initialize the engine
37925 */
37926
37927 }, {
37928 key: "initPhysics",
37929 value: function initPhysics() {
37930 if (this.physicsEnabled === true && this.options.enabled === true) {
37931 if (this.options.stabilization.enabled === true) {
37932 this.stabilize();
37933 } else {
37934 this.stabilized = false;
37935 this.ready = true;
37936 this.body.emitter.emit('fit', {}, this.layoutFailed); // if the layout failed, we use the approximation for the zoom
37937
37938 this.startSimulation();
37939 }
37940 } else {
37941 this.ready = true;
37942 this.body.emitter.emit('fit');
37943 }
37944 }
37945 /**
37946 * Start the simulation
37947 */
37948
37949 }, {
37950 key: "startSimulation",
37951 value: function startSimulation() {
37952 if (this.physicsEnabled === true && this.options.enabled === true) {
37953 this.stabilized = false; // when visible, adaptivity is disabled.
37954
37955 this.adaptiveTimestep = false; // this sets the width of all nodes initially which could be required for the avoidOverlap
37956
37957 this.body.emitter.emit("_resizeNodes");
37958
37959 if (this.viewFunction === undefined) {
37960 this.viewFunction = this.simulationStep.bind(this);
37961 this.body.emitter.on('initRedraw', this.viewFunction);
37962 this.body.emitter.emit('_startRendering');
37963 }
37964 } else {
37965 this.body.emitter.emit('_redraw');
37966 }
37967 }
37968 /**
37969 * Stop the simulation, force stabilization.
37970 * @param {boolean} [emit=true]
37971 */
37972
37973 }, {
37974 key: "stopSimulation",
37975 value: function stopSimulation() {
37976 var emit = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
37977 this.stabilized = true;
37978
37979 if (emit === true) {
37980 this._emitStabilized();
37981 }
37982
37983 if (this.viewFunction !== undefined) {
37984 this.body.emitter.off('initRedraw', this.viewFunction);
37985 this.viewFunction = undefined;
37986
37987 if (emit === true) {
37988 this.body.emitter.emit('_stopRendering');
37989 }
37990 }
37991 }
37992 /**
37993 * The viewFunction inserts this step into each render loop. It calls the physics tick and handles the cleanup at stabilized.
37994 *
37995 */
37996
37997 }, {
37998 key: "simulationStep",
37999 value: function simulationStep() {
38000 // check if the physics have settled
38001 var startTime = Date.now();
38002 this.physicsTick();
38003 var physicsTime = Date.now() - startTime; // run double speed if it is a little graph
38004
38005 if ((physicsTime < 0.4 * this.simulationInterval || this.runDoubleSpeed === true) && this.stabilized === false) {
38006 this.physicsTick(); // this makes sure there is no jitter. The decision is taken once to run it at double speed.
38007
38008 this.runDoubleSpeed = true;
38009 }
38010
38011 if (this.stabilized === true) {
38012 this.stopSimulation();
38013 }
38014 }
38015 /**
38016 * trigger the stabilized event.
38017 *
38018 * @param {number} [amountOfIterations=this.stabilizationIterations]
38019 * @private
38020 */
38021
38022 }, {
38023 key: "_emitStabilized",
38024 value: function _emitStabilized() {
38025 var _this2 = this;
38026
38027 var amountOfIterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.stabilizationIterations;
38028
38029 if (this.stabilizationIterations > 1 || this.startedStabilization === true) {
38030 setTimeout(function () {
38031 _this2.body.emitter.emit('stabilized', {
38032 iterations: amountOfIterations
38033 });
38034
38035 _this2.startedStabilization = false;
38036 _this2.stabilizationIterations = 0;
38037 }, 0);
38038 }
38039 }
38040 /**
38041 * Calculate the forces for one physics iteration and move the nodes.
38042 * @private
38043 */
38044
38045 }, {
38046 key: "physicsStep",
38047 value: function physicsStep() {
38048 this.gravitySolver.solve();
38049 this.nodesSolver.solve();
38050 this.edgesSolver.solve();
38051 this.moveNodes();
38052 }
38053 /**
38054 * Make dynamic adjustments to the timestep, based on current state.
38055 *
38056 * Helper function for physicsTick().
38057 * @private
38058 */
38059
38060 }, {
38061 key: "adjustTimeStep",
38062 value: function adjustTimeStep() {
38063 var factor = 1.2; // Factor for increasing the timestep on success.
38064 // we compare the two steps. if it is acceptable we double the step.
38065
38066 if (this._evaluateStepQuality() === true) {
38067 this.timestep = factor * this.timestep;
38068 } else {
38069 // if not, we decrease the step to a minimum of the options timestep.
38070 // if the decreased timestep is smaller than the options step, we do not reset the counter
38071 // we assume that the options timestep is stable enough.
38072 if (this.timestep / factor < this.options.timestep) {
38073 this.timestep = this.options.timestep;
38074 } else {
38075 // if the timestep was larger than 2 times the option one we check the adaptivity again to ensure
38076 // that large instabilities do not form.
38077 this.adaptiveCounter = -1; // check again next iteration
38078
38079 this.timestep = Math.max(this.options.timestep, this.timestep / factor);
38080 }
38081 }
38082 }
38083 /**
38084 * A single simulation step (or 'tick') in the physics simulation
38085 *
38086 * @private
38087 */
38088
38089 }, {
38090 key: "physicsTick",
38091 value: function physicsTick() {
38092 this._startStabilizing(); // this ensures that there is no start event when the network is already stable.
38093
38094
38095 if (this.stabilized === true) return; // adaptivity means the timestep adapts to the situation, only applicable for stabilization
38096
38097 if (this.adaptiveTimestep === true && this.adaptiveTimestepEnabled === true) {
38098 // timestep remains stable for "interval" iterations.
38099 var doAdaptive = this.adaptiveCounter % this.adaptiveInterval === 0;
38100
38101 if (doAdaptive) {
38102 // first the big step and revert.
38103 this.timestep = 2 * this.timestep;
38104 this.physicsStep();
38105 this.revert(); // saves the reference state
38106 // now the normal step. Since this is the last step, it is the more stable one and we will take this.
38107
38108 this.timestep = 0.5 * this.timestep; // since it's half the step, we do it twice.
38109
38110 this.physicsStep();
38111 this.physicsStep();
38112 this.adjustTimeStep();
38113 } else {
38114 this.physicsStep(); // normal step, keeping timestep constant
38115 }
38116
38117 this.adaptiveCounter += 1;
38118 } else {
38119 // case for the static timestep, we reset it to the one in options and take a normal step.
38120 this.timestep = this.options.timestep;
38121 this.physicsStep();
38122 }
38123
38124 if (this.stabilized === true) this.revert();
38125 this.stabilizationIterations++;
38126 }
38127 /**
38128 * Nodes and edges can have the physics toggles on or off. A collection of indices is created here so we can skip the check all the time.
38129 *
38130 * @private
38131 */
38132
38133 }, {
38134 key: "updatePhysicsData",
38135 value: function updatePhysicsData() {
38136 this.physicsBody.forces = {};
38137 this.physicsBody.physicsNodeIndices = [];
38138 this.physicsBody.physicsEdgeIndices = [];
38139 var nodes = this.body.nodes;
38140 var edges = this.body.edges; // get node indices for physics
38141
38142 for (var nodeId in nodes) {
38143 if (nodes.hasOwnProperty(nodeId)) {
38144 if (nodes[nodeId].options.physics === true) {
38145 this.physicsBody.physicsNodeIndices.push(nodes[nodeId].id);
38146 }
38147 }
38148 } // get edge indices for physics
38149
38150
38151 for (var edgeId in edges) {
38152 if (edges.hasOwnProperty(edgeId)) {
38153 if (edges[edgeId].options.physics === true) {
38154 this.physicsBody.physicsEdgeIndices.push(edges[edgeId].id);
38155 }
38156 }
38157 } // get the velocity and the forces vector
38158
38159
38160 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
38161 var _nodeId = this.physicsBody.physicsNodeIndices[i];
38162 this.physicsBody.forces[_nodeId] = {
38163 x: 0,
38164 y: 0
38165 }; // forces can be reset because they are recalculated. Velocities have to persist.
38166
38167 if (this.physicsBody.velocities[_nodeId] === undefined) {
38168 this.physicsBody.velocities[_nodeId] = {
38169 x: 0,
38170 y: 0
38171 };
38172 }
38173 } // clean deleted nodes from the velocity vector
38174
38175
38176 for (var _nodeId2 in this.physicsBody.velocities) {
38177 if (nodes[_nodeId2] === undefined) {
38178 delete this.physicsBody.velocities[_nodeId2];
38179 }
38180 }
38181 }
38182 /**
38183 * Revert the simulation one step. This is done so after stabilization, every new start of the simulation will also say stabilized.
38184 */
38185
38186 }, {
38187 key: "revert",
38188 value: function revert() {
38189 var nodeIds = Object.keys(this.previousStates);
38190 var nodes = this.body.nodes;
38191 var velocities = this.physicsBody.velocities;
38192 this.referenceState = {};
38193
38194 for (var i = 0; i < nodeIds.length; i++) {
38195 var nodeId = nodeIds[i];
38196
38197 if (nodes[nodeId] !== undefined) {
38198 if (nodes[nodeId].options.physics === true) {
38199 this.referenceState[nodeId] = {
38200 positions: {
38201 x: nodes[nodeId].x,
38202 y: nodes[nodeId].y
38203 }
38204 };
38205 velocities[nodeId].x = this.previousStates[nodeId].vx;
38206 velocities[nodeId].y = this.previousStates[nodeId].vy;
38207 nodes[nodeId].x = this.previousStates[nodeId].x;
38208 nodes[nodeId].y = this.previousStates[nodeId].y;
38209 }
38210 } else {
38211 delete this.previousStates[nodeId];
38212 }
38213 }
38214 }
38215 /**
38216 * This compares the reference state to the current state
38217 *
38218 * @returns {boolean}
38219 * @private
38220 */
38221
38222 }, {
38223 key: "_evaluateStepQuality",
38224 value: function _evaluateStepQuality() {
38225 var dx, dy, dpos;
38226 var nodes = this.body.nodes;
38227 var reference = this.referenceState;
38228 var posThreshold = 0.3;
38229
38230 for (var nodeId in this.referenceState) {
38231 if (this.referenceState.hasOwnProperty(nodeId) && nodes[nodeId] !== undefined) {
38232 dx = nodes[nodeId].x - reference[nodeId].positions.x;
38233 dy = nodes[nodeId].y - reference[nodeId].positions.y;
38234 dpos = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
38235
38236 if (dpos > posThreshold) {
38237 return false;
38238 }
38239 }
38240 }
38241
38242 return true;
38243 }
38244 /**
38245 * move the nodes one timestep and check if they are stabilized
38246 */
38247
38248 }, {
38249 key: "moveNodes",
38250 value: function moveNodes() {
38251 var nodeIndices = this.physicsBody.physicsNodeIndices;
38252 var maxNodeVelocity = 0;
38253 var averageNodeVelocity = 0; // the velocity threshold (energy in the system) for the adaptivity toggle
38254
38255 var velocityAdaptiveThreshold = 5;
38256
38257 for (var i = 0; i < nodeIndices.length; i++) {
38258 var nodeId = nodeIndices[i];
38259
38260 var nodeVelocity = this._performStep(nodeId); // stabilized is true if stabilized is true and velocity is smaller than vmin --> all nodes must be stabilized
38261
38262
38263 maxNodeVelocity = Math.max(maxNodeVelocity, nodeVelocity);
38264 averageNodeVelocity += nodeVelocity;
38265 } // evaluating the stabilized and adaptiveTimestepEnabled conditions
38266
38267
38268 this.adaptiveTimestepEnabled = averageNodeVelocity / nodeIndices.length < velocityAdaptiveThreshold;
38269 this.stabilized = maxNodeVelocity < this.options.minVelocity;
38270 }
38271 /**
38272 * Calculate new velocity for a coordinate direction
38273 *
38274 * @param {number} v velocity for current coordinate
38275 * @param {number} f regular force for current coordinate
38276 * @param {number} m mass of current node
38277 * @returns {number} new velocity for current coordinate
38278 * @private
38279 */
38280
38281 }, {
38282 key: "calculateComponentVelocity",
38283 value: function calculateComponentVelocity(v, f, m) {
38284 var df = this.modelOptions.damping * v; // damping force
38285
38286 var a = (f - df) / m; // acceleration
38287
38288 v += a * this.timestep; // Put a limit on the velocities if it is really high
38289
38290 var maxV = this.options.maxVelocity || 1e9;
38291
38292 if (Math.abs(v) > maxV) {
38293 v = v > 0 ? maxV : -maxV;
38294 }
38295
38296 return v;
38297 }
38298 /**
38299 * Perform the actual step
38300 *
38301 * @param {Node.id} nodeId
38302 * @returns {number} the new velocity of given node
38303 * @private
38304 */
38305
38306 }, {
38307 key: "_performStep",
38308 value: function _performStep(nodeId) {
38309 var node = this.body.nodes[nodeId];
38310 var force = this.physicsBody.forces[nodeId];
38311 var velocity = this.physicsBody.velocities[nodeId]; // store the state so we can revert
38312
38313 this.previousStates[nodeId] = {
38314 x: node.x,
38315 y: node.y,
38316 vx: velocity.x,
38317 vy: velocity.y
38318 };
38319
38320 if (node.options.fixed.x === false) {
38321 velocity.x = this.calculateComponentVelocity(velocity.x, force.x, node.options.mass);
38322 node.x += velocity.x * this.timestep;
38323 } else {
38324 force.x = 0;
38325 velocity.x = 0;
38326 }
38327
38328 if (node.options.fixed.y === false) {
38329 velocity.y = this.calculateComponentVelocity(velocity.y, force.y, node.options.mass);
38330 node.y += velocity.y * this.timestep;
38331 } else {
38332 force.y = 0;
38333 velocity.y = 0;
38334 }
38335
38336 var totalVelocity = Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(velocity.y, 2));
38337 return totalVelocity;
38338 }
38339 /**
38340 * When initializing and stabilizing, we can freeze nodes with a predefined position.
38341 * This greatly speeds up stabilization because only the supportnodes for the smoothCurves have to settle.
38342 *
38343 * @private
38344 */
38345
38346 }, {
38347 key: "_freezeNodes",
38348 value: function _freezeNodes() {
38349 var nodes = this.body.nodes;
38350
38351 for (var id in nodes) {
38352 if (nodes.hasOwnProperty(id)) {
38353 if (nodes[id].x && nodes[id].y) {
38354 var fixed = nodes[id].options.fixed;
38355 this.freezeCache[id] = {
38356 x: fixed.x,
38357 y: fixed.y
38358 };
38359 fixed.x = true;
38360 fixed.y = true;
38361 }
38362 }
38363 }
38364 }
38365 /**
38366 * Unfreezes the nodes that have been frozen by _freezeDefinedNodes.
38367 *
38368 * @private
38369 */
38370
38371 }, {
38372 key: "_restoreFrozenNodes",
38373 value: function _restoreFrozenNodes() {
38374 var nodes = this.body.nodes;
38375
38376 for (var id in nodes) {
38377 if (nodes.hasOwnProperty(id)) {
38378 if (this.freezeCache[id] !== undefined) {
38379 nodes[id].options.fixed.x = this.freezeCache[id].x;
38380 nodes[id].options.fixed.y = this.freezeCache[id].y;
38381 }
38382 }
38383 }
38384
38385 this.freezeCache = {};
38386 }
38387 /**
38388 * Find a stable position for all nodes
38389 *
38390 * @param {number} [iterations=this.options.stabilization.iterations]
38391 */
38392
38393 }, {
38394 key: "stabilize",
38395 value: function stabilize() {
38396 var _this3 = this;
38397
38398 var iterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.stabilization.iterations;
38399
38400 if (typeof iterations !== 'number') {
38401 iterations = this.options.stabilization.iterations;
38402 console.log('The stabilize method needs a numeric amount of iterations. Switching to default: ', iterations);
38403 }
38404
38405 if (this.physicsBody.physicsNodeIndices.length === 0) {
38406 this.ready = true;
38407 return;
38408 } // enable adaptive timesteps
38409
38410
38411 this.adaptiveTimestep = this.options.adaptiveTimestep; // this sets the width of all nodes initially which could be required for the avoidOverlap
38412
38413 this.body.emitter.emit("_resizeNodes");
38414 this.stopSimulation(); // stop the render loop
38415
38416 this.stabilized = false; // block redraw requests
38417
38418 this.body.emitter.emit('_blockRedraw');
38419 this.targetIterations = iterations; // start the stabilization
38420
38421 if (this.options.stabilization.onlyDynamicEdges === true) {
38422 this._freezeNodes();
38423 }
38424
38425 this.stabilizationIterations = 0;
38426 setTimeout(function () {
38427 return _this3._stabilizationBatch();
38428 }, 0);
38429 }
38430 /**
38431 * If not already stabilizing, start it and emit a start event.
38432 *
38433 * @returns {boolean} true if stabilization started with this call
38434 * @private
38435 */
38436
38437 }, {
38438 key: "_startStabilizing",
38439 value: function _startStabilizing() {
38440 if (this.startedStabilization === true) return false;
38441 this.body.emitter.emit('startStabilizing');
38442 this.startedStabilization = true;
38443 return true;
38444 }
38445 /**
38446 * One batch of stabilization
38447 * @private
38448 */
38449
38450 }, {
38451 key: "_stabilizationBatch",
38452 value: function _stabilizationBatch() {
38453 var _this4 = this;
38454
38455 var running = function running() {
38456 return _this4.stabilized === false && _this4.stabilizationIterations < _this4.targetIterations;
38457 };
38458
38459 var sendProgress = function sendProgress() {
38460 _this4.body.emitter.emit('stabilizationProgress', {
38461 iterations: _this4.stabilizationIterations,
38462 total: _this4.targetIterations
38463 });
38464 };
38465
38466 if (this._startStabilizing()) {
38467 sendProgress(); // Ensure that there is at least one start event.
38468 }
38469
38470 var count = 0;
38471
38472 while (running() && count < this.options.stabilization.updateInterval) {
38473 this.physicsTick();
38474 count++;
38475 }
38476
38477 sendProgress();
38478
38479 if (running()) {
38480 setTimeout(this._stabilizationBatch.bind(this), 0);
38481 } else {
38482 this._finalizeStabilization();
38483 }
38484 }
38485 /**
38486 * Wrap up the stabilization, fit and emit the events.
38487 * @private
38488 */
38489
38490 }, {
38491 key: "_finalizeStabilization",
38492 value: function _finalizeStabilization() {
38493 this.body.emitter.emit('_allowRedraw');
38494
38495 if (this.options.stabilization.fit === true) {
38496 this.body.emitter.emit('fit');
38497 }
38498
38499 if (this.options.stabilization.onlyDynamicEdges === true) {
38500 this._restoreFrozenNodes();
38501 }
38502
38503 this.body.emitter.emit('stabilizationIterationsDone');
38504 this.body.emitter.emit('_requestRedraw');
38505
38506 if (this.stabilized === true) {
38507 this._emitStabilized();
38508 } else {
38509 this.startSimulation();
38510 }
38511
38512 this.ready = true;
38513 } //--------------------------- DEBUGGING BELOW ---------------------------//
38514
38515 /**
38516 * Debug function that display arrows for the forces currently active in the network.
38517 *
38518 * Use this when debugging only.
38519 *
38520 * @param {CanvasRenderingContext2D} ctx
38521 * @private
38522 */
38523
38524 }, {
38525 key: "_drawForces",
38526 value: function _drawForces(ctx) {
38527 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
38528 var index = this.physicsBody.physicsNodeIndices[i];
38529 var node = this.body.nodes[index];
38530 var force = this.physicsBody.forces[index];
38531 var factor = 20;
38532 var colorFactor = 0.03;
38533 var forceSize = Math.sqrt(Math.pow(force.x, 2) + Math.pow(force.x, 2));
38534 var size = Math.min(Math.max(5, forceSize), 15);
38535 var arrowSize = 3 * size;
38536 var color = HSVToHex((180 - Math.min(1, Math.max(0, colorFactor * forceSize)) * 180) / 360, 1, 1);
38537 var point = {
38538 x: node.x + factor * force.x,
38539 y: node.y + factor * force.y
38540 };
38541 ctx.lineWidth = size;
38542 ctx.strokeStyle = color;
38543 ctx.beginPath();
38544 ctx.moveTo(node.x, node.y);
38545 ctx.lineTo(point.x, point.y);
38546 ctx.stroke();
38547 var angle = Math.atan2(force.y, force.x);
38548 ctx.fillStyle = color;
38549 EndPoints.draw(ctx, {
38550 type: 'arrow',
38551 point: point,
38552 angle: angle,
38553 length: arrowSize
38554 });
38555 ctx.fill();
38556 }
38557 }
38558 }]);
38559
38560 return PhysicsEngine;
38561 }();
38562
38563 var nativeReverse = [].reverse;
38564 var test$2 = [1, 2]; // `Array.prototype.reverse` method
38565 // https://tc39.github.io/ecma262/#sec-array.prototype.reverse
38566 // fix for Safari 12.0 bug
38567 // https://bugs.webkit.org/show_bug.cgi?id=188794
38568
38569 _export({
38570 target: 'Array',
38571 proto: true,
38572 forced: String(test$2) === String(test$2.reverse())
38573 }, {
38574 reverse: function reverse() {
38575 if (isArray(this)) this.length = this.length;
38576 return nativeReverse.call(this);
38577 }
38578 });
38579
38580 /**
38581 * Utility Class
38582 */
38583
38584 var NetworkUtil =
38585 /*#__PURE__*/
38586 function () {
38587 /**
38588 * @ignore
38589 */
38590 function NetworkUtil() {
38591 _classCallCheck(this, NetworkUtil);
38592 }
38593 /**
38594 * Find the center position of the network considering the bounding boxes
38595 *
38596 * @param {Array.<Node>} allNodes
38597 * @param {Array.<Node>} [specificNodes=[]]
38598 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
38599 * @static
38600 */
38601
38602
38603 _createClass(NetworkUtil, null, [{
38604 key: "getRange",
38605 value: function getRange(allNodes) {
38606 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
38607 var minY = 1e9,
38608 maxY = -1e9,
38609 minX = 1e9,
38610 maxX = -1e9,
38611 node;
38612
38613 if (specificNodes.length > 0) {
38614 for (var i = 0; i < specificNodes.length; i++) {
38615 node = allNodes[specificNodes[i]];
38616
38617 if (minX > node.shape.boundingBox.left) {
38618 minX = node.shape.boundingBox.left;
38619 }
38620
38621 if (maxX < node.shape.boundingBox.right) {
38622 maxX = node.shape.boundingBox.right;
38623 }
38624
38625 if (minY > node.shape.boundingBox.top) {
38626 minY = node.shape.boundingBox.top;
38627 } // top is negative, bottom is positive
38628
38629
38630 if (maxY < node.shape.boundingBox.bottom) {
38631 maxY = node.shape.boundingBox.bottom;
38632 } // top is negative, bottom is positive
38633
38634 }
38635 }
38636
38637 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
38638 minY = 0, maxY = 0, minX = 0, maxX = 0;
38639 }
38640
38641 return {
38642 minX: minX,
38643 maxX: maxX,
38644 minY: minY,
38645 maxY: maxY
38646 };
38647 }
38648 /**
38649 * Find the center position of the network
38650 *
38651 * @param {Array.<Node>} allNodes
38652 * @param {Array.<Node>} [specificNodes=[]]
38653 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
38654 * @static
38655 */
38656
38657 }, {
38658 key: "getRangeCore",
38659 value: function getRangeCore(allNodes) {
38660 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
38661 var minY = 1e9,
38662 maxY = -1e9,
38663 minX = 1e9,
38664 maxX = -1e9,
38665 node;
38666
38667 if (specificNodes.length > 0) {
38668 for (var i = 0; i < specificNodes.length; i++) {
38669 node = allNodes[specificNodes[i]];
38670
38671 if (minX > node.x) {
38672 minX = node.x;
38673 }
38674
38675 if (maxX < node.x) {
38676 maxX = node.x;
38677 }
38678
38679 if (minY > node.y) {
38680 minY = node.y;
38681 } // top is negative, bottom is positive
38682
38683
38684 if (maxY < node.y) {
38685 maxY = node.y;
38686 } // top is negative, bottom is positive
38687
38688 }
38689 }
38690
38691 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
38692 minY = 0, maxY = 0, minX = 0, maxX = 0;
38693 }
38694
38695 return {
38696 minX: minX,
38697 maxX: maxX,
38698 minY: minY,
38699 maxY: maxY
38700 };
38701 }
38702 /**
38703 * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY};
38704 * @returns {{x: number, y: number}}
38705 * @static
38706 */
38707
38708 }, {
38709 key: "findCenter",
38710 value: function findCenter(range) {
38711 return {
38712 x: 0.5 * (range.maxX + range.minX),
38713 y: 0.5 * (range.maxY + range.minY)
38714 };
38715 }
38716 /**
38717 * This returns a clone of the options or options of the edge or node to be used for construction of new edges or check functions for new nodes.
38718 * @param {vis.Item} item
38719 * @param {'node'|undefined} type
38720 * @returns {{}}
38721 * @static
38722 */
38723
38724 }, {
38725 key: "cloneOptions",
38726 value: function cloneOptions(item, type) {
38727 var clonedOptions = {};
38728
38729 if (type === undefined || type === 'node') {
38730 deepExtend(clonedOptions, item.options, true);
38731 clonedOptions.x = item.x;
38732 clonedOptions.y = item.y;
38733 clonedOptions.amountOfConnections = item.edges.length;
38734 } else {
38735 deepExtend(clonedOptions, item.options, true);
38736 }
38737
38738 return clonedOptions;
38739 }
38740 }]);
38741
38742 return NetworkUtil;
38743 }();
38744
38745 /**
38746 * A Cluster is a special Node that allows a group of Nodes positioned closely together
38747 * to be represented by a single Cluster Node.
38748 *
38749 * @extends Node
38750 */
38751
38752 var Cluster =
38753 /*#__PURE__*/
38754 function (_Node) {
38755 _inherits(Cluster, _Node);
38756
38757 /**
38758 * @param {Object} options
38759 * @param {Object} body
38760 * @param {Array.<HTMLImageElement>}imagelist
38761 * @param {Array} grouplist
38762 * @param {Object} globalOptions
38763 * @param {Object} defaultOptions Global default options for nodes
38764 */
38765 function Cluster(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
38766 var _this;
38767
38768 _classCallCheck(this, Cluster);
38769
38770 _this = _possibleConstructorReturn(this, _getPrototypeOf(Cluster).call(this, options, body, imagelist, grouplist, globalOptions, defaultOptions));
38771 _this.isCluster = true;
38772 _this.containedNodes = {};
38773 _this.containedEdges = {};
38774 return _this;
38775 }
38776 /**
38777 * Transfer child cluster data to current and disconnect the child cluster.
38778 *
38779 * Please consult the header comment in 'Clustering.js' for the fields set here.
38780 *
38781 * @param {string|number} childClusterId id of child cluster to open
38782 */
38783
38784
38785 _createClass(Cluster, [{
38786 key: "_openChildCluster",
38787 value: function _openChildCluster(childClusterId) {
38788 var _this2 = this;
38789
38790 var childCluster = this.body.nodes[childClusterId];
38791
38792 if (this.containedNodes[childClusterId] === undefined) {
38793 throw new Error('node with id: ' + childClusterId + ' not in current cluster');
38794 }
38795
38796 if (!childCluster.isCluster) {
38797 throw new Error('node with id: ' + childClusterId + ' is not a cluster');
38798 } // Disconnect child cluster from current cluster
38799
38800
38801 delete this.containedNodes[childClusterId];
38802 forEach(childCluster.edges, function (edge) {
38803 delete _this2.containedEdges[edge.id];
38804 }); // Transfer nodes and edges
38805
38806 forEach(childCluster.containedNodes, function (node, nodeId) {
38807 _this2.containedNodes[nodeId] = node;
38808 });
38809 childCluster.containedNodes = {};
38810 forEach(childCluster.containedEdges, function (edge, edgeId) {
38811 _this2.containedEdges[edgeId] = edge;
38812 });
38813 childCluster.containedEdges = {}; // Transfer edges within cluster edges which are clustered
38814
38815 forEach(childCluster.edges, function (clusterEdge) {
38816 forEach(_this2.edges, function (parentClusterEdge) {
38817 // Assumption: a clustered edge can only be present in a single clustering edge
38818 // Not tested here
38819 var index = parentClusterEdge.clusteringEdgeReplacingIds.indexOf(clusterEdge.id);
38820 if (index === -1) return;
38821 forEach(clusterEdge.clusteringEdgeReplacingIds, function (srcId) {
38822 parentClusterEdge.clusteringEdgeReplacingIds.push(srcId); // Maintain correct bookkeeping for transferred edge
38823
38824 _this2.body.edges[srcId].edgeReplacedById = parentClusterEdge.id;
38825 }); // Remove cluster edge from parent cluster edge
38826
38827 parentClusterEdge.clusteringEdgeReplacingIds.splice(index, 1);
38828 });
38829 });
38830 childCluster.edges = [];
38831 }
38832 }]);
38833
38834 return Cluster;
38835 }(Node);
38836
38837 /**
38838 * The clustering engine
38839 */
38840
38841 var ClusterEngine =
38842 /*#__PURE__*/
38843 function () {
38844 /**
38845 * @param {Object} body
38846 */
38847 function ClusterEngine(body) {
38848 var _this = this;
38849
38850 _classCallCheck(this, ClusterEngine);
38851
38852 this.body = body;
38853 this.clusteredNodes = {}; // key: node id, value: { clusterId: <id of cluster>, node: <node instance>}
38854
38855 this.clusteredEdges = {}; // key: edge id, value: restore information for given edge
38856
38857 this.options = {};
38858 this.defaultOptions = {};
38859 extend(this.options, this.defaultOptions);
38860 this.body.emitter.on('_resetData', function () {
38861 _this.clusteredNodes = {};
38862 _this.clusteredEdges = {};
38863 });
38864 }
38865 /**
38866 *
38867 * @param {number} hubsize
38868 * @param {Object} options
38869 */
38870
38871
38872 _createClass(ClusterEngine, [{
38873 key: "clusterByHubsize",
38874 value: function clusterByHubsize(hubsize, options) {
38875 if (hubsize === undefined) {
38876 hubsize = this._getHubSize();
38877 } else if (_typeof$1(hubsize) === "object") {
38878 options = this._checkOptions(hubsize);
38879 hubsize = this._getHubSize();
38880 }
38881
38882 var nodesToCluster = [];
38883
38884 for (var i = 0; i < this.body.nodeIndices.length; i++) {
38885 var node = this.body.nodes[this.body.nodeIndices[i]];
38886
38887 if (node.edges.length >= hubsize) {
38888 nodesToCluster.push(node.id);
38889 }
38890 }
38891
38892 for (var _i = 0; _i < nodesToCluster.length; _i++) {
38893 this.clusterByConnection(nodesToCluster[_i], options, true);
38894 }
38895
38896 this.body.emitter.emit('_dataChanged');
38897 }
38898 /**
38899 * loop over all nodes, check if they adhere to the condition and cluster if needed.
38900 * @param {Object} options
38901 * @param {boolean} [refreshData=true]
38902 */
38903
38904 }, {
38905 key: "cluster",
38906 value: function cluster() {
38907 var _this2 = this;
38908
38909 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
38910 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
38911
38912 if (options.joinCondition === undefined) {
38913 throw new Error("Cannot call clusterByNodeData without a joinCondition function in the options.");
38914 } // check if the options object is fine, append if needed
38915
38916
38917 options = this._checkOptions(options);
38918 var childNodesObj = {};
38919 var childEdgesObj = {}; // collect the nodes that will be in the cluster
38920
38921 forEach(this.body.nodes, function (node, nodeId) {
38922 if (node.options && options.joinCondition(node.options) === true) {
38923 childNodesObj[nodeId] = node; // collect the edges that will be in the cluster
38924
38925 forEach(node.edges, function (edge) {
38926 if (_this2.clusteredEdges[edge.id] === undefined) {
38927 childEdgesObj[edge.id] = edge;
38928 }
38929 });
38930 }
38931 });
38932
38933 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
38934 }
38935 /**
38936 * Cluster all nodes in the network that have only X edges
38937 * @param {number} edgeCount
38938 * @param {Object} options
38939 * @param {boolean} [refreshData=true]
38940 */
38941
38942 }, {
38943 key: "clusterByEdgeCount",
38944 value: function clusterByEdgeCount(edgeCount, options) {
38945 var _this3 = this;
38946
38947 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
38948 options = this._checkOptions(options);
38949 var clusters = [];
38950 var usedNodes = {};
38951 var edge, edges, relevantEdgeCount; // collect the nodes that will be in the cluster
38952
38953 var _loop = function _loop(i) {
38954 var childNodesObj = {};
38955 var childEdgesObj = {};
38956 var nodeId = _this3.body.nodeIndices[i];
38957 var node = _this3.body.nodes[nodeId]; // if this node is already used in another cluster this session, we do not have to re-evaluate it.
38958
38959 if (usedNodes[nodeId] === undefined) {
38960 relevantEdgeCount = 0;
38961 edges = [];
38962
38963 for (var j = 0; j < node.edges.length; j++) {
38964 edge = node.edges[j];
38965
38966 if (_this3.clusteredEdges[edge.id] === undefined) {
38967 if (edge.toId !== edge.fromId) {
38968 relevantEdgeCount++;
38969 }
38970
38971 edges.push(edge);
38972 }
38973 } // this node qualifies, we collect its neighbours to start the clustering process.
38974
38975
38976 if (relevantEdgeCount === edgeCount) {
38977 checkJoinCondition = function checkJoinCondition(node) {
38978 if (options.joinCondition === undefined || options.joinCondition === null) {
38979 return true;
38980 }
38981
38982 var clonedOptions = NetworkUtil.cloneOptions(node);
38983 return options.joinCondition(clonedOptions);
38984 };
38985
38986 var gatheringSuccessful = true;
38987
38988 for (var _j = 0; _j < edges.length; _j++) {
38989 edge = edges[_j];
38990
38991 var childNodeId = _this3._getConnectedId(edge, nodeId); // add the nodes to the list by the join condition.
38992
38993
38994 if (checkJoinCondition(node)) {
38995 childEdgesObj[edge.id] = edge;
38996 childNodesObj[nodeId] = node;
38997 childNodesObj[childNodeId] = _this3.body.nodes[childNodeId];
38998 usedNodes[nodeId] = true;
38999 } else {
39000 // this node does not qualify after all.
39001 gatheringSuccessful = false;
39002 break;
39003 }
39004 } // add to the cluster queue
39005
39006
39007 if (Object.keys(childNodesObj).length > 0 && Object.keys(childEdgesObj).length > 0 && gatheringSuccessful === true) {
39008 /**
39009 * Search for cluster data that contains any of the node id's
39010 * @returns {Boolean} true if no joinCondition, otherwise return value of joinCondition
39011 */
39012 findClusterData = function findClusterData() {
39013 for (var n = 0; n < clusters.length; ++n) {
39014 // Search for a cluster containing any of the node id's
39015 for (var m in childNodesObj) {
39016 if (clusters[n].nodes[m] !== undefined) {
39017 return clusters[n];
39018 }
39019 }
39020 }
39021
39022 return undefined;
39023 }; // If any of the found nodes is part of a cluster found in this method,
39024 // add the current values to that cluster
39025
39026
39027 foundCluster = findClusterData();
39028
39029 if (foundCluster !== undefined) {
39030 // Add nodes to found cluster if not present
39031 for (var m in childNodesObj) {
39032 if (foundCluster.nodes[m] === undefined) {
39033 foundCluster.nodes[m] = childNodesObj[m];
39034 }
39035 } // Add edges to found cluster, if not present
39036
39037
39038 for (var _m in childEdgesObj) {
39039 if (foundCluster.edges[_m] === undefined) {
39040 foundCluster.edges[_m] = childEdgesObj[_m];
39041 }
39042 }
39043 } else {
39044 // Create a new cluster group
39045 clusters.push({
39046 nodes: childNodesObj,
39047 edges: childEdgesObj
39048 });
39049 }
39050 }
39051 }
39052 }
39053 };
39054
39055 for (var i = 0; i < this.body.nodeIndices.length; i++) {
39056 var checkJoinCondition;
39057 var findClusterData;
39058 var foundCluster;
39059
39060 _loop(i);
39061 }
39062
39063 for (var _i2 = 0; _i2 < clusters.length; _i2++) {
39064 this._cluster(clusters[_i2].nodes, clusters[_i2].edges, options, false);
39065 }
39066
39067 if (refreshData === true) {
39068 this.body.emitter.emit('_dataChanged');
39069 }
39070 }
39071 /**
39072 * Cluster all nodes in the network that have only 1 edge
39073 * @param {Object} options
39074 * @param {boolean} [refreshData=true]
39075 */
39076
39077 }, {
39078 key: "clusterOutliers",
39079 value: function clusterOutliers(options) {
39080 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
39081 this.clusterByEdgeCount(1, options, refreshData);
39082 }
39083 /**
39084 * Cluster all nodes in the network that have only 2 edge
39085 * @param {Object} options
39086 * @param {boolean} [refreshData=true]
39087 */
39088
39089 }, {
39090 key: "clusterBridges",
39091 value: function clusterBridges(options) {
39092 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
39093 this.clusterByEdgeCount(2, options, refreshData);
39094 }
39095 /**
39096 * suck all connected nodes of a node into the node.
39097 * @param {Node.id} nodeId
39098 * @param {Object} options
39099 * @param {boolean} [refreshData=true]
39100 */
39101
39102 }, {
39103 key: "clusterByConnection",
39104 value: function clusterByConnection(nodeId, options) {
39105 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
39106
39107 // kill conditions
39108 if (nodeId === undefined) {
39109 throw new Error("No nodeId supplied to clusterByConnection!");
39110 }
39111
39112 if (this.body.nodes[nodeId] === undefined) {
39113 throw new Error("The nodeId given to clusterByConnection does not exist!");
39114 }
39115
39116 var node = this.body.nodes[nodeId];
39117 options = this._checkOptions(options, node);
39118
39119 if (options.clusterNodeProperties.x === undefined) {
39120 options.clusterNodeProperties.x = node.x;
39121 }
39122
39123 if (options.clusterNodeProperties.y === undefined) {
39124 options.clusterNodeProperties.y = node.y;
39125 }
39126
39127 if (options.clusterNodeProperties.fixed === undefined) {
39128 options.clusterNodeProperties.fixed = {};
39129 options.clusterNodeProperties.fixed.x = node.options.fixed.x;
39130 options.clusterNodeProperties.fixed.y = node.options.fixed.y;
39131 }
39132
39133 var childNodesObj = {};
39134 var childEdgesObj = {};
39135 var parentNodeId = node.id;
39136 var parentClonedOptions = NetworkUtil.cloneOptions(node);
39137 childNodesObj[parentNodeId] = node; // collect the nodes that will be in the cluster
39138
39139 for (var i = 0; i < node.edges.length; i++) {
39140 var edge = node.edges[i];
39141
39142 if (this.clusteredEdges[edge.id] === undefined) {
39143 var childNodeId = this._getConnectedId(edge, parentNodeId); // if the child node is not in a cluster
39144
39145
39146 if (this.clusteredNodes[childNodeId] === undefined) {
39147 if (childNodeId !== parentNodeId) {
39148 if (options.joinCondition === undefined) {
39149 childEdgesObj[edge.id] = edge;
39150 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
39151 } else {
39152 // clone the options and insert some additional parameters that could be interesting.
39153 var childClonedOptions = NetworkUtil.cloneOptions(this.body.nodes[childNodeId]);
39154
39155 if (options.joinCondition(parentClonedOptions, childClonedOptions) === true) {
39156 childEdgesObj[edge.id] = edge;
39157 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
39158 }
39159 }
39160 } else {
39161 // swallow the edge if it is self-referencing.
39162 childEdgesObj[edge.id] = edge;
39163 }
39164 }
39165 }
39166 }
39167
39168 var childNodeIDs = Object.keys(childNodesObj).map(function (childNode) {
39169 return childNodesObj[childNode].id;
39170 });
39171
39172 for (childNode in childNodesObj) {
39173 if (!childNodesObj.hasOwnProperty(childNode)) continue;
39174 var childNode = childNodesObj[childNode];
39175
39176 for (var y = 0; y < childNode.edges.length; y++) {
39177 var childEdge = childNode.edges[y];
39178
39179 if (childNodeIDs.indexOf(this._getConnectedId(childEdge, childNode.id)) > -1) {
39180 childEdgesObj[childEdge.id] = childEdge;
39181 }
39182 }
39183 }
39184
39185 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
39186 }
39187 /**
39188 * This function creates the edges that will be attached to the cluster
39189 * It looks for edges that are connected to the nodes from the "outside' of the cluster.
39190 *
39191 * @param {{Node.id: vis.Node}} childNodesObj
39192 * @param {{vis.Edge.id: vis.Edge}} childEdgesObj
39193 * @param {Object} clusterNodeProperties
39194 * @param {Object} clusterEdgeProperties
39195 * @private
39196 */
39197
39198 }, {
39199 key: "_createClusterEdges",
39200 value: function _createClusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, clusterEdgeProperties) {
39201 var edge, childNodeId, childNode, toId, fromId, otherNodeId; // loop over all child nodes and their edges to find edges going out of the cluster
39202 // these edges will be replaced by clusterEdges.
39203
39204 var childKeys = Object.keys(childNodesObj);
39205 var createEdges = [];
39206
39207 for (var i = 0; i < childKeys.length; i++) {
39208 childNodeId = childKeys[i];
39209 childNode = childNodesObj[childNodeId]; // construct new edges from the cluster to others
39210
39211 for (var j = 0; j < childNode.edges.length; j++) {
39212 edge = childNode.edges[j]; // we only handle edges that are visible to the system, not the disabled ones from the clustering process.
39213
39214 if (this.clusteredEdges[edge.id] === undefined) {
39215 // self-referencing edges will be added to the "hidden" list
39216 if (edge.toId == edge.fromId) {
39217 childEdgesObj[edge.id] = edge;
39218 } else {
39219 // set up the from and to.
39220 if (edge.toId == childNodeId) {
39221 // this is a double equals because ints and strings can be interchanged here.
39222 toId = clusterNodeProperties.id;
39223 fromId = edge.fromId;
39224 otherNodeId = fromId;
39225 } else {
39226 toId = edge.toId;
39227 fromId = clusterNodeProperties.id;
39228 otherNodeId = toId;
39229 }
39230 } // Only edges from the cluster outwards are being replaced.
39231
39232
39233 if (childNodesObj[otherNodeId] === undefined) {
39234 createEdges.push({
39235 edge: edge,
39236 fromId: fromId,
39237 toId: toId
39238 });
39239 }
39240 }
39241 }
39242 } //
39243 // Here we actually create the replacement edges.
39244 //
39245 // We could not do this in the loop above as the creation process
39246 // would add an edge to the edges array we are iterating over.
39247 //
39248 // NOTE: a clustered edge can have multiple base edges!
39249 //
39250
39251
39252 var newEdges = [];
39253 /**
39254 * Find a cluster edge which matches the given created edge.
39255 * @param {vis.Edge} createdEdge
39256 * @returns {vis.Edge}
39257 */
39258
39259 var getNewEdge = function getNewEdge(createdEdge) {
39260 for (var _j2 = 0; _j2 < newEdges.length; _j2++) {
39261 var newEdge = newEdges[_j2]; // We replace both to and from edges with a single cluster edge
39262
39263 var matchToDirection = createdEdge.fromId === newEdge.fromId && createdEdge.toId === newEdge.toId;
39264 var matchFromDirection = createdEdge.fromId === newEdge.toId && createdEdge.toId === newEdge.fromId;
39265
39266 if (matchToDirection || matchFromDirection) {
39267 return newEdge;
39268 }
39269 }
39270
39271 return null;
39272 };
39273
39274 for (var _j3 = 0; _j3 < createEdges.length; _j3++) {
39275 var createdEdge = createEdges[_j3];
39276 var _edge = createdEdge.edge;
39277 var newEdge = getNewEdge(createdEdge);
39278
39279 if (newEdge === null) {
39280 // Create a clustered edge for this connection
39281 newEdge = this._createClusteredEdge(createdEdge.fromId, createdEdge.toId, _edge, clusterEdgeProperties);
39282 newEdges.push(newEdge);
39283 } else {
39284 newEdge.clusteringEdgeReplacingIds.push(_edge.id);
39285 } // also reference the new edge in the old edge
39286
39287
39288 this.body.edges[_edge.id].edgeReplacedById = newEdge.id; // hide the replaced edge
39289
39290 this._backupEdgeOptions(_edge);
39291
39292 _edge.setOptions({
39293 physics: false
39294 });
39295 }
39296 }
39297 /**
39298 * This function checks the options that can be supplied to the different cluster functions
39299 * for certain fields and inserts defaults if needed
39300 * @param {Object} options
39301 * @returns {*}
39302 * @private
39303 */
39304
39305 }, {
39306 key: "_checkOptions",
39307 value: function _checkOptions() {
39308 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
39309
39310 if (options.clusterEdgeProperties === undefined) {
39311 options.clusterEdgeProperties = {};
39312 }
39313
39314 if (options.clusterNodeProperties === undefined) {
39315 options.clusterNodeProperties = {};
39316 }
39317
39318 return options;
39319 }
39320 /**
39321 *
39322 * @param {Object} childNodesObj | object with node objects, id as keys, same as childNodes except it also contains a source node
39323 * @param {Object} childEdgesObj | object with edge objects, id as keys
39324 * @param {Array} options | object with {clusterNodeProperties, clusterEdgeProperties, processProperties}
39325 * @param {boolean} refreshData | when true, do not wrap up
39326 * @private
39327 */
39328
39329 }, {
39330 key: "_cluster",
39331 value: function _cluster(childNodesObj, childEdgesObj, options) {
39332 var refreshData = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
39333 // Remove nodes which are already clustered
39334 var tmpNodesToRemove = [];
39335
39336 for (var nodeId in childNodesObj) {
39337 if (childNodesObj.hasOwnProperty(nodeId)) {
39338 if (this.clusteredNodes[nodeId] !== undefined) {
39339 tmpNodesToRemove.push(nodeId);
39340 }
39341 }
39342 }
39343
39344 for (var n = 0; n < tmpNodesToRemove.length; ++n) {
39345 delete childNodesObj[tmpNodesToRemove[n]];
39346 } // kill condition: no nodes don't bother
39347
39348
39349 if (Object.keys(childNodesObj).length == 0) {
39350 return;
39351 } // allow clusters of 1 if options allow
39352
39353
39354 if (Object.keys(childNodesObj).length == 1 && options.clusterNodeProperties.allowSingleNodeCluster != true) {
39355 return;
39356 }
39357
39358 var clusterNodeProperties = deepExtend({}, options.clusterNodeProperties); // construct the clusterNodeProperties
39359
39360 if (options.processProperties !== undefined) {
39361 // get the childNode options
39362 var childNodesOptions = [];
39363
39364 for (var _nodeId in childNodesObj) {
39365 if (childNodesObj.hasOwnProperty(_nodeId)) {
39366 var clonedOptions = NetworkUtil.cloneOptions(childNodesObj[_nodeId]);
39367 childNodesOptions.push(clonedOptions);
39368 }
39369 } // get cluster properties based on childNodes
39370
39371
39372 var childEdgesOptions = [];
39373
39374 for (var edgeId in childEdgesObj) {
39375 if (childEdgesObj.hasOwnProperty(edgeId)) {
39376 // these cluster edges will be removed on creation of the cluster.
39377 if (edgeId.substr(0, 12) !== "clusterEdge:") {
39378 var _clonedOptions = NetworkUtil.cloneOptions(childEdgesObj[edgeId], 'edge');
39379
39380 childEdgesOptions.push(_clonedOptions);
39381 }
39382 }
39383 }
39384
39385 clusterNodeProperties = options.processProperties(clusterNodeProperties, childNodesOptions, childEdgesOptions);
39386
39387 if (!clusterNodeProperties) {
39388 throw new Error("The processProperties function does not return properties!");
39389 }
39390 } // check if we have an unique id;
39391
39392
39393 if (clusterNodeProperties.id === undefined) {
39394 clusterNodeProperties.id = 'cluster:' + uuid4();
39395 }
39396
39397 var clusterId = clusterNodeProperties.id;
39398
39399 if (clusterNodeProperties.label === undefined) {
39400 clusterNodeProperties.label = 'cluster';
39401 } // give the clusterNode a position if it does not have one.
39402
39403
39404 var pos = undefined;
39405
39406 if (clusterNodeProperties.x === undefined) {
39407 pos = this._getClusterPosition(childNodesObj);
39408 clusterNodeProperties.x = pos.x;
39409 }
39410
39411 if (clusterNodeProperties.y === undefined) {
39412 if (pos === undefined) {
39413 pos = this._getClusterPosition(childNodesObj);
39414 }
39415
39416 clusterNodeProperties.y = pos.y;
39417 } // force the ID to remain the same
39418
39419
39420 clusterNodeProperties.id = clusterId; // create the cluster Node
39421 // Note that allowSingleNodeCluster, if present, is stored in the options as well
39422
39423 var clusterNode = this.body.functions.createNode(clusterNodeProperties, Cluster);
39424 clusterNode.containedNodes = childNodesObj;
39425 clusterNode.containedEdges = childEdgesObj; // cache a copy from the cluster edge properties if we have to reconnect others later on
39426
39427 clusterNode.clusterEdgeProperties = options.clusterEdgeProperties; // finally put the cluster node into global
39428
39429 this.body.nodes[clusterNodeProperties.id] = clusterNode;
39430
39431 this._clusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, options.clusterEdgeProperties); // set ID to undefined so no duplicates arise
39432
39433
39434 clusterNodeProperties.id = undefined; // wrap up
39435
39436 if (refreshData === true) {
39437 this.body.emitter.emit('_dataChanged');
39438 }
39439 }
39440 /**
39441 *
39442 * @param {Edge} edge
39443 * @private
39444 */
39445
39446 }, {
39447 key: "_backupEdgeOptions",
39448 value: function _backupEdgeOptions(edge) {
39449 if (this.clusteredEdges[edge.id] === undefined) {
39450 this.clusteredEdges[edge.id] = {
39451 physics: edge.options.physics
39452 };
39453 }
39454 }
39455 /**
39456 *
39457 * @param {Edge} edge
39458 * @private
39459 */
39460
39461 }, {
39462 key: "_restoreEdge",
39463 value: function _restoreEdge(edge) {
39464 var originalOptions = this.clusteredEdges[edge.id];
39465
39466 if (originalOptions !== undefined) {
39467 edge.setOptions({
39468 physics: originalOptions.physics
39469 });
39470 delete this.clusteredEdges[edge.id];
39471 }
39472 }
39473 /**
39474 * Check if a node is a cluster.
39475 * @param {Node.id} nodeId
39476 * @returns {*}
39477 */
39478
39479 }, {
39480 key: "isCluster",
39481 value: function isCluster(nodeId) {
39482 if (this.body.nodes[nodeId] !== undefined) {
39483 return this.body.nodes[nodeId].isCluster === true;
39484 } else {
39485 console.log("Node does not exist.");
39486 return false;
39487 }
39488 }
39489 /**
39490 * get the position of the cluster node based on what's inside
39491 * @param {object} childNodesObj | object with node objects, id as keys
39492 * @returns {{x: number, y: number}}
39493 * @private
39494 */
39495
39496 }, {
39497 key: "_getClusterPosition",
39498 value: function _getClusterPosition(childNodesObj) {
39499 var childKeys = Object.keys(childNodesObj);
39500 var minX = childNodesObj[childKeys[0]].x;
39501 var maxX = childNodesObj[childKeys[0]].x;
39502 var minY = childNodesObj[childKeys[0]].y;
39503 var maxY = childNodesObj[childKeys[0]].y;
39504 var node;
39505
39506 for (var i = 1; i < childKeys.length; i++) {
39507 node = childNodesObj[childKeys[i]];
39508 minX = node.x < minX ? node.x : minX;
39509 maxX = node.x > maxX ? node.x : maxX;
39510 minY = node.y < minY ? node.y : minY;
39511 maxY = node.y > maxY ? node.y : maxY;
39512 }
39513
39514 return {
39515 x: 0.5 * (minX + maxX),
39516 y: 0.5 * (minY + maxY)
39517 };
39518 }
39519 /**
39520 * Open a cluster by calling this function.
39521 * @param {vis.Edge.id} clusterNodeId | the ID of the cluster node
39522 * @param {Object} options
39523 * @param {boolean} refreshData | wrap up afterwards if not true
39524 */
39525
39526 }, {
39527 key: "openCluster",
39528 value: function openCluster(clusterNodeId, options) {
39529 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
39530
39531 // kill conditions
39532 if (clusterNodeId === undefined) {
39533 throw new Error("No clusterNodeId supplied to openCluster.");
39534 }
39535
39536 var clusterNode = this.body.nodes[clusterNodeId];
39537
39538 if (clusterNode === undefined) {
39539 throw new Error("The clusterNodeId supplied to openCluster does not exist.");
39540 }
39541
39542 if (clusterNode.isCluster !== true || clusterNode.containedNodes === undefined || clusterNode.containedEdges === undefined) {
39543 throw new Error("The node:" + clusterNodeId + " is not a valid cluster.");
39544 } // Check if current cluster is clustered itself
39545
39546
39547 var stack = this.findNode(clusterNodeId);
39548 var parentIndex = stack.indexOf(clusterNodeId) - 1;
39549
39550 if (parentIndex >= 0) {
39551 // Current cluster is clustered; transfer contained nodes and edges to parent
39552 var parentClusterNodeId = stack[parentIndex];
39553 var parentClusterNode = this.body.nodes[parentClusterNodeId]; // clustering.clusteredNodes and clustering.clusteredEdges remain unchanged
39554
39555 parentClusterNode._openChildCluster(clusterNodeId); // All components of child cluster node have been transferred. It can die now.
39556
39557
39558 delete this.body.nodes[clusterNodeId];
39559
39560 if (refreshData === true) {
39561 this.body.emitter.emit('_dataChanged');
39562 }
39563
39564 return;
39565 } // main body
39566
39567
39568 var containedNodes = clusterNode.containedNodes;
39569 var containedEdges = clusterNode.containedEdges; // allow the user to position the nodes after release.
39570
39571 if (options !== undefined && options.releaseFunction !== undefined && typeof options.releaseFunction === 'function') {
39572 var positions = {};
39573 var clusterPosition = {
39574 x: clusterNode.x,
39575 y: clusterNode.y
39576 };
39577
39578 for (var nodeId in containedNodes) {
39579 if (containedNodes.hasOwnProperty(nodeId)) {
39580 var containedNode = this.body.nodes[nodeId];
39581 positions[nodeId] = {
39582 x: containedNode.x,
39583 y: containedNode.y
39584 };
39585 }
39586 }
39587
39588 var newPositions = options.releaseFunction(clusterPosition, positions);
39589
39590 for (var _nodeId2 in containedNodes) {
39591 if (containedNodes.hasOwnProperty(_nodeId2)) {
39592 var _containedNode = this.body.nodes[_nodeId2];
39593
39594 if (newPositions[_nodeId2] !== undefined) {
39595 _containedNode.x = newPositions[_nodeId2].x === undefined ? clusterNode.x : newPositions[_nodeId2].x;
39596 _containedNode.y = newPositions[_nodeId2].y === undefined ? clusterNode.y : newPositions[_nodeId2].y;
39597 }
39598 }
39599 }
39600 } else {
39601 // copy the position from the cluster
39602 forEach(containedNodes, function (containedNode) {
39603 // inherit position
39604 if (containedNode.options.fixed.x === false) {
39605 containedNode.x = clusterNode.x;
39606 }
39607
39608 if (containedNode.options.fixed.y === false) {
39609 containedNode.y = clusterNode.y;
39610 }
39611 });
39612 } // release nodes
39613
39614
39615 for (var _nodeId3 in containedNodes) {
39616 if (containedNodes.hasOwnProperty(_nodeId3)) {
39617 var _containedNode2 = this.body.nodes[_nodeId3]; // inherit speed
39618
39619 _containedNode2.vx = clusterNode.vx;
39620 _containedNode2.vy = clusterNode.vy;
39621
39622 _containedNode2.setOptions({
39623 physics: true
39624 });
39625
39626 delete this.clusteredNodes[_nodeId3];
39627 }
39628 } // copy the clusterNode edges because we cannot iterate over an object that we add or remove from.
39629
39630
39631 var edgesToBeDeleted = [];
39632
39633 for (var i = 0; i < clusterNode.edges.length; i++) {
39634 edgesToBeDeleted.push(clusterNode.edges[i]);
39635 } // actually handling the deleting.
39636
39637
39638 for (var _i3 = 0; _i3 < edgesToBeDeleted.length; _i3++) {
39639 var edge = edgesToBeDeleted[_i3];
39640
39641 var otherNodeId = this._getConnectedId(edge, clusterNodeId);
39642
39643 var otherNode = this.clusteredNodes[otherNodeId];
39644
39645 for (var j = 0; j < edge.clusteringEdgeReplacingIds.length; j++) {
39646 var transferId = edge.clusteringEdgeReplacingIds[j];
39647 var transferEdge = this.body.edges[transferId];
39648 if (transferEdge === undefined) continue; // if the other node is in another cluster, we transfer ownership of this edge to the other cluster
39649
39650 if (otherNode !== undefined) {
39651 // transfer ownership:
39652 var otherCluster = this.body.nodes[otherNode.clusterId];
39653 otherCluster.containedEdges[transferEdge.id] = transferEdge; // delete local reference
39654
39655 delete containedEdges[transferEdge.id]; // get to and from
39656
39657 var fromId = transferEdge.fromId;
39658 var toId = transferEdge.toId;
39659
39660 if (transferEdge.toId == otherNodeId) {
39661 toId = otherNode.clusterId;
39662 } else {
39663 fromId = otherNode.clusterId;
39664 } // create new cluster edge from the otherCluster
39665
39666
39667 this._createClusteredEdge(fromId, toId, transferEdge, otherCluster.clusterEdgeProperties, {
39668 hidden: false,
39669 physics: true
39670 });
39671 } else {
39672 this._restoreEdge(transferEdge);
39673 }
39674 }
39675
39676 edge.remove();
39677 } // handle the releasing of the edges
39678
39679
39680 for (var edgeId in containedEdges) {
39681 if (containedEdges.hasOwnProperty(edgeId)) {
39682 this._restoreEdge(containedEdges[edgeId]);
39683 }
39684 } // remove clusterNode
39685
39686
39687 delete this.body.nodes[clusterNodeId];
39688
39689 if (refreshData === true) {
39690 this.body.emitter.emit('_dataChanged');
39691 }
39692 }
39693 /**
39694 *
39695 * @param {Cluster.id} clusterId
39696 * @returns {Array.<Node.id>}
39697 */
39698
39699 }, {
39700 key: "getNodesInCluster",
39701 value: function getNodesInCluster(clusterId) {
39702 var nodesArray = [];
39703
39704 if (this.isCluster(clusterId) === true) {
39705 var containedNodes = this.body.nodes[clusterId].containedNodes;
39706
39707 for (var nodeId in containedNodes) {
39708 if (containedNodes.hasOwnProperty(nodeId)) {
39709 nodesArray.push(this.body.nodes[nodeId].id);
39710 }
39711 }
39712 }
39713
39714 return nodesArray;
39715 }
39716 /**
39717 * Get the stack clusterId's that a certain node resides in. cluster A -> cluster B -> cluster C -> node
39718 *
39719 * If a node can't be found in the chain, return an empty array.
39720 *
39721 * @param {string|number} nodeId
39722 * @returns {Array}
39723 */
39724
39725 }, {
39726 key: "findNode",
39727 value: function findNode(nodeId) {
39728 var stack = [];
39729 var max = 100;
39730 var counter = 0;
39731 var node;
39732
39733 while (this.clusteredNodes[nodeId] !== undefined && counter < max) {
39734 node = this.body.nodes[nodeId];
39735 if (node === undefined) return [];
39736 stack.push(node.id);
39737 nodeId = this.clusteredNodes[nodeId].clusterId;
39738 counter++;
39739 }
39740
39741 node = this.body.nodes[nodeId];
39742 if (node === undefined) return [];
39743 stack.push(node.id);
39744 stack.reverse();
39745 return stack;
39746 }
39747 /**
39748 * Using a clustered nodeId, update with the new options
39749 * @param {vis.Edge.id} clusteredNodeId
39750 * @param {object} newOptions
39751 */
39752
39753 }, {
39754 key: "updateClusteredNode",
39755 value: function updateClusteredNode(clusteredNodeId, newOptions) {
39756 if (clusteredNodeId === undefined) {
39757 throw new Error("No clusteredNodeId supplied to updateClusteredNode.");
39758 }
39759
39760 if (newOptions === undefined) {
39761 throw new Error("No newOptions supplied to updateClusteredNode.");
39762 }
39763
39764 if (this.body.nodes[clusteredNodeId] === undefined) {
39765 throw new Error("The clusteredNodeId supplied to updateClusteredNode does not exist.");
39766 }
39767
39768 this.body.nodes[clusteredNodeId].setOptions(newOptions);
39769 this.body.emitter.emit('_dataChanged');
39770 }
39771 /**
39772 * Using a base edgeId, update all related clustered edges with the new options
39773 * @param {vis.Edge.id} startEdgeId
39774 * @param {object} newOptions
39775 */
39776
39777 }, {
39778 key: "updateEdge",
39779 value: function updateEdge(startEdgeId, newOptions) {
39780 if (startEdgeId === undefined) {
39781 throw new Error("No startEdgeId supplied to updateEdge.");
39782 }
39783
39784 if (newOptions === undefined) {
39785 throw new Error("No newOptions supplied to updateEdge.");
39786 }
39787
39788 if (this.body.edges[startEdgeId] === undefined) {
39789 throw new Error("The startEdgeId supplied to updateEdge does not exist.");
39790 }
39791
39792 var allEdgeIds = this.getClusteredEdges(startEdgeId);
39793
39794 for (var i = 0; i < allEdgeIds.length; i++) {
39795 var edge = this.body.edges[allEdgeIds[i]];
39796 edge.setOptions(newOptions);
39797 }
39798
39799 this.body.emitter.emit('_dataChanged');
39800 }
39801 /**
39802 * Get a stack of clusterEdgeId's (+base edgeid) that a base edge is the same as. cluster edge C -> cluster edge B -> cluster edge A -> base edge(edgeId)
39803 * @param {vis.Edge.id} edgeId
39804 * @returns {Array.<vis.Edge.id>}
39805 */
39806
39807 }, {
39808 key: "getClusteredEdges",
39809 value: function getClusteredEdges(edgeId) {
39810 var stack = [];
39811 var max = 100;
39812 var counter = 0;
39813
39814 while (edgeId !== undefined && this.body.edges[edgeId] !== undefined && counter < max) {
39815 stack.push(this.body.edges[edgeId].id);
39816 edgeId = this.body.edges[edgeId].edgeReplacedById;
39817 counter++;
39818 }
39819
39820 stack.reverse();
39821 return stack;
39822 }
39823 /**
39824 * Get the base edge id of clusterEdgeId. cluster edge (clusteredEdgeId) -> cluster edge B -> cluster edge C -> base edge
39825 * @param {vis.Edge.id} clusteredEdgeId
39826 * @returns {vis.Edge.id} baseEdgeId
39827 *
39828 * TODO: deprecate in 5.0.0. Method getBaseEdges() is the correct one to use.
39829 */
39830
39831 }, {
39832 key: "getBaseEdge",
39833 value: function getBaseEdge(clusteredEdgeId) {
39834 // Just kludge this by returning the first base edge id found
39835 return this.getBaseEdges(clusteredEdgeId)[0];
39836 }
39837 /**
39838 * Get all regular edges for this clustered edge id.
39839 *
39840 * @param {vis.Edge.id} clusteredEdgeId
39841 * @returns {Array.<vis.Edge.id>} all baseEdgeId's under this clustered edge
39842 */
39843
39844 }, {
39845 key: "getBaseEdges",
39846 value: function getBaseEdges(clusteredEdgeId) {
39847 var IdsToHandle = [clusteredEdgeId];
39848 var doneIds = [];
39849 var foundIds = [];
39850 var max = 100;
39851 var counter = 0;
39852
39853 while (IdsToHandle.length > 0 && counter < max) {
39854 var nextId = IdsToHandle.pop();
39855 if (nextId === undefined) continue; // Paranoia here and onwards
39856
39857 var nextEdge = this.body.edges[nextId];
39858 if (nextEdge === undefined) continue;
39859 counter++;
39860 var replacingIds = nextEdge.clusteringEdgeReplacingIds;
39861
39862 if (replacingIds === undefined) {
39863 // nextId is a base id
39864 foundIds.push(nextId);
39865 } else {
39866 // Another cluster edge, unravel this one as well
39867 for (var i = 0; i < replacingIds.length; ++i) {
39868 var replacingId = replacingIds[i]; // Don't add if already handled
39869 // TODO: never triggers; find a test-case which does
39870
39871 if (IdsToHandle.indexOf(replacingIds) !== -1 || doneIds.indexOf(replacingIds) !== -1) {
39872 continue;
39873 }
39874
39875 IdsToHandle.push(replacingId);
39876 }
39877 }
39878
39879 doneIds.push(nextId);
39880 }
39881
39882 return foundIds;
39883 }
39884 /**
39885 * Get the Id the node is connected to
39886 * @param {vis.Edge} edge
39887 * @param {Node.id} nodeId
39888 * @returns {*}
39889 * @private
39890 */
39891
39892 }, {
39893 key: "_getConnectedId",
39894 value: function _getConnectedId(edge, nodeId) {
39895 if (edge.toId != nodeId) {
39896 return edge.toId;
39897 } else if (edge.fromId != nodeId) {
39898 return edge.fromId;
39899 } else {
39900 return edge.fromId;
39901 }
39902 }
39903 /**
39904 * We determine how many connections denote an important hub.
39905 * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%)
39906 *
39907 * @returns {number}
39908 * @private
39909 */
39910
39911 }, {
39912 key: "_getHubSize",
39913 value: function _getHubSize() {
39914 var average = 0;
39915 var averageSquared = 0;
39916 var hubCounter = 0;
39917 var largestHub = 0;
39918
39919 for (var i = 0; i < this.body.nodeIndices.length; i++) {
39920 var node = this.body.nodes[this.body.nodeIndices[i]];
39921
39922 if (node.edges.length > largestHub) {
39923 largestHub = node.edges.length;
39924 }
39925
39926 average += node.edges.length;
39927 averageSquared += Math.pow(node.edges.length, 2);
39928 hubCounter += 1;
39929 }
39930
39931 average = average / hubCounter;
39932 averageSquared = averageSquared / hubCounter;
39933 var variance = averageSquared - Math.pow(average, 2);
39934 var standardDeviation = Math.sqrt(variance);
39935 var hubThreshold = Math.floor(average + 2 * standardDeviation); // always have at least one to cluster
39936
39937 if (hubThreshold > largestHub) {
39938 hubThreshold = largestHub;
39939 }
39940
39941 return hubThreshold;
39942 }
39943 /**
39944 * Create an edge for the cluster representation.
39945 *
39946 * @param {Node.id} fromId
39947 * @param {Node.id} toId
39948 * @param {vis.Edge} baseEdge
39949 * @param {Object} clusterEdgeProperties
39950 * @param {Object} extraOptions
39951 * @returns {Edge} newly created clustered edge
39952 * @private
39953 */
39954
39955 }, {
39956 key: "_createClusteredEdge",
39957 value: function _createClusteredEdge(fromId, toId, baseEdge, clusterEdgeProperties, extraOptions) {
39958 // copy the options of the edge we will replace
39959 var clonedOptions = NetworkUtil.cloneOptions(baseEdge, 'edge'); // make sure the properties of clusterEdges are superimposed on it
39960
39961 deepExtend(clonedOptions, clusterEdgeProperties); // set up the edge
39962
39963 clonedOptions.from = fromId;
39964 clonedOptions.to = toId;
39965 clonedOptions.id = 'clusterEdge:' + uuid4(); // apply the edge specific options to it if specified
39966
39967 if (extraOptions !== undefined) {
39968 deepExtend(clonedOptions, extraOptions);
39969 }
39970
39971 var newEdge = this.body.functions.createEdge(clonedOptions);
39972 newEdge.clusteringEdgeReplacingIds = [baseEdge.id];
39973 newEdge.connect(); // Register the new edge
39974
39975 this.body.edges[newEdge.id] = newEdge;
39976 return newEdge;
39977 }
39978 /**
39979 * Add the passed child nodes and edges to the given cluster node.
39980 *
39981 * @param {Object|Node} childNodes hash of nodes or single node to add in cluster
39982 * @param {Object|Edge} childEdges hash of edges or single edge to take into account when clustering
39983 * @param {Node} clusterNode cluster node to add nodes and edges to
39984 * @param {Object} [clusterEdgeProperties]
39985 * @private
39986 */
39987
39988 }, {
39989 key: "_clusterEdges",
39990 value: function _clusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties) {
39991 if (childEdges instanceof Edge) {
39992 var edge = childEdges;
39993 var obj = {};
39994 obj[edge.id] = edge;
39995 childEdges = obj;
39996 }
39997
39998 if (childNodes instanceof Node) {
39999 var node = childNodes;
40000 var _obj = {};
40001 _obj[node.id] = node;
40002 childNodes = _obj;
40003 }
40004
40005 if (clusterNode === undefined || clusterNode === null) {
40006 throw new Error("_clusterEdges: parameter clusterNode required");
40007 }
40008
40009 if (clusterEdgeProperties === undefined) {
40010 // Take the required properties from the cluster node
40011 clusterEdgeProperties = clusterNode.clusterEdgeProperties;
40012 } // create the new edges that will connect to the cluster.
40013 // All self-referencing edges will be added to childEdges here.
40014
40015
40016 this._createClusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties); // disable the childEdges
40017
40018
40019 for (var edgeId in childEdges) {
40020 if (childEdges.hasOwnProperty(edgeId)) {
40021 if (this.body.edges[edgeId] !== undefined) {
40022 var _edge2 = this.body.edges[edgeId]; // cache the options before changing
40023
40024 this._backupEdgeOptions(_edge2); // disable physics and hide the edge
40025
40026
40027 _edge2.setOptions({
40028 physics: false
40029 });
40030 }
40031 }
40032 } // disable the childNodes
40033
40034
40035 for (var nodeId in childNodes) {
40036 if (childNodes.hasOwnProperty(nodeId)) {
40037 this.clusteredNodes[nodeId] = {
40038 clusterId: clusterNode.id,
40039 node: this.body.nodes[nodeId]
40040 };
40041 this.body.nodes[nodeId].setOptions({
40042 physics: false
40043 });
40044 }
40045 }
40046 }
40047 /**
40048 * Determine in which cluster given nodeId resides.
40049 *
40050 * If not in cluster, return undefined.
40051 *
40052 * NOTE: If you know a cleaner way to do this, please enlighten me (wimrijnders).
40053 *
40054 * @param {Node.id} nodeId
40055 * @returns {Node|undefined} Node instance for cluster, if present
40056 * @private
40057 */
40058
40059 }, {
40060 key: "_getClusterNodeForNode",
40061 value: function _getClusterNodeForNode(nodeId) {
40062 if (nodeId === undefined) return undefined;
40063 var clusteredNode = this.clusteredNodes[nodeId]; // NOTE: If no cluster info found, it should actually be an error
40064
40065 if (clusteredNode === undefined) return undefined;
40066 var clusterId = clusteredNode.clusterId;
40067 if (clusterId === undefined) return undefined;
40068 return this.body.nodes[clusterId];
40069 }
40070 /**
40071 * Internal helper function for conditionally removing items in array
40072 *
40073 * Done like this because Array.filter() is not fully supported by all IE's.
40074 *
40075 * @param {Array} arr
40076 * @param {function} callback
40077 * @returns {Array}
40078 * @private
40079 */
40080
40081 }, {
40082 key: "_filter",
40083 value: function _filter(arr, callback) {
40084 var ret = [];
40085 forEach(arr, function (item) {
40086 if (callback(item)) {
40087 ret.push(item);
40088 }
40089 });
40090 return ret;
40091 }
40092 /**
40093 * Scan all edges for changes in clustering and adjust this if necessary.
40094 *
40095 * Call this (internally) after there has been a change in node or edge data.
40096 *
40097 * Pre: States of this.body.nodes and this.body.edges consistent
40098 * Pre: this.clusteredNodes and this.clusteredEdge consistent with containedNodes and containedEdges
40099 * of cluster nodes.
40100 */
40101
40102 }, {
40103 key: "_updateState",
40104 value: function _updateState() {
40105 var _this4 = this;
40106
40107 var nodeId;
40108 var deletedNodeIds = [];
40109 var deletedEdgeIds = {};
40110 /**
40111 * Utility function to iterate over clustering nodes only
40112 *
40113 * @param {Function} callback function to call for each cluster node
40114 */
40115
40116 var eachClusterNode = function eachClusterNode(callback) {
40117 forEach(_this4.body.nodes, function (node) {
40118 if (node.isCluster === true) {
40119 callback(node);
40120 }
40121 });
40122 }; //
40123 // Remove deleted regular nodes from clustering
40124 //
40125 // Determine the deleted nodes
40126
40127
40128 for (nodeId in this.clusteredNodes) {
40129 if (!this.clusteredNodes.hasOwnProperty(nodeId)) continue;
40130 var node = this.body.nodes[nodeId];
40131
40132 if (node === undefined) {
40133 deletedNodeIds.push(nodeId);
40134 }
40135 } // Remove nodes from cluster nodes
40136
40137
40138 eachClusterNode(function (clusterNode) {
40139 for (var n = 0; n < deletedNodeIds.length; n++) {
40140 delete clusterNode.containedNodes[deletedNodeIds[n]];
40141 }
40142 }); // Remove nodes from cluster list
40143
40144 for (var n = 0; n < deletedNodeIds.length; n++) {
40145 delete this.clusteredNodes[deletedNodeIds[n]];
40146 } //
40147 // Remove deleted edges from clustering
40148 //
40149 // Add the deleted clustered edges to the list
40150
40151
40152 forEach(this.clusteredEdges, function (edgeId) {
40153 var edge = _this4.body.edges[edgeId];
40154
40155 if (edge === undefined || !edge.endPointsValid()) {
40156 deletedEdgeIds[edgeId] = edgeId;
40157 }
40158 }); // Cluster nodes can also contain edges which are not clustered,
40159 // i.e. nodes 1-2 within cluster with an edge in between.
40160 // So the cluster nodes also need to be scanned for invalid edges
40161
40162 eachClusterNode(function (clusterNode) {
40163 forEach(clusterNode.containedEdges, function (edge, edgeId) {
40164 if (!edge.endPointsValid() && !deletedEdgeIds[edgeId]) {
40165 deletedEdgeIds[edgeId] = edgeId;
40166 }
40167 });
40168 }); // Also scan for cluster edges which need to be removed in the active list.
40169 // Regular edges have been removed beforehand, so this only picks up the cluster edges.
40170
40171 forEach(this.body.edges, function (edge, edgeId) {
40172 // Explicitly scan the contained edges for validity
40173 var isValid = true;
40174 var replacedIds = edge.clusteringEdgeReplacingIds;
40175
40176 if (replacedIds !== undefined) {
40177 var numValid = 0;
40178 forEach(replacedIds, function (containedEdgeId) {
40179 var containedEdge = _this4.body.edges[containedEdgeId];
40180
40181 if (containedEdge !== undefined && containedEdge.endPointsValid()) {
40182 numValid += 1;
40183 }
40184 });
40185 isValid = numValid > 0;
40186 }
40187
40188 if (!edge.endPointsValid() || !isValid) {
40189 deletedEdgeIds[edgeId] = edgeId;
40190 }
40191 }); // Remove edges from cluster nodes
40192
40193 eachClusterNode(function (clusterNode) {
40194 forEach(deletedEdgeIds, function (deletedEdgeId) {
40195 delete clusterNode.containedEdges[deletedEdgeId];
40196 forEach(clusterNode.edges, function (edge, m) {
40197 if (edge.id === deletedEdgeId) {
40198 clusterNode.edges[m] = null; // Don't want to directly delete here, because in the loop
40199
40200 return;
40201 }
40202
40203 edge.clusteringEdgeReplacingIds = _this4._filter(edge.clusteringEdgeReplacingIds, function (id) {
40204 return !deletedEdgeIds[id];
40205 });
40206 }); // Clean up the nulls
40207
40208 clusterNode.edges = _this4._filter(clusterNode.edges, function (item) {
40209 return item !== null;
40210 });
40211 });
40212 }); // Remove from cluster list
40213
40214 forEach(deletedEdgeIds, function (edgeId) {
40215 delete _this4.clusteredEdges[edgeId];
40216 }); // Remove cluster edges from active list (this.body.edges).
40217 // deletedEdgeIds still contains id of regular edges, but these should all
40218 // be gone when you reach here.
40219
40220 forEach(deletedEdgeIds, function (edgeId) {
40221 delete _this4.body.edges[edgeId];
40222 }); //
40223 // Check changed cluster state of edges
40224 //
40225 // Iterating over keys here, because edges may be removed in the loop
40226
40227 var ids = Object.keys(this.body.edges);
40228 forEach(ids, function (edgeId) {
40229 var edge = _this4.body.edges[edgeId];
40230
40231 var shouldBeClustered = _this4._isClusteredNode(edge.fromId) || _this4._isClusteredNode(edge.toId);
40232
40233 if (shouldBeClustered === _this4._isClusteredEdge(edge.id)) {
40234 return; // all is well
40235 }
40236
40237 if (shouldBeClustered) {
40238 // add edge to clustering
40239 var clusterFrom = _this4._getClusterNodeForNode(edge.fromId);
40240
40241 if (clusterFrom !== undefined) {
40242 _this4._clusterEdges(_this4.body.nodes[edge.fromId], edge, clusterFrom);
40243 }
40244
40245 var clusterTo = _this4._getClusterNodeForNode(edge.toId);
40246
40247 if (clusterTo !== undefined) {
40248 _this4._clusterEdges(_this4.body.nodes[edge.toId], edge, clusterTo);
40249 } // TODO: check that it works for both edges clustered
40250 // (This might be paranoia)
40251
40252 } else {
40253 delete _this4._clusterEdges[edgeId];
40254
40255 _this4._restoreEdge(edge); // This should not be happening, the state should
40256 // be properly updated at this point.
40257 //
40258 // If it *is* reached during normal operation, then we have to implement
40259 // undo clustering for this edge here.
40260 // throw new Error('remove edge from clustering not implemented!')
40261
40262 }
40263 }); // Clusters may be nested to any level. Keep on opening until nothing to open
40264
40265 var changed = false;
40266 var continueLoop = true;
40267
40268 var _loop2 = function _loop2() {
40269 var clustersToOpen = []; // Determine the id's of clusters that need opening
40270
40271 eachClusterNode(function (clusterNode) {
40272 var numNodes = Object.keys(clusterNode.containedNodes).length;
40273 var allowSingle = clusterNode.options.allowSingleNodeCluster === true;
40274
40275 if (allowSingle && numNodes < 1 || !allowSingle && numNodes < 2) {
40276 clustersToOpen.push(clusterNode.id);
40277 }
40278 }); // Open them
40279
40280 for (var _n = 0; _n < clustersToOpen.length; ++_n) {
40281 _this4.openCluster(clustersToOpen[_n], {}, false
40282 /* Don't refresh, we're in an refresh/update already */
40283 );
40284 }
40285
40286 continueLoop = clustersToOpen.length > 0;
40287 changed = changed || continueLoop;
40288 };
40289
40290 while (continueLoop) {
40291 _loop2();
40292 }
40293
40294 if (changed) {
40295 this._updateState(); // Redo this method (recursion possible! should be safe)
40296
40297 }
40298 }
40299 /**
40300 * Determine if node with given id is part of a cluster.
40301 *
40302 * @param {Node.id} nodeId
40303 * @return {boolean} true if part of a cluster.
40304 */
40305
40306 }, {
40307 key: "_isClusteredNode",
40308 value: function _isClusteredNode(nodeId) {
40309 return this.clusteredNodes[nodeId] !== undefined;
40310 }
40311 /**
40312 * Determine if edge with given id is not visible due to clustering.
40313 *
40314 * An edge is considered clustered if:
40315 * - it is directly replaced by a clustering edge
40316 * - any of its connecting nodes is in a cluster
40317 *
40318 * @param {vis.Edge.id} edgeId
40319 * @return {boolean} true if part of a cluster.
40320 */
40321
40322 }, {
40323 key: "_isClusteredEdge",
40324 value: function _isClusteredEdge(edgeId) {
40325 return this.clusteredEdges[edgeId] !== undefined;
40326 }
40327 }]);
40328
40329 return ClusterEngine;
40330 }();
40331
40332 /**
40333 * Initializes window.requestAnimationFrame() to a usable form.
40334 *
40335 * Specifically, set up this method for the case of running on node.js with jsdom enabled.
40336 *
40337 * NOTES:
40338 *
40339 * * On node.js, when calling this directly outside of this class, `window` is not defined.
40340 * This happens even if jsdom is used.
40341 * * For node.js + jsdom, `window` is available at the moment the constructor is called.
40342 * For this reason, the called is placed within the constructor.
40343 * * Even then, `window.requestAnimationFrame()` is not defined, so it still needs to be added.
40344 * * During unit testing, it happens that the window object is reset during execution, causing
40345 * a runtime error due to missing `requestAnimationFrame()`. This needs to be compensated for,
40346 * see `_requestNextFrame()`.
40347 * * Since this is a global object, it may affect other modules besides `Network`. With normal
40348 * usage, this does not cause any problems. During unit testing, errors may occur. These have
40349 * been compensated for, see comment block in _requestNextFrame().
40350 *
40351 * @private
40352 */
40353 function _initRequestAnimationFrame() {
40354 var func;
40355
40356 if (window !== undefined) {
40357 func = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
40358 }
40359
40360 if (func === undefined) {
40361 // window or method not present, setting mock requestAnimationFrame
40362 window.requestAnimationFrame = function (callback) {
40363 //console.log("Called mock requestAnimationFrame");
40364 callback();
40365 };
40366 } else {
40367 window.requestAnimationFrame = func;
40368 }
40369 }
40370 /**
40371 * The canvas renderer
40372 */
40373
40374 var CanvasRenderer =
40375 /*#__PURE__*/
40376 function () {
40377 /**
40378 * @param {Object} body
40379 * @param {Canvas} canvas
40380 */
40381 function CanvasRenderer(body, canvas) {
40382 _classCallCheck(this, CanvasRenderer);
40383
40384 _initRequestAnimationFrame();
40385
40386 this.body = body;
40387 this.canvas = canvas;
40388 this.redrawRequested = false;
40389 this.renderTimer = undefined;
40390 this.requiresTimeout = true;
40391 this.renderingActive = false;
40392 this.renderRequests = 0;
40393 this.allowRedraw = true;
40394 this.dragging = false;
40395 this.zooming = false;
40396 this.options = {};
40397 this.defaultOptions = {
40398 hideEdgesOnDrag: false,
40399 hideEdgesOnZoom: false,
40400 hideNodesOnDrag: false
40401 };
40402 extend(this.options, this.defaultOptions);
40403
40404 this._determineBrowserMethod();
40405
40406 this.bindEventListeners();
40407 }
40408 /**
40409 * Binds event listeners
40410 */
40411
40412
40413 _createClass(CanvasRenderer, [{
40414 key: "bindEventListeners",
40415 value: function bindEventListeners() {
40416 var _this = this;
40417
40418 this.body.emitter.on("dragStart", function () {
40419 _this.dragging = true;
40420 });
40421 this.body.emitter.on("dragEnd", function () {
40422 _this.dragging = false;
40423 });
40424 this.body.emitter.on("zoom", function () {
40425 _this.zooming = true;
40426 window.clearTimeout(_this.zoomTimeoutId);
40427 _this.zoomTimeoutId = window.setTimeout(function () {
40428 _this.zooming = false;
40429
40430 _this._requestRedraw.bind(_this)();
40431 }, 250);
40432 });
40433 this.body.emitter.on("_resizeNodes", function () {
40434 _this._resizeNodes();
40435 });
40436 this.body.emitter.on("_redraw", function () {
40437 if (_this.renderingActive === false) {
40438 _this._redraw();
40439 }
40440 });
40441 this.body.emitter.on("_blockRedraw", function () {
40442 _this.allowRedraw = false;
40443 });
40444 this.body.emitter.on("_allowRedraw", function () {
40445 _this.allowRedraw = true;
40446 _this.redrawRequested = false;
40447 });
40448 this.body.emitter.on("_requestRedraw", this._requestRedraw.bind(this));
40449 this.body.emitter.on("_startRendering", function () {
40450 _this.renderRequests += 1;
40451 _this.renderingActive = true;
40452
40453 _this._startRendering();
40454 });
40455 this.body.emitter.on("_stopRendering", function () {
40456 _this.renderRequests -= 1;
40457 _this.renderingActive = _this.renderRequests > 0;
40458 _this.renderTimer = undefined;
40459 });
40460 this.body.emitter.on('destroy', function () {
40461 _this.renderRequests = 0;
40462 _this.allowRedraw = false;
40463 _this.renderingActive = false;
40464
40465 if (_this.requiresTimeout === true) {
40466 clearTimeout(_this.renderTimer);
40467 } else {
40468 window.cancelAnimationFrame(_this.renderTimer);
40469 }
40470
40471 _this.body.emitter.off();
40472 });
40473 }
40474 /**
40475 *
40476 * @param {Object} options
40477 */
40478
40479 }, {
40480 key: "setOptions",
40481 value: function setOptions(options) {
40482 if (options !== undefined) {
40483 var fields = ['hideEdgesOnDrag', 'hideEdgesOnZoom', 'hideNodesOnDrag'];
40484 selectiveDeepExtend(fields, this.options, options);
40485 }
40486 }
40487 /**
40488 * Prepare the drawing of the next frame.
40489 *
40490 * Calls the callback when the next frame can or will be drawn.
40491 *
40492 * @param {function} callback
40493 * @param {number} delay - timeout case only, wait this number of milliseconds
40494 * @returns {function|undefined}
40495 * @private
40496 */
40497
40498 }, {
40499 key: "_requestNextFrame",
40500 value: function _requestNextFrame(callback, delay) {
40501 // During unit testing, it happens that the mock window object is reset while
40502 // the next frame is still pending. Then, either 'window' is not present, or
40503 // 'requestAnimationFrame()' is not present because it is not defined on the
40504 // mock window object.
40505 //
40506 // As a consequence, unrelated unit tests may appear to fail, even if the problem
40507 // described happens in the current unit test.
40508 //
40509 // This is not something that will happen in normal operation, but we still need
40510 // to take it into account.
40511 //
40512 if (typeof window === 'undefined') return; // Doing `if (window === undefined)` does not work here!
40513
40514 var timer;
40515 var myWindow = window; // Grab a reference to reduce the possibility that 'window' is reset
40516 // while running this method.
40517
40518 if (this.requiresTimeout === true) {
40519 // wait given number of milliseconds and perform the animation step function
40520 timer = myWindow.setTimeout(callback, delay);
40521 } else {
40522 if (myWindow.requestAnimationFrame) {
40523 timer = myWindow.requestAnimationFrame(callback);
40524 }
40525 }
40526
40527 return timer;
40528 }
40529 /**
40530 *
40531 * @private
40532 */
40533
40534 }, {
40535 key: "_startRendering",
40536 value: function _startRendering() {
40537 if (this.renderingActive === true) {
40538 if (this.renderTimer === undefined) {
40539 this.renderTimer = this._requestNextFrame(this._renderStep.bind(this), this.simulationInterval);
40540 }
40541 }
40542 }
40543 /**
40544 *
40545 * @private
40546 */
40547
40548 }, {
40549 key: "_renderStep",
40550 value: function _renderStep() {
40551 if (this.renderingActive === true) {
40552 // reset the renderTimer so a new scheduled animation step can be set
40553 this.renderTimer = undefined;
40554
40555 if (this.requiresTimeout === true) {
40556 // this schedules a new simulation step
40557 this._startRendering();
40558 }
40559
40560 this._redraw();
40561
40562 if (this.requiresTimeout === false) {
40563 // this schedules a new simulation step
40564 this._startRendering();
40565 }
40566 }
40567 }
40568 /**
40569 * Redraw the network with the current data
40570 * chart will be resized too.
40571 */
40572
40573 }, {
40574 key: "redraw",
40575 value: function redraw() {
40576 this.body.emitter.emit('setSize');
40577
40578 this._redraw();
40579 }
40580 /**
40581 * Redraw the network with the current data
40582 * @private
40583 */
40584
40585 }, {
40586 key: "_requestRedraw",
40587 value: function _requestRedraw() {
40588 var _this2 = this;
40589
40590 if (this.redrawRequested !== true && this.renderingActive === false && this.allowRedraw === true) {
40591 this.redrawRequested = true;
40592
40593 this._requestNextFrame(function () {
40594 _this2._redraw(false);
40595 }, 0);
40596 }
40597 }
40598 /**
40599 * Redraw the network with the current data
40600 * @param {boolean} [hidden=false] | Used to get the first estimate of the node sizes.
40601 * Only the nodes are drawn after which they are quickly drawn over.
40602 * @private
40603 */
40604
40605 }, {
40606 key: "_redraw",
40607 value: function _redraw() {
40608 var hidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
40609
40610 if (this.allowRedraw === true) {
40611 this.body.emitter.emit("initRedraw");
40612 this.redrawRequested = false; // when the container div was hidden, this fixes it back up!
40613
40614 if (this.canvas.frame.canvas.width === 0 || this.canvas.frame.canvas.height === 0) {
40615 this.canvas.setSize();
40616 }
40617
40618 this.canvas.setTransform();
40619 var ctx = this.canvas.getContext(); // clear the canvas
40620
40621 var w = this.canvas.frame.canvas.clientWidth;
40622 var h = this.canvas.frame.canvas.clientHeight;
40623 ctx.clearRect(0, 0, w, h); // if the div is hidden, we stop the redraw here for performance.
40624
40625 if (this.canvas.frame.clientWidth === 0) {
40626 return;
40627 } // set scaling and translation
40628
40629
40630 ctx.save();
40631 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
40632 ctx.scale(this.body.view.scale, this.body.view.scale);
40633 ctx.beginPath();
40634 this.body.emitter.emit("beforeDrawing", ctx);
40635 ctx.closePath();
40636
40637 if (hidden === false) {
40638 if ((this.dragging === false || this.dragging === true && this.options.hideEdgesOnDrag === false) && (this.zooming === false || this.zooming === true && this.options.hideEdgesOnZoom === false)) {
40639 this._drawEdges(ctx);
40640 }
40641 }
40642
40643 if (this.dragging === false || this.dragging === true && this.options.hideNodesOnDrag === false) {
40644 this._drawNodes(ctx, hidden);
40645 }
40646
40647 ctx.beginPath();
40648 this.body.emitter.emit("afterDrawing", ctx);
40649 ctx.closePath(); // restore original scaling and translation
40650
40651 ctx.restore();
40652
40653 if (hidden === true) {
40654 ctx.clearRect(0, 0, w, h);
40655 }
40656 }
40657 }
40658 /**
40659 * Redraw all nodes
40660 *
40661 * @param {CanvasRenderingContext2D} ctx
40662 * @param {boolean} [alwaysShow]
40663 * @private
40664 */
40665
40666 }, {
40667 key: "_resizeNodes",
40668 value: function _resizeNodes() {
40669 this.canvas.setTransform();
40670 var ctx = this.canvas.getContext();
40671 ctx.save();
40672 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
40673 ctx.scale(this.body.view.scale, this.body.view.scale);
40674 var nodes = this.body.nodes;
40675 var node; // resize all nodes
40676
40677 for (var nodeId in nodes) {
40678 if (nodes.hasOwnProperty(nodeId)) {
40679 node = nodes[nodeId];
40680 node.resize(ctx);
40681 node.updateBoundingBox(ctx, node.selected);
40682 }
40683 } // restore original scaling and translation
40684
40685
40686 ctx.restore();
40687 }
40688 /**
40689 * Redraw all nodes
40690 *
40691 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
40692 * @param {boolean} [alwaysShow]
40693 * @private
40694 */
40695
40696 }, {
40697 key: "_drawNodes",
40698 value: function _drawNodes(ctx) {
40699 var alwaysShow = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
40700 var nodes = this.body.nodes;
40701 var nodeIndices = this.body.nodeIndices;
40702 var node;
40703 var selected = [];
40704 var margin = 20;
40705 var topLeft = this.canvas.DOMtoCanvas({
40706 x: -margin,
40707 y: -margin
40708 });
40709 var bottomRight = this.canvas.DOMtoCanvas({
40710 x: this.canvas.frame.canvas.clientWidth + margin,
40711 y: this.canvas.frame.canvas.clientHeight + margin
40712 });
40713 var viewableArea = {
40714 top: topLeft.y,
40715 left: topLeft.x,
40716 bottom: bottomRight.y,
40717 right: bottomRight.x
40718 }; // draw unselected nodes;
40719
40720 for (var i = 0; i < nodeIndices.length; i++) {
40721 node = nodes[nodeIndices[i]]; // set selected nodes aside
40722
40723 if (node.isSelected()) {
40724 selected.push(nodeIndices[i]);
40725 } else {
40726 if (alwaysShow === true) {
40727 node.draw(ctx);
40728 } else if (node.isBoundingBoxOverlappingWith(viewableArea) === true) {
40729 node.draw(ctx);
40730 } else {
40731 node.updateBoundingBox(ctx, node.selected);
40732 }
40733 }
40734 } // draw the selected nodes on top
40735
40736
40737 for (var _i = 0; _i < selected.length; _i++) {
40738 node = nodes[selected[_i]];
40739 node.draw(ctx);
40740 }
40741 }
40742 /**
40743 * Redraw all edges
40744 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
40745 * @private
40746 */
40747
40748 }, {
40749 key: "_drawEdges",
40750 value: function _drawEdges(ctx) {
40751 var edges = this.body.edges;
40752 var edgeIndices = this.body.edgeIndices;
40753 var edge;
40754
40755 for (var i = 0; i < edgeIndices.length; i++) {
40756 edge = edges[edgeIndices[i]];
40757
40758 if (edge.connected === true) {
40759 edge.draw(ctx);
40760 }
40761 }
40762 }
40763 /**
40764 * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because
40765 * some implementations (safari and IE9) did not support requestAnimationFrame
40766 * @private
40767 */
40768
40769 }, {
40770 key: "_determineBrowserMethod",
40771 value: function _determineBrowserMethod() {
40772 if (typeof window !== 'undefined') {
40773 var browserType = navigator.userAgent.toLowerCase();
40774 this.requiresTimeout = false;
40775
40776 if (browserType.indexOf('msie 9.0') != -1) {
40777 // IE 9
40778 this.requiresTimeout = true;
40779 } else if (browserType.indexOf('safari') != -1) {
40780 // safari
40781 if (browserType.indexOf('chrome') <= -1) {
40782 this.requiresTimeout = true;
40783 }
40784 }
40785 } else {
40786 this.requiresTimeout = true;
40787 }
40788 }
40789 }]);
40790
40791 return CanvasRenderer;
40792 }();
40793
40794 var hammerUtil = createCommonjsModule(function (module, exports) {
40795 /**
40796 * Register a touch event, taking place before a gesture
40797 * @param {Hammer} hammer A hammer instance
40798 * @param {function} callback Callback, called as callback(event)
40799 */
40800 exports.onTouch = function (hammer, callback) {
40801 callback.inputHandler = function (event) {
40802 if (event.isFirst) {
40803 callback(event);
40804 }
40805 };
40806
40807 hammer.on('hammer.input', callback.inputHandler);
40808 };
40809 /**
40810 * Register a release event, taking place after a gesture
40811 * @param {Hammer} hammer A hammer instance
40812 * @param {function} callback Callback, called as callback(event)
40813 * @returns {*}
40814 */
40815
40816
40817 exports.onRelease = function (hammer, callback) {
40818 callback.inputHandler = function (event) {
40819 if (event.isFinal) {
40820 callback(event);
40821 }
40822 };
40823
40824 return hammer.on('hammer.input', callback.inputHandler);
40825 };
40826 /**
40827 * Unregister a touch event, taking place before a gesture
40828 * @param {Hammer} hammer A hammer instance
40829 * @param {function} callback Callback, called as callback(event)
40830 */
40831
40832
40833 exports.offTouch = function (hammer, callback) {
40834 hammer.off('hammer.input', callback.inputHandler);
40835 };
40836 /**
40837 * Unregister a release event, taking place before a gesture
40838 * @param {Hammer} hammer A hammer instance
40839 * @param {function} callback Callback, called as callback(event)
40840 */
40841
40842
40843 exports.offRelease = exports.offTouch;
40844 /**
40845 * Hack the PinchRecognizer such that it doesn't prevent default behavior
40846 * for vertical panning.
40847 *
40848 * Yeah ... this is quite a hack ... see https://github.com/hammerjs/hammer.js/issues/932
40849 *
40850 * @param {Hammer.Pinch} pinchRecognizer
40851 * @return {Hammer.Pinch} returns the pinchRecognizer
40852 */
40853
40854 exports.disablePreventDefaultVertically = function (pinchRecognizer) {
40855 var TOUCH_ACTION_PAN_Y = 'pan-y';
40856
40857 pinchRecognizer.getTouchAction = function () {
40858 // default method returns [TOUCH_ACTION_NONE]
40859 return [TOUCH_ACTION_PAN_Y];
40860 };
40861
40862 return pinchRecognizer;
40863 };
40864 });
40865 var hammerUtil_1 = hammerUtil.onTouch;
40866 var hammerUtil_2 = hammerUtil.onRelease;
40867 var hammerUtil_3 = hammerUtil.offTouch;
40868 var hammerUtil_4 = hammerUtil.offRelease;
40869 var hammerUtil_5 = hammerUtil.disablePreventDefaultVertically;
40870
40871 /**
40872 * Create the main frame for the Network.
40873 * This function is executed once when a Network object is created. The frame
40874 * contains a canvas, and this canvas contains all objects like the axis and
40875 * nodes.
40876 */
40877
40878 var Canvas =
40879 /*#__PURE__*/
40880 function () {
40881 /**
40882 * @param {Object} body
40883 */
40884 function Canvas(body) {
40885 _classCallCheck(this, Canvas);
40886
40887 this.body = body;
40888 this.pixelRatio = 1;
40889 this.resizeTimer = undefined;
40890 this.resizeFunction = this._onResize.bind(this);
40891 this.cameraState = {};
40892 this.initialized = false;
40893 this.canvasViewCenter = {};
40894 this.options = {};
40895 this.defaultOptions = {
40896 autoResize: true,
40897 height: '100%',
40898 width: '100%'
40899 };
40900 extend(this.options, this.defaultOptions);
40901 this.bindEventListeners();
40902 }
40903 /**
40904 * Binds event listeners
40905 */
40906
40907
40908 _createClass(Canvas, [{
40909 key: "bindEventListeners",
40910 value: function bindEventListeners() {
40911 var _this = this;
40912
40913 // bind the events
40914 this.body.emitter.once("resize", function (obj) {
40915 if (obj.width !== 0) {
40916 _this.body.view.translation.x = obj.width * 0.5;
40917 }
40918
40919 if (obj.height !== 0) {
40920 _this.body.view.translation.y = obj.height * 0.5;
40921 }
40922 });
40923 this.body.emitter.on("setSize", this.setSize.bind(this));
40924 this.body.emitter.on("destroy", function () {
40925 _this.hammerFrame.destroy();
40926
40927 _this.hammer.destroy();
40928
40929 _this._cleanUp();
40930 });
40931 }
40932 /**
40933 * @param {Object} options
40934 */
40935
40936 }, {
40937 key: "setOptions",
40938 value: function setOptions(options) {
40939 var _this2 = this;
40940
40941 if (options !== undefined) {
40942 var fields = ['width', 'height', 'autoResize'];
40943 selectiveDeepExtend(fields, this.options, options);
40944 }
40945
40946 if (this.options.autoResize === true) {
40947 // automatically adapt to a changing size of the browser.
40948 this._cleanUp();
40949
40950 this.resizeTimer = setInterval(function () {
40951 var changed = _this2.setSize();
40952
40953 if (changed === true) {
40954 _this2.body.emitter.emit("_requestRedraw");
40955 }
40956 }, 1000);
40957 this.resizeFunction = this._onResize.bind(this);
40958 addEventListener(window, 'resize', this.resizeFunction);
40959 }
40960 }
40961 /**
40962 * @private
40963 */
40964
40965 }, {
40966 key: "_cleanUp",
40967 value: function _cleanUp() {
40968 // automatically adapt to a changing size of the browser.
40969 if (this.resizeTimer !== undefined) {
40970 clearInterval(this.resizeTimer);
40971 }
40972
40973 removeEventListener(window, 'resize', this.resizeFunction);
40974 this.resizeFunction = undefined;
40975 }
40976 /**
40977 * @private
40978 */
40979
40980 }, {
40981 key: "_onResize",
40982 value: function _onResize() {
40983 this.setSize();
40984 this.body.emitter.emit("_redraw");
40985 }
40986 /**
40987 * Get and store the cameraState
40988 *
40989 * @param {number} [pixelRatio=this.pixelRatio]
40990 * @private
40991 */
40992
40993 }, {
40994 key: "_getCameraState",
40995 value: function _getCameraState() {
40996 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.pixelRatio;
40997
40998 if (this.initialized === true) {
40999 this.cameraState.previousWidth = this.frame.canvas.width / pixelRatio;
41000 this.cameraState.previousHeight = this.frame.canvas.height / pixelRatio;
41001 this.cameraState.scale = this.body.view.scale;
41002 this.cameraState.position = this.DOMtoCanvas({
41003 x: 0.5 * this.frame.canvas.width / pixelRatio,
41004 y: 0.5 * this.frame.canvas.height / pixelRatio
41005 });
41006 }
41007 }
41008 /**
41009 * Set the cameraState
41010 * @private
41011 */
41012
41013 }, {
41014 key: "_setCameraState",
41015 value: function _setCameraState() {
41016 if (this.cameraState.scale !== undefined && this.frame.canvas.clientWidth !== 0 && this.frame.canvas.clientHeight !== 0 && this.pixelRatio !== 0 && this.cameraState.previousWidth > 0) {
41017 var widthRatio = this.frame.canvas.width / this.pixelRatio / this.cameraState.previousWidth;
41018 var heightRatio = this.frame.canvas.height / this.pixelRatio / this.cameraState.previousHeight;
41019 var newScale = this.cameraState.scale;
41020
41021 if (widthRatio != 1 && heightRatio != 1) {
41022 newScale = this.cameraState.scale * 0.5 * (widthRatio + heightRatio);
41023 } else if (widthRatio != 1) {
41024 newScale = this.cameraState.scale * widthRatio;
41025 } else if (heightRatio != 1) {
41026 newScale = this.cameraState.scale * heightRatio;
41027 }
41028
41029 this.body.view.scale = newScale; // this comes from the view module.
41030
41031 var currentViewCenter = this.DOMtoCanvas({
41032 x: 0.5 * this.frame.canvas.clientWidth,
41033 y: 0.5 * this.frame.canvas.clientHeight
41034 });
41035 var distanceFromCenter = {
41036 // offset from view, distance view has to change by these x and y to center the node
41037 x: currentViewCenter.x - this.cameraState.position.x,
41038 y: currentViewCenter.y - this.cameraState.position.y
41039 };
41040 this.body.view.translation.x += distanceFromCenter.x * this.body.view.scale;
41041 this.body.view.translation.y += distanceFromCenter.y * this.body.view.scale;
41042 }
41043 }
41044 /**
41045 *
41046 * @param {number|string} value
41047 * @returns {string}
41048 * @private
41049 */
41050
41051 }, {
41052 key: "_prepareValue",
41053 value: function _prepareValue(value) {
41054 if (typeof value === 'number') {
41055 return value + 'px';
41056 } else if (typeof value === 'string') {
41057 if (value.indexOf('%') !== -1 || value.indexOf('px') !== -1) {
41058 return value;
41059 } else if (value.indexOf('%') === -1) {
41060 return value + 'px';
41061 }
41062 }
41063
41064 throw new Error('Could not use the value supplied for width or height:' + value);
41065 }
41066 /**
41067 * Create the HTML
41068 */
41069
41070 }, {
41071 key: "_create",
41072 value: function _create() {
41073 // remove all elements from the container element.
41074 while (this.body.container.hasChildNodes()) {
41075 this.body.container.removeChild(this.body.container.firstChild);
41076 }
41077
41078 this.frame = document.createElement('div');
41079 this.frame.className = 'vis-network';
41080 this.frame.style.position = 'relative';
41081 this.frame.style.overflow = 'hidden';
41082 this.frame.tabIndex = 900; // tab index is required for keycharm to bind keystrokes to the div instead of the window
41083 //////////////////////////////////////////////////////////////////
41084
41085 this.frame.canvas = document.createElement("canvas");
41086 this.frame.canvas.style.position = 'relative';
41087 this.frame.appendChild(this.frame.canvas);
41088
41089 if (!this.frame.canvas.getContext) {
41090 var noCanvas = document.createElement('DIV');
41091 noCanvas.style.color = 'red';
41092 noCanvas.style.fontWeight = 'bold';
41093 noCanvas.style.padding = '10px';
41094 noCanvas.innerHTML = 'Error: your browser does not support HTML canvas';
41095 this.frame.canvas.appendChild(noCanvas);
41096 } else {
41097 this._setPixelRatio();
41098
41099 this.setTransform();
41100 } // add the frame to the container element
41101
41102
41103 this.body.container.appendChild(this.frame);
41104 this.body.view.scale = 1;
41105 this.body.view.translation = {
41106 x: 0.5 * this.frame.canvas.clientWidth,
41107 y: 0.5 * this.frame.canvas.clientHeight
41108 };
41109
41110 this._bindHammer();
41111 }
41112 /**
41113 * This function binds hammer, it can be repeated over and over due to the uniqueness check.
41114 * @private
41115 */
41116
41117 }, {
41118 key: "_bindHammer",
41119 value: function _bindHammer() {
41120 var _this3 = this;
41121
41122 if (this.hammer !== undefined) {
41123 this.hammer.destroy();
41124 }
41125
41126 this.drag = {};
41127 this.pinch = {}; // init hammer
41128
41129 this.hammer = new hammer(this.frame.canvas);
41130 this.hammer.get('pinch').set({
41131 enable: true
41132 }); // enable to get better response, todo: test on mobile.
41133
41134 this.hammer.get('pan').set({
41135 threshold: 5,
41136 direction: hammer.DIRECTION_ALL
41137 });
41138 hammerUtil.onTouch(this.hammer, function (event) {
41139 _this3.body.eventListeners.onTouch(event);
41140 });
41141 this.hammer.on('tap', function (event) {
41142 _this3.body.eventListeners.onTap(event);
41143 });
41144 this.hammer.on('doubletap', function (event) {
41145 _this3.body.eventListeners.onDoubleTap(event);
41146 });
41147 this.hammer.on('press', function (event) {
41148 _this3.body.eventListeners.onHold(event);
41149 });
41150 this.hammer.on('panstart', function (event) {
41151 _this3.body.eventListeners.onDragStart(event);
41152 });
41153 this.hammer.on('panmove', function (event) {
41154 _this3.body.eventListeners.onDrag(event);
41155 });
41156 this.hammer.on('panend', function (event) {
41157 _this3.body.eventListeners.onDragEnd(event);
41158 });
41159 this.hammer.on('pinch', function (event) {
41160 _this3.body.eventListeners.onPinch(event);
41161 }); // TODO: neatly cleanup these handlers when re-creating the Canvas, IF these are done with hammer, event.stopPropagation will not work?
41162
41163 this.frame.canvas.addEventListener('wheel', function (event) {
41164 _this3.body.eventListeners.onMouseWheel(event);
41165 });
41166 this.frame.canvas.addEventListener('mousemove', function (event) {
41167 _this3.body.eventListeners.onMouseMove(event);
41168 });
41169 this.frame.canvas.addEventListener('contextmenu', function (event) {
41170 _this3.body.eventListeners.onContext(event);
41171 });
41172 this.hammerFrame = new hammer(this.frame);
41173 hammerUtil.onRelease(this.hammerFrame, function (event) {
41174 _this3.body.eventListeners.onRelease(event);
41175 });
41176 }
41177 /**
41178 * Set a new size for the network
41179 * @param {string} width Width in pixels or percentage (for example '800px'
41180 * or '50%')
41181 * @param {string} height Height in pixels or percentage (for example '400px'
41182 * or '30%')
41183 * @returns {boolean}
41184 */
41185
41186 }, {
41187 key: "setSize",
41188 value: function setSize() {
41189 var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.width;
41190 var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.height;
41191 width = this._prepareValue(width);
41192 height = this._prepareValue(height);
41193 var emitEvent = false;
41194 var oldWidth = this.frame.canvas.width;
41195 var oldHeight = this.frame.canvas.height; // update the pixel ratio
41196 //
41197 // NOTE: Comment in following is rather inconsistent; this is the ONLY place in the code
41198 // where it is assumed that the pixel ratio could change at runtime.
41199 // The only way I can think of this happening is a rotating screen or tablet; but then
41200 // there should be a mechanism for reloading the data (TODO: check if this is present).
41201 //
41202 // If the assumption is true (i.e. pixel ratio can change at runtime), then *all* usage
41203 // of pixel ratio must be overhauled for this.
41204 //
41205 // For the time being, I will humor the assumption here, and in the rest of the code assume it is
41206 // constant.
41207
41208 var previousRatio = this.pixelRatio; // we cache this because the camera state storage needs the old value
41209
41210 this._setPixelRatio();
41211
41212 if (width != this.options.width || height != this.options.height || this.frame.style.width != width || this.frame.style.height != height) {
41213 this._getCameraState(previousRatio);
41214
41215 this.frame.style.width = width;
41216 this.frame.style.height = height;
41217 this.frame.canvas.style.width = '100%';
41218 this.frame.canvas.style.height = '100%';
41219 this.frame.canvas.width = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
41220 this.frame.canvas.height = Math.round(this.frame.canvas.clientHeight * this.pixelRatio);
41221 this.options.width = width;
41222 this.options.height = height;
41223 this.canvasViewCenter = {
41224 x: 0.5 * this.frame.clientWidth,
41225 y: 0.5 * this.frame.clientHeight
41226 };
41227 emitEvent = true;
41228 } else {
41229 // this would adapt the width of the canvas to the width from 100% if and only if
41230 // there is a change.
41231 var newWidth = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
41232 var newHeight = Math.round(this.frame.canvas.clientHeight * this.pixelRatio); // store the camera if there is a change in size.
41233
41234 if (this.frame.canvas.width !== newWidth || this.frame.canvas.height !== newHeight) {
41235 this._getCameraState(previousRatio);
41236 }
41237
41238 if (this.frame.canvas.width !== newWidth) {
41239 this.frame.canvas.width = newWidth;
41240 emitEvent = true;
41241 }
41242
41243 if (this.frame.canvas.height !== newHeight) {
41244 this.frame.canvas.height = newHeight;
41245 emitEvent = true;
41246 }
41247 }
41248
41249 if (emitEvent === true) {
41250 this.body.emitter.emit('resize', {
41251 width: Math.round(this.frame.canvas.width / this.pixelRatio),
41252 height: Math.round(this.frame.canvas.height / this.pixelRatio),
41253 oldWidth: Math.round(oldWidth / this.pixelRatio),
41254 oldHeight: Math.round(oldHeight / this.pixelRatio)
41255 }); // restore the camera on change.
41256
41257 this._setCameraState();
41258 } // set initialized so the get and set camera will work from now on.
41259
41260
41261 this.initialized = true;
41262 return emitEvent;
41263 }
41264 /**
41265 *
41266 * @returns {CanvasRenderingContext2D}
41267 */
41268
41269 }, {
41270 key: "getContext",
41271 value: function getContext() {
41272 return this.frame.canvas.getContext("2d");
41273 }
41274 /**
41275 * Determine the pixel ratio for various browsers.
41276 *
41277 * @returns {number}
41278 * @private
41279 */
41280
41281 }, {
41282 key: "_determinePixelRatio",
41283 value: function _determinePixelRatio() {
41284 var ctx = this.getContext();
41285
41286 if (ctx === undefined) {
41287 throw new Error("Could not get canvax context");
41288 }
41289
41290 var numerator = 1;
41291
41292 if (typeof window !== 'undefined') {
41293 // (window !== undefined) doesn't work here!
41294 // Protection during unit tests, where 'window' can be missing
41295 numerator = window.devicePixelRatio || 1;
41296 }
41297
41298 var denominator = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
41299 return numerator / denominator;
41300 }
41301 /**
41302 * Lazy determination of pixel ratio.
41303 *
41304 * @private
41305 */
41306
41307 }, {
41308 key: "_setPixelRatio",
41309 value: function _setPixelRatio() {
41310 this.pixelRatio = this._determinePixelRatio();
41311 }
41312 /**
41313 * Set the transform in the contained context, based on its pixelRatio
41314 */
41315
41316 }, {
41317 key: "setTransform",
41318 value: function setTransform() {
41319 var ctx = this.getContext();
41320
41321 if (ctx === undefined) {
41322 throw new Error("Could not get canvax context");
41323 }
41324
41325 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
41326 }
41327 /**
41328 * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
41329 * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
41330 * @param {number} x
41331 * @returns {number}
41332 * @private
41333 */
41334
41335 }, {
41336 key: "_XconvertDOMtoCanvas",
41337 value: function _XconvertDOMtoCanvas(x) {
41338 return (x - this.body.view.translation.x) / this.body.view.scale;
41339 }
41340 /**
41341 * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
41342 * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
41343 * @param {number} x
41344 * @returns {number}
41345 * @private
41346 */
41347
41348 }, {
41349 key: "_XconvertCanvasToDOM",
41350 value: function _XconvertCanvasToDOM(x) {
41351 return x * this.body.view.scale + this.body.view.translation.x;
41352 }
41353 /**
41354 * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
41355 * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
41356 * @param {number} y
41357 * @returns {number}
41358 * @private
41359 */
41360
41361 }, {
41362 key: "_YconvertDOMtoCanvas",
41363 value: function _YconvertDOMtoCanvas(y) {
41364 return (y - this.body.view.translation.y) / this.body.view.scale;
41365 }
41366 /**
41367 * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
41368 * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
41369 * @param {number} y
41370 * @returns {number}
41371 * @private
41372 */
41373
41374 }, {
41375 key: "_YconvertCanvasToDOM",
41376 value: function _YconvertCanvasToDOM(y) {
41377 return y * this.body.view.scale + this.body.view.translation.y;
41378 }
41379 /**
41380 * @param {point} pos
41381 * @returns {point}
41382 */
41383
41384 }, {
41385 key: "canvasToDOM",
41386 value: function canvasToDOM(pos) {
41387 return {
41388 x: this._XconvertCanvasToDOM(pos.x),
41389 y: this._YconvertCanvasToDOM(pos.y)
41390 };
41391 }
41392 /**
41393 *
41394 * @param {point} pos
41395 * @returns {point}
41396 */
41397
41398 }, {
41399 key: "DOMtoCanvas",
41400 value: function DOMtoCanvas(pos) {
41401 return {
41402 x: this._XconvertDOMtoCanvas(pos.x),
41403 y: this._YconvertDOMtoCanvas(pos.y)
41404 };
41405 }
41406 }]);
41407
41408 return Canvas;
41409 }();
41410
41411 var globalIsFinite = global_1.isFinite; // `Number.isFinite` method
41412 // https://tc39.github.io/ecma262/#sec-number.isfinite
41413
41414 var numberIsFinite = Number.isFinite || function isFinite(it) {
41415 return typeof it == 'number' && globalIsFinite(it);
41416 };
41417
41418 // https://tc39.github.io/ecma262/#sec-number.isfinite
41419
41420 _export({
41421 target: 'Number',
41422 stat: true
41423 }, {
41424 isFinite: numberIsFinite
41425 });
41426
41427 /**
41428 * The view
41429 */
41430
41431 var View =
41432 /*#__PURE__*/
41433 function () {
41434 /**
41435 * @param {Object} body
41436 * @param {Canvas} canvas
41437 */
41438 function View(body, canvas) {
41439 var _this = this;
41440
41441 _classCallCheck(this, View);
41442
41443 this.body = body;
41444 this.canvas = canvas;
41445 this.animationSpeed = 1 / this.renderRefreshRate;
41446 this.animationEasingFunction = "easeInOutQuint";
41447 this.easingTime = 0;
41448 this.sourceScale = 0;
41449 this.targetScale = 0;
41450 this.sourceTranslation = 0;
41451 this.targetTranslation = 0;
41452 this.lockedOnNodeId = undefined;
41453 this.lockedOnNodeOffset = undefined;
41454 this.touchTime = 0;
41455 this.viewFunction = undefined;
41456 this.body.emitter.on("fit", this.fit.bind(this));
41457 this.body.emitter.on("animationFinished", function () {
41458 _this.body.emitter.emit("_stopRendering");
41459 });
41460 this.body.emitter.on("unlockNode", this.releaseNode.bind(this));
41461 }
41462 /**
41463 *
41464 * @param {Object} [options={}]
41465 */
41466
41467
41468 _createClass(View, [{
41469 key: "setOptions",
41470 value: function setOptions() {
41471 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
41472 this.options = options;
41473 }
41474 /**
41475 * This function zooms out to fit all data on screen based on amount of nodes
41476 * @param {Object} [options={{nodes=Array}}]
41477 * @param {boolean} [initialZoom=false] | zoom based on fitted formula or range, true = fitted, default = false;
41478 */
41479
41480 }, {
41481 key: "fit",
41482 value: function fit() {
41483 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
41484 nodes: []
41485 };
41486 var initialZoom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
41487 var range;
41488 var zoomLevel;
41489 options = Object.assign({}, options);
41490
41491 if (options.nodes === undefined || options.nodes.length === 0) {
41492 options.nodes = this.body.nodeIndices;
41493 }
41494
41495 if (initialZoom === true) {
41496 // check if more than half of the nodes have a predefined position. If so, we use the range, not the approximation.
41497 var positionDefined = 0;
41498
41499 for (var nodeId in this.body.nodes) {
41500 if (this.body.nodes.hasOwnProperty(nodeId)) {
41501 var node = this.body.nodes[nodeId];
41502
41503 if (node.predefinedPosition === true) {
41504 positionDefined += 1;
41505 }
41506 }
41507 }
41508
41509 if (positionDefined > 0.5 * this.body.nodeIndices.length) {
41510 this.fit(options, false);
41511 return;
41512 }
41513
41514 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
41515 var numberOfNodes = this.body.nodeIndices.length;
41516 zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
41517 // correct for larger canvasses.
41518
41519 var factor = Math.min(this.canvas.frame.canvas.clientWidth / 600, this.canvas.frame.canvas.clientHeight / 600);
41520 zoomLevel *= factor;
41521 } else {
41522 this.body.emitter.emit("_resizeNodes");
41523 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
41524 var xDistance = Math.abs(range.maxX - range.minX) * 1.1;
41525 var yDistance = Math.abs(range.maxY - range.minY) * 1.1;
41526 var xZoomLevel = this.canvas.frame.canvas.clientWidth / xDistance;
41527 var yZoomLevel = this.canvas.frame.canvas.clientHeight / yDistance;
41528 zoomLevel = xZoomLevel <= yZoomLevel ? xZoomLevel : yZoomLevel;
41529 }
41530
41531 if (zoomLevel > 1.0) {
41532 zoomLevel = 1.0;
41533 } else if (zoomLevel === 0) {
41534 zoomLevel = 1.0;
41535 }
41536
41537 var center = NetworkUtil.findCenter(range);
41538 var animationOptions = {
41539 position: center,
41540 scale: zoomLevel,
41541 animation: options.animation
41542 };
41543 this.moveTo(animationOptions);
41544 } // animation
41545
41546 /**
41547 * Center a node in view.
41548 *
41549 * @param {number} nodeId
41550 * @param {number} [options]
41551 */
41552
41553 }, {
41554 key: "focus",
41555 value: function focus(nodeId) {
41556 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
41557
41558 if (this.body.nodes[nodeId] !== undefined) {
41559 var nodePosition = {
41560 x: this.body.nodes[nodeId].x,
41561 y: this.body.nodes[nodeId].y
41562 };
41563 options.position = nodePosition;
41564 options.lockedOnNode = nodeId;
41565 this.moveTo(options);
41566 } else {
41567 console.log("Node: " + nodeId + " cannot be found.");
41568 }
41569 }
41570 /**
41571 *
41572 * @param {Object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
41573 * | options.scale = number // scale to move to
41574 * | options.position = {x:number, y:number} // position to move to
41575 * | options.animation = {duration:number, easingFunction:String} || Boolean // position to move to
41576 */
41577
41578 }, {
41579 key: "moveTo",
41580 value: function moveTo(options) {
41581 if (options === undefined) {
41582 options = {};
41583 return;
41584 }
41585
41586 if (options.offset != null) {
41587 if (options.offset.x != null) {
41588 // Coerce and verify that x is valid.
41589 options.offset.x = +options.offset.x;
41590
41591 if (!Number.isFinite(options.offset.x)) {
41592 throw new TypeError('The option "offset.x" has to be a finite number.');
41593 }
41594 } else {
41595 options.offset.x = 0;
41596 }
41597
41598 if (options.offset.y != null) {
41599 // Coerce and verify that y is valid.
41600 options.offset.y = +options.offset.y;
41601
41602 if (!Number.isFinite(options.offset.y)) {
41603 throw new TypeError('The option "offset.y" has to be a finite number.');
41604 }
41605 } else {
41606 options.offset.x = 0;
41607 }
41608 } else {
41609 options.offset = {
41610 x: 0,
41611 y: 0
41612 };
41613 }
41614
41615 if (options.position != null) {
41616 if (options.position.x != null) {
41617 // Coerce and verify that x is valid.
41618 options.position.x = +options.position.x;
41619
41620 if (!Number.isFinite(options.position.x)) {
41621 throw new TypeError('The option "position.x" has to be a finite number.');
41622 }
41623 } else {
41624 options.position.x = 0;
41625 }
41626
41627 if (options.position.y != null) {
41628 // Coerce and verify that y is valid.
41629 options.position.y = +options.position.y;
41630
41631 if (!Number.isFinite(options.position.y)) {
41632 throw new TypeError('The option "position.y" has to be a finite number.');
41633 }
41634 } else {
41635 options.position.x = 0;
41636 }
41637 } else {
41638 options.position = this.getViewPosition();
41639 }
41640
41641 if (options.scale != null) {
41642 // Coerce and verify that the scale is valid.
41643 options.scale = +options.scale;
41644
41645 if (!(options.scale > 0)) {
41646 throw new TypeError('The option "scale" has to be a number greater than zero.');
41647 }
41648 } else {
41649 options.scale = this.body.view.scale;
41650 }
41651
41652 if (options.animation === undefined) {
41653 options.animation = {
41654 duration: 0
41655 };
41656 }
41657
41658 if (options.animation === false) {
41659 options.animation = {
41660 duration: 0
41661 };
41662 }
41663
41664 if (options.animation === true) {
41665 options.animation = {};
41666 }
41667
41668 if (options.animation.duration === undefined) {
41669 options.animation.duration = 1000;
41670 } // default duration
41671
41672
41673 if (options.animation.easingFunction === undefined) {
41674 options.animation.easingFunction = "easeInOutQuad";
41675 } // default easing function
41676
41677
41678 this.animateView(options);
41679 }
41680 /**
41681 *
41682 * @param {Object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
41683 * | options.time = number // animation time in milliseconds
41684 * | options.scale = number // scale to animate to
41685 * | options.position = {x:number, y:number} // position to animate to
41686 * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad,
41687 * // easeInCubic, easeOutCubic, easeInOutCubic,
41688 * // easeInQuart, easeOutQuart, easeInOutQuart,
41689 * // easeInQuint, easeOutQuint, easeInOutQuint
41690 */
41691
41692 }, {
41693 key: "animateView",
41694 value: function animateView(options) {
41695 if (options === undefined) {
41696 return;
41697 }
41698
41699 this.animationEasingFunction = options.animation.easingFunction; // release if something focussed on the node
41700
41701 this.releaseNode();
41702
41703 if (options.locked === true) {
41704 this.lockedOnNodeId = options.lockedOnNode;
41705 this.lockedOnNodeOffset = options.offset;
41706 } // forcefully complete the old animation if it was still running
41707
41708
41709 if (this.easingTime != 0) {
41710 this._transitionRedraw(true); // by setting easingtime to 1, we finish the animation.
41711
41712 }
41713
41714 this.sourceScale = this.body.view.scale;
41715 this.sourceTranslation = this.body.view.translation;
41716 this.targetScale = options.scale; // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw
41717 // but at least then we'll have the target transition
41718
41719 this.body.view.scale = this.targetScale;
41720 var viewCenter = this.canvas.DOMtoCanvas({
41721 x: 0.5 * this.canvas.frame.canvas.clientWidth,
41722 y: 0.5 * this.canvas.frame.canvas.clientHeight
41723 });
41724 var distanceFromCenter = {
41725 // offset from view, distance view has to change by these x and y to center the node
41726 x: viewCenter.x - options.position.x,
41727 y: viewCenter.y - options.position.y
41728 };
41729 this.targetTranslation = {
41730 x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x,
41731 y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y
41732 }; // if the time is set to 0, don't do an animation
41733
41734 if (options.animation.duration === 0) {
41735 if (this.lockedOnNodeId != undefined) {
41736 this.viewFunction = this._lockedRedraw.bind(this);
41737 this.body.emitter.on("initRedraw", this.viewFunction);
41738 } else {
41739 this.body.view.scale = this.targetScale;
41740 this.body.view.translation = this.targetTranslation;
41741 this.body.emitter.emit("_requestRedraw");
41742 }
41743 } else {
41744 this.animationSpeed = 1 / (60 * options.animation.duration * 0.001) || 1 / 60; // 60 for 60 seconds, 0.001 for milli's
41745
41746 this.animationEasingFunction = options.animation.easingFunction;
41747 this.viewFunction = this._transitionRedraw.bind(this);
41748 this.body.emitter.on("initRedraw", this.viewFunction);
41749 this.body.emitter.emit("_startRendering");
41750 }
41751 }
41752 /**
41753 * used to animate smoothly by hijacking the redraw function.
41754 * @private
41755 */
41756
41757 }, {
41758 key: "_lockedRedraw",
41759 value: function _lockedRedraw() {
41760 var nodePosition = {
41761 x: this.body.nodes[this.lockedOnNodeId].x,
41762 y: this.body.nodes[this.lockedOnNodeId].y
41763 };
41764 var viewCenter = this.canvas.DOMtoCanvas({
41765 x: 0.5 * this.canvas.frame.canvas.clientWidth,
41766 y: 0.5 * this.canvas.frame.canvas.clientHeight
41767 });
41768 var distanceFromCenter = {
41769 // offset from view, distance view has to change by these x and y to center the node
41770 x: viewCenter.x - nodePosition.x,
41771 y: viewCenter.y - nodePosition.y
41772 };
41773 var sourceTranslation = this.body.view.translation;
41774 var targetTranslation = {
41775 x: sourceTranslation.x + distanceFromCenter.x * this.body.view.scale + this.lockedOnNodeOffset.x,
41776 y: sourceTranslation.y + distanceFromCenter.y * this.body.view.scale + this.lockedOnNodeOffset.y
41777 };
41778 this.body.view.translation = targetTranslation;
41779 }
41780 /**
41781 * Resets state of a locked on Node
41782 */
41783
41784 }, {
41785 key: "releaseNode",
41786 value: function releaseNode() {
41787 if (this.lockedOnNodeId !== undefined && this.viewFunction !== undefined) {
41788 this.body.emitter.off("initRedraw", this.viewFunction);
41789 this.lockedOnNodeId = undefined;
41790 this.lockedOnNodeOffset = undefined;
41791 }
41792 }
41793 /**
41794 * @param {boolean} [finished=false]
41795 * @private
41796 */
41797
41798 }, {
41799 key: "_transitionRedraw",
41800 value: function _transitionRedraw() {
41801 var finished = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
41802 this.easingTime += this.animationSpeed;
41803 this.easingTime = finished === true ? 1.0 : this.easingTime;
41804 var progress = easingFunctions[this.animationEasingFunction](this.easingTime);
41805 this.body.view.scale = this.sourceScale + (this.targetScale - this.sourceScale) * progress;
41806 this.body.view.translation = {
41807 x: this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress,
41808 y: this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress
41809 }; // cleanup
41810
41811 if (this.easingTime >= 1.0) {
41812 this.body.emitter.off("initRedraw", this.viewFunction);
41813 this.easingTime = 0;
41814
41815 if (this.lockedOnNodeId != undefined) {
41816 this.viewFunction = this._lockedRedraw.bind(this);
41817 this.body.emitter.on("initRedraw", this.viewFunction);
41818 }
41819
41820 this.body.emitter.emit("animationFinished");
41821 }
41822 }
41823 /**
41824 *
41825 * @returns {number}
41826 */
41827
41828 }, {
41829 key: "getScale",
41830 value: function getScale() {
41831 return this.body.view.scale;
41832 }
41833 /**
41834 *
41835 * @returns {{x: number, y: number}}
41836 */
41837
41838 }, {
41839 key: "getViewPosition",
41840 value: function getViewPosition() {
41841 return this.canvas.DOMtoCanvas({
41842 x: 0.5 * this.canvas.frame.canvas.clientWidth,
41843 y: 0.5 * this.canvas.frame.canvas.clientHeight
41844 });
41845 }
41846 }]);
41847
41848 return View;
41849 }();
41850
41851 /**
41852 * Navigation Handler
41853 */
41854
41855 var NavigationHandler =
41856 /*#__PURE__*/
41857 function () {
41858 /**
41859 * @param {Object} body
41860 * @param {Canvas} canvas
41861 */
41862 function NavigationHandler(body, canvas) {
41863 var _this = this;
41864
41865 _classCallCheck(this, NavigationHandler);
41866
41867 this.body = body;
41868 this.canvas = canvas;
41869 this.iconsCreated = false;
41870 this.navigationHammers = [];
41871 this.boundFunctions = {};
41872 this.touchTime = 0;
41873 this.activated = false;
41874 this.body.emitter.on("activate", function () {
41875 _this.activated = true;
41876
41877 _this.configureKeyboardBindings();
41878 });
41879 this.body.emitter.on("deactivate", function () {
41880 _this.activated = false;
41881
41882 _this.configureKeyboardBindings();
41883 });
41884 this.body.emitter.on("destroy", function () {
41885 if (_this.keycharm !== undefined) {
41886 _this.keycharm.destroy();
41887 }
41888 });
41889 this.options = {};
41890 }
41891 /**
41892 *
41893 * @param {Object} options
41894 */
41895
41896
41897 _createClass(NavigationHandler, [{
41898 key: "setOptions",
41899 value: function setOptions(options) {
41900 if (options !== undefined) {
41901 this.options = options;
41902 this.create();
41903 }
41904 }
41905 /**
41906 * Creates or refreshes navigation and sets key bindings
41907 */
41908
41909 }, {
41910 key: "create",
41911 value: function create() {
41912 if (this.options.navigationButtons === true) {
41913 if (this.iconsCreated === false) {
41914 this.loadNavigationElements();
41915 }
41916 } else if (this.iconsCreated === true) {
41917 this.cleanNavigation();
41918 }
41919
41920 this.configureKeyboardBindings();
41921 }
41922 /**
41923 * Cleans up previous navigation items
41924 */
41925
41926 }, {
41927 key: "cleanNavigation",
41928 value: function cleanNavigation() {
41929 // clean hammer bindings
41930 if (this.navigationHammers.length != 0) {
41931 for (var i = 0; i < this.navigationHammers.length; i++) {
41932 this.navigationHammers[i].destroy();
41933 }
41934
41935 this.navigationHammers = [];
41936 } // clean up previous navigation items
41937
41938
41939 if (this.navigationDOM && this.navigationDOM['wrapper'] && this.navigationDOM['wrapper'].parentNode) {
41940 this.navigationDOM['wrapper'].parentNode.removeChild(this.navigationDOM['wrapper']);
41941 }
41942
41943 this.iconsCreated = false;
41944 }
41945 /**
41946 * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation
41947 * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent
41948 * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false.
41949 * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas.
41950 *
41951 * @private
41952 */
41953
41954 }, {
41955 key: "loadNavigationElements",
41956 value: function loadNavigationElements() {
41957 var _this2 = this;
41958
41959 this.cleanNavigation();
41960 this.navigationDOM = {};
41961 var navigationDivs = ['up', 'down', 'left', 'right', 'zoomIn', 'zoomOut', 'zoomExtends'];
41962 var navigationDivActions = ['_moveUp', '_moveDown', '_moveLeft', '_moveRight', '_zoomIn', '_zoomOut', '_fit'];
41963 this.navigationDOM['wrapper'] = document.createElement('div');
41964 this.navigationDOM['wrapper'].className = 'vis-navigation';
41965 this.canvas.frame.appendChild(this.navigationDOM['wrapper']);
41966
41967 for (var i = 0; i < navigationDivs.length; i++) {
41968 this.navigationDOM[navigationDivs[i]] = document.createElement('div');
41969 this.navigationDOM[navigationDivs[i]].className = 'vis-button vis-' + navigationDivs[i];
41970 this.navigationDOM['wrapper'].appendChild(this.navigationDOM[navigationDivs[i]]);
41971 var hammer$1 = new hammer(this.navigationDOM[navigationDivs[i]]);
41972
41973 if (navigationDivActions[i] === "_fit") {
41974 hammerUtil.onTouch(hammer$1, this._fit.bind(this));
41975 } else {
41976 hammerUtil.onTouch(hammer$1, this.bindToRedraw.bind(this, navigationDivActions[i]));
41977 }
41978
41979 this.navigationHammers.push(hammer$1);
41980 } // use a hammer for the release so we do not require the one used in the rest of the network
41981 // the one the rest uses can be overloaded by the manipulation system.
41982
41983
41984 var hammerFrame = new hammer(this.canvas.frame);
41985 hammerUtil.onRelease(hammerFrame, function () {
41986 _this2._stopMovement();
41987 });
41988 this.navigationHammers.push(hammerFrame);
41989 this.iconsCreated = true;
41990 }
41991 /**
41992 *
41993 * @param {string} action
41994 */
41995
41996 }, {
41997 key: "bindToRedraw",
41998 value: function bindToRedraw(action) {
41999 if (this.boundFunctions[action] === undefined) {
42000 this.boundFunctions[action] = this[action].bind(this);
42001 this.body.emitter.on("initRedraw", this.boundFunctions[action]);
42002 this.body.emitter.emit("_startRendering");
42003 }
42004 }
42005 /**
42006 *
42007 * @param {string} action
42008 */
42009
42010 }, {
42011 key: "unbindFromRedraw",
42012 value: function unbindFromRedraw(action) {
42013 if (this.boundFunctions[action] !== undefined) {
42014 this.body.emitter.off("initRedraw", this.boundFunctions[action]);
42015 this.body.emitter.emit("_stopRendering");
42016 delete this.boundFunctions[action];
42017 }
42018 }
42019 /**
42020 * this stops all movement induced by the navigation buttons
42021 *
42022 * @private
42023 */
42024
42025 }, {
42026 key: "_fit",
42027 value: function _fit() {
42028 if (new Date().valueOf() - this.touchTime > 700) {
42029 // TODO: fix ugly hack to avoid hammer's double fireing of event (because we use release?)
42030 this.body.emitter.emit("fit", {
42031 duration: 700
42032 });
42033 this.touchTime = new Date().valueOf();
42034 }
42035 }
42036 /**
42037 * this stops all movement induced by the navigation buttons
42038 *
42039 * @private
42040 */
42041
42042 }, {
42043 key: "_stopMovement",
42044 value: function _stopMovement() {
42045 for (var boundAction in this.boundFunctions) {
42046 if (this.boundFunctions.hasOwnProperty(boundAction)) {
42047 this.body.emitter.off("initRedraw", this.boundFunctions[boundAction]);
42048 this.body.emitter.emit("_stopRendering");
42049 }
42050 }
42051
42052 this.boundFunctions = {};
42053 }
42054 /**
42055 *
42056 * @private
42057 */
42058
42059 }, {
42060 key: "_moveUp",
42061 value: function _moveUp() {
42062 this.body.view.translation.y += this.options.keyboard.speed.y;
42063 }
42064 /**
42065 *
42066 * @private
42067 */
42068
42069 }, {
42070 key: "_moveDown",
42071 value: function _moveDown() {
42072 this.body.view.translation.y -= this.options.keyboard.speed.y;
42073 }
42074 /**
42075 *
42076 * @private
42077 */
42078
42079 }, {
42080 key: "_moveLeft",
42081 value: function _moveLeft() {
42082 this.body.view.translation.x += this.options.keyboard.speed.x;
42083 }
42084 /**
42085 *
42086 * @private
42087 */
42088
42089 }, {
42090 key: "_moveRight",
42091 value: function _moveRight() {
42092 this.body.view.translation.x -= this.options.keyboard.speed.x;
42093 }
42094 /**
42095 *
42096 * @private
42097 */
42098
42099 }, {
42100 key: "_zoomIn",
42101 value: function _zoomIn() {
42102 var scaleOld = this.body.view.scale;
42103 var scale = this.body.view.scale * (1 + this.options.keyboard.speed.zoom);
42104 var translation = this.body.view.translation;
42105 var scaleFrac = scale / scaleOld;
42106 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
42107 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
42108 this.body.view.scale = scale;
42109 this.body.view.translation = {
42110 x: tx,
42111 y: ty
42112 };
42113 this.body.emitter.emit('zoom', {
42114 direction: '+',
42115 scale: this.body.view.scale,
42116 pointer: null
42117 });
42118 }
42119 /**
42120 *
42121 * @private
42122 */
42123
42124 }, {
42125 key: "_zoomOut",
42126 value: function _zoomOut() {
42127 var scaleOld = this.body.view.scale;
42128 var scale = this.body.view.scale / (1 + this.options.keyboard.speed.zoom);
42129 var translation = this.body.view.translation;
42130 var scaleFrac = scale / scaleOld;
42131 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
42132 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
42133 this.body.view.scale = scale;
42134 this.body.view.translation = {
42135 x: tx,
42136 y: ty
42137 };
42138 this.body.emitter.emit('zoom', {
42139 direction: '-',
42140 scale: this.body.view.scale,
42141 pointer: null
42142 });
42143 }
42144 /**
42145 * bind all keys using keycharm.
42146 */
42147
42148 }, {
42149 key: "configureKeyboardBindings",
42150 value: function configureKeyboardBindings() {
42151 var _this3 = this;
42152
42153 if (this.keycharm !== undefined) {
42154 this.keycharm.destroy();
42155 }
42156
42157 if (this.options.keyboard.enabled === true) {
42158 if (this.options.keyboard.bindToWindow === true) {
42159 this.keycharm = keycharm({
42160 container: window,
42161 preventDefault: true
42162 });
42163 } else {
42164 this.keycharm = keycharm({
42165 container: this.canvas.frame,
42166 preventDefault: true
42167 });
42168 }
42169
42170 this.keycharm.reset();
42171
42172 if (this.activated === true) {
42173 this.keycharm.bind("up", function () {
42174 _this3.bindToRedraw("_moveUp");
42175 }, "keydown");
42176 this.keycharm.bind("down", function () {
42177 _this3.bindToRedraw("_moveDown");
42178 }, "keydown");
42179 this.keycharm.bind("left", function () {
42180 _this3.bindToRedraw("_moveLeft");
42181 }, "keydown");
42182 this.keycharm.bind("right", function () {
42183 _this3.bindToRedraw("_moveRight");
42184 }, "keydown");
42185 this.keycharm.bind("=", function () {
42186 _this3.bindToRedraw("_zoomIn");
42187 }, "keydown");
42188 this.keycharm.bind("num+", function () {
42189 _this3.bindToRedraw("_zoomIn");
42190 }, "keydown");
42191 this.keycharm.bind("num-", function () {
42192 _this3.bindToRedraw("_zoomOut");
42193 }, "keydown");
42194 this.keycharm.bind("-", function () {
42195 _this3.bindToRedraw("_zoomOut");
42196 }, "keydown");
42197 this.keycharm.bind("[", function () {
42198 _this3.bindToRedraw("_zoomOut");
42199 }, "keydown");
42200 this.keycharm.bind("]", function () {
42201 _this3.bindToRedraw("_zoomIn");
42202 }, "keydown");
42203 this.keycharm.bind("pageup", function () {
42204 _this3.bindToRedraw("_zoomIn");
42205 }, "keydown");
42206 this.keycharm.bind("pagedown", function () {
42207 _this3.bindToRedraw("_zoomOut");
42208 }, "keydown");
42209 this.keycharm.bind("up", function () {
42210 _this3.unbindFromRedraw("_moveUp");
42211 }, "keyup");
42212 this.keycharm.bind("down", function () {
42213 _this3.unbindFromRedraw("_moveDown");
42214 }, "keyup");
42215 this.keycharm.bind("left", function () {
42216 _this3.unbindFromRedraw("_moveLeft");
42217 }, "keyup");
42218 this.keycharm.bind("right", function () {
42219 _this3.unbindFromRedraw("_moveRight");
42220 }, "keyup");
42221 this.keycharm.bind("=", function () {
42222 _this3.unbindFromRedraw("_zoomIn");
42223 }, "keyup");
42224 this.keycharm.bind("num+", function () {
42225 _this3.unbindFromRedraw("_zoomIn");
42226 }, "keyup");
42227 this.keycharm.bind("num-", function () {
42228 _this3.unbindFromRedraw("_zoomOut");
42229 }, "keyup");
42230 this.keycharm.bind("-", function () {
42231 _this3.unbindFromRedraw("_zoomOut");
42232 }, "keyup");
42233 this.keycharm.bind("[", function () {
42234 _this3.unbindFromRedraw("_zoomOut");
42235 }, "keyup");
42236 this.keycharm.bind("]", function () {
42237 _this3.unbindFromRedraw("_zoomIn");
42238 }, "keyup");
42239 this.keycharm.bind("pageup", function () {
42240 _this3.unbindFromRedraw("_zoomIn");
42241 }, "keyup");
42242 this.keycharm.bind("pagedown", function () {
42243 _this3.unbindFromRedraw("_zoomOut");
42244 }, "keyup");
42245 }
42246 }
42247 }
42248 }]);
42249
42250 return NavigationHandler;
42251 }();
42252
42253 /**
42254 * Popup is a class to create a popup window with some text
42255 */
42256
42257 var Popup =
42258 /*#__PURE__*/
42259 function () {
42260 /**
42261 * @param {Element} container The container object.
42262 * @param {string} overflowMethod How the popup should act to overflowing ('flip' or 'cap')
42263 */
42264 function Popup(container, overflowMethod) {
42265 _classCallCheck(this, Popup);
42266
42267 this.container = container;
42268 this.overflowMethod = overflowMethod || 'cap';
42269 this.x = 0;
42270 this.y = 0;
42271 this.padding = 5;
42272 this.hidden = false; // create the frame
42273
42274 this.frame = document.createElement('div');
42275 this.frame.className = 'vis-tooltip';
42276 this.container.appendChild(this.frame);
42277 }
42278 /**
42279 * @param {number} x Horizontal position of the popup window
42280 * @param {number} y Vertical position of the popup window
42281 */
42282
42283
42284 _createClass(Popup, [{
42285 key: "setPosition",
42286 value: function setPosition(x, y) {
42287 this.x = parseInt(x);
42288 this.y = parseInt(y);
42289 }
42290 /**
42291 * Set the content for the popup window. This can be HTML code or text.
42292 * @param {string | Element} content
42293 */
42294
42295 }, {
42296 key: "setText",
42297 value: function setText(content) {
42298 if (content instanceof Element) {
42299 this.frame.innerHTML = '';
42300 this.frame.appendChild(content);
42301 } else {
42302 this.frame.innerHTML = content; // string containing text or HTML
42303 }
42304 }
42305 /**
42306 * Show the popup window
42307 * @param {boolean} [doShow] Show or hide the window
42308 */
42309
42310 }, {
42311 key: "show",
42312 value: function show(doShow) {
42313 if (doShow === undefined) {
42314 doShow = true;
42315 }
42316
42317 if (doShow === true) {
42318 var height = this.frame.clientHeight;
42319 var width = this.frame.clientWidth;
42320 var maxHeight = this.frame.parentNode.clientHeight;
42321 var maxWidth = this.frame.parentNode.clientWidth;
42322 var left = 0,
42323 top = 0;
42324
42325 if (this.overflowMethod == 'flip') {
42326 var isLeft = false,
42327 isTop = true; // Where around the position it's located
42328
42329 if (this.y - height < this.padding) {
42330 isTop = false;
42331 }
42332
42333 if (this.x + width > maxWidth - this.padding) {
42334 isLeft = true;
42335 }
42336
42337 if (isLeft) {
42338 left = this.x - width;
42339 } else {
42340 left = this.x;
42341 }
42342
42343 if (isTop) {
42344 top = this.y - height;
42345 } else {
42346 top = this.y;
42347 }
42348 } else {
42349 top = this.y - height;
42350
42351 if (top + height + this.padding > maxHeight) {
42352 top = maxHeight - height - this.padding;
42353 }
42354
42355 if (top < this.padding) {
42356 top = this.padding;
42357 }
42358
42359 left = this.x;
42360
42361 if (left + width + this.padding > maxWidth) {
42362 left = maxWidth - width - this.padding;
42363 }
42364
42365 if (left < this.padding) {
42366 left = this.padding;
42367 }
42368 }
42369
42370 this.frame.style.left = left + "px";
42371 this.frame.style.top = top + "px";
42372 this.frame.style.visibility = "visible";
42373 this.hidden = false;
42374 } else {
42375 this.hide();
42376 }
42377 }
42378 /**
42379 * Hide the popup window
42380 */
42381
42382 }, {
42383 key: "hide",
42384 value: function hide() {
42385 this.hidden = true;
42386 this.frame.style.left = "0";
42387 this.frame.style.top = "0";
42388 this.frame.style.visibility = "hidden";
42389 }
42390 /**
42391 * Remove the popup window
42392 */
42393
42394 }, {
42395 key: "destroy",
42396 value: function destroy() {
42397 this.frame.parentNode.removeChild(this.frame); // Remove element from DOM
42398 }
42399 }]);
42400
42401 return Popup;
42402 }();
42403
42404 /**
42405 * Handler for interactions
42406 */
42407
42408 var InteractionHandler =
42409 /*#__PURE__*/
42410 function () {
42411 /**
42412 * @param {Object} body
42413 * @param {Canvas} canvas
42414 * @param {SelectionHandler} selectionHandler
42415 */
42416 function InteractionHandler(body, canvas, selectionHandler) {
42417 _classCallCheck(this, InteractionHandler);
42418
42419 this.body = body;
42420 this.canvas = canvas;
42421 this.selectionHandler = selectionHandler;
42422 this.navigationHandler = new NavigationHandler(body, canvas); // bind the events from hammer to functions in this object
42423
42424 this.body.eventListeners.onTap = this.onTap.bind(this);
42425 this.body.eventListeners.onTouch = this.onTouch.bind(this);
42426 this.body.eventListeners.onDoubleTap = this.onDoubleTap.bind(this);
42427 this.body.eventListeners.onHold = this.onHold.bind(this);
42428 this.body.eventListeners.onDragStart = this.onDragStart.bind(this);
42429 this.body.eventListeners.onDrag = this.onDrag.bind(this);
42430 this.body.eventListeners.onDragEnd = this.onDragEnd.bind(this);
42431 this.body.eventListeners.onMouseWheel = this.onMouseWheel.bind(this);
42432 this.body.eventListeners.onPinch = this.onPinch.bind(this);
42433 this.body.eventListeners.onMouseMove = this.onMouseMove.bind(this);
42434 this.body.eventListeners.onRelease = this.onRelease.bind(this);
42435 this.body.eventListeners.onContext = this.onContext.bind(this);
42436 this.touchTime = 0;
42437 this.drag = {};
42438 this.pinch = {};
42439 this.popup = undefined;
42440 this.popupObj = undefined;
42441 this.popupTimer = undefined;
42442 this.body.functions.getPointer = this.getPointer.bind(this);
42443 this.options = {};
42444 this.defaultOptions = {
42445 dragNodes: true,
42446 dragView: true,
42447 hover: false,
42448 keyboard: {
42449 enabled: false,
42450 speed: {
42451 x: 10,
42452 y: 10,
42453 zoom: 0.02
42454 },
42455 bindToWindow: true
42456 },
42457 navigationButtons: false,
42458 tooltipDelay: 300,
42459 zoomView: true,
42460 zoomSpeed: 1
42461 };
42462 extend(this.options, this.defaultOptions);
42463 this.bindEventListeners();
42464 }
42465 /**
42466 * Binds event listeners
42467 */
42468
42469
42470 _createClass(InteractionHandler, [{
42471 key: "bindEventListeners",
42472 value: function bindEventListeners() {
42473 var _this = this;
42474
42475 this.body.emitter.on('destroy', function () {
42476 clearTimeout(_this.popupTimer);
42477 delete _this.body.functions.getPointer;
42478 });
42479 }
42480 /**
42481 *
42482 * @param {Object} options
42483 */
42484
42485 }, {
42486 key: "setOptions",
42487 value: function setOptions(options) {
42488 if (options !== undefined) {
42489 // extend all but the values in fields
42490 var fields = ['hideEdgesOnDrag', 'hideEdgesOnZoom', 'hideNodesOnDrag', 'keyboard', 'multiselect', 'selectable', 'selectConnectedEdges'];
42491 selectiveNotDeepExtend(fields, this.options, options); // merge the keyboard options in.
42492
42493 mergeOptions(this.options, options, 'keyboard');
42494
42495 if (options.tooltip) {
42496 extend(this.options.tooltip, options.tooltip);
42497
42498 if (options.tooltip.color) {
42499 this.options.tooltip.color = parseColor(options.tooltip.color);
42500 }
42501 }
42502 }
42503
42504 this.navigationHandler.setOptions(this.options);
42505 }
42506 /**
42507 * Get the pointer location from a touch location
42508 * @param {{x: number, y: number}} touch
42509 * @return {{x: number, y: number}} pointer
42510 * @private
42511 */
42512
42513 }, {
42514 key: "getPointer",
42515 value: function getPointer(touch) {
42516 return {
42517 x: touch.x - getAbsoluteLeft(this.canvas.frame.canvas),
42518 y: touch.y - getAbsoluteTop(this.canvas.frame.canvas)
42519 };
42520 }
42521 /**
42522 * On start of a touch gesture, store the pointer
42523 * @param {Event} event The event
42524 * @private
42525 */
42526
42527 }, {
42528 key: "onTouch",
42529 value: function onTouch(event) {
42530 if (new Date().valueOf() - this.touchTime > 50) {
42531 this.drag.pointer = this.getPointer(event.center);
42532 this.drag.pinched = false;
42533 this.pinch.scale = this.body.view.scale; // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
42534
42535 this.touchTime = new Date().valueOf();
42536 }
42537 }
42538 /**
42539 * handle tap/click event: select/unselect a node
42540 * @param {Event} event
42541 * @private
42542 */
42543
42544 }, {
42545 key: "onTap",
42546 value: function onTap(event) {
42547 var pointer = this.getPointer(event.center);
42548 var multiselect = this.selectionHandler.options.multiselect && (event.changedPointers[0].ctrlKey || event.changedPointers[0].metaKey);
42549 this.checkSelectionChanges(pointer, event, multiselect);
42550
42551 this.selectionHandler._generateClickEvent('click', event, pointer);
42552 }
42553 /**
42554 * handle doubletap event
42555 * @param {Event} event
42556 * @private
42557 */
42558
42559 }, {
42560 key: "onDoubleTap",
42561 value: function onDoubleTap(event) {
42562 var pointer = this.getPointer(event.center);
42563
42564 this.selectionHandler._generateClickEvent('doubleClick', event, pointer);
42565 }
42566 /**
42567 * handle long tap event: multi select nodes
42568 * @param {Event} event
42569 * @private
42570 */
42571
42572 }, {
42573 key: "onHold",
42574 value: function onHold(event) {
42575 var pointer = this.getPointer(event.center);
42576 var multiselect = this.selectionHandler.options.multiselect;
42577 this.checkSelectionChanges(pointer, event, multiselect);
42578
42579 this.selectionHandler._generateClickEvent('click', event, pointer);
42580
42581 this.selectionHandler._generateClickEvent('hold', event, pointer);
42582 }
42583 /**
42584 * handle the release of the screen
42585 *
42586 * @param {Event} event
42587 * @private
42588 */
42589
42590 }, {
42591 key: "onRelease",
42592 value: function onRelease(event) {
42593 if (new Date().valueOf() - this.touchTime > 10) {
42594 var pointer = this.getPointer(event.center);
42595
42596 this.selectionHandler._generateClickEvent('release', event, pointer); // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
42597
42598
42599 this.touchTime = new Date().valueOf();
42600 }
42601 }
42602 /**
42603 *
42604 * @param {Event} event
42605 */
42606
42607 }, {
42608 key: "onContext",
42609 value: function onContext(event) {
42610 var pointer = this.getPointer({
42611 x: event.clientX,
42612 y: event.clientY
42613 });
42614
42615 this.selectionHandler._generateClickEvent('oncontext', event, pointer);
42616 }
42617 /**
42618 * Select and deselect nodes depending current selection change.
42619 *
42620 * For changing nodes, select/deselect events are fired.
42621 *
42622 * NOTE: For a given edge, if one connecting node is deselected and with the same
42623 * click the other node is selected, no events for the edge will fire.
42624 * It was selected and it will remain selected.
42625 *
42626 * TODO: This is all SelectionHandler calls; the method should be moved to there.
42627 *
42628 * @param {{x: number, y: number}} pointer
42629 * @param {Event} event
42630 * @param {boolean} [add=false]
42631 */
42632
42633 }, {
42634 key: "checkSelectionChanges",
42635 value: function checkSelectionChanges(pointer, event) {
42636 var add = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
42637 var previousSelection = this.selectionHandler.getSelection();
42638 var selected = false;
42639
42640 if (add === true) {
42641 selected = this.selectionHandler.selectAdditionalOnPoint(pointer);
42642 } else {
42643 selected = this.selectionHandler.selectOnPoint(pointer);
42644 }
42645
42646 var currentSelection = this.selectionHandler.getSelection(); // See NOTE in method comment for the reason to do it like this
42647
42648 var deselectedItems = this._determineDifference(previousSelection, currentSelection);
42649
42650 var selectedItems = this._determineDifference(currentSelection, previousSelection);
42651
42652 if (deselectedItems.edges.length > 0) {
42653 this.selectionHandler._generateClickEvent('deselectEdge', event, pointer, previousSelection);
42654
42655 selected = true;
42656 }
42657
42658 if (deselectedItems.nodes.length > 0) {
42659 this.selectionHandler._generateClickEvent('deselectNode', event, pointer, previousSelection);
42660
42661 selected = true;
42662 }
42663
42664 if (selectedItems.nodes.length > 0) {
42665 this.selectionHandler._generateClickEvent('selectNode', event, pointer);
42666
42667 selected = true;
42668 }
42669
42670 if (selectedItems.edges.length > 0) {
42671 this.selectionHandler._generateClickEvent('selectEdge', event, pointer);
42672
42673 selected = true;
42674 } // fire the select event if anything has been selected or deselected
42675
42676
42677 if (selected === true) {
42678 // select or unselect
42679 this.selectionHandler._generateClickEvent('select', event, pointer);
42680 }
42681 }
42682 /**
42683 * Remove all node and edge id's from the first set that are present in the second one.
42684 *
42685 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} firstSet
42686 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} secondSet
42687 * @returns {{nodes: Array.<Node>, edges: Array.<vis.Edge>}}
42688 * @private
42689 */
42690
42691 }, {
42692 key: "_determineDifference",
42693 value: function _determineDifference(firstSet, secondSet) {
42694 var arrayDiff = function arrayDiff(firstArr, secondArr) {
42695 var result = [];
42696
42697 for (var i = 0; i < firstArr.length; i++) {
42698 var value = firstArr[i];
42699
42700 if (secondArr.indexOf(value) === -1) {
42701 result.push(value);
42702 }
42703 }
42704
42705 return result;
42706 };
42707
42708 return {
42709 nodes: arrayDiff(firstSet.nodes, secondSet.nodes),
42710 edges: arrayDiff(firstSet.edges, secondSet.edges)
42711 };
42712 }
42713 /**
42714 * This function is called by onDragStart.
42715 * It is separated out because we can then overload it for the datamanipulation system.
42716 *
42717 * @param {Event} event
42718 * @private
42719 */
42720
42721 }, {
42722 key: "onDragStart",
42723 value: function onDragStart(event) {
42724 //in case the touch event was triggered on an external div, do the initial touch now.
42725 if (this.drag.pointer === undefined) {
42726 this.onTouch(event);
42727 } // note: drag.pointer is set in onTouch to get the initial touch location
42728
42729
42730 var node = this.selectionHandler.getNodeAt(this.drag.pointer);
42731 this.drag.dragging = true;
42732 this.drag.selection = [];
42733 this.drag.translation = extend({}, this.body.view.translation); // copy the object
42734
42735 this.drag.nodeId = undefined;
42736
42737 if (node !== undefined && this.options.dragNodes === true) {
42738 this.drag.nodeId = node.id; // select the clicked node if not yet selected
42739
42740 if (node.isSelected() === false) {
42741 this.selectionHandler.unselectAll();
42742 this.selectionHandler.selectObject(node);
42743 } // after select to contain the node
42744
42745
42746 this.selectionHandler._generateClickEvent('dragStart', event, this.drag.pointer);
42747
42748 var selection = this.selectionHandler.selectionObj.nodes; // create an array with the selected nodes and their original location and status
42749
42750 for (var nodeId in selection) {
42751 if (selection.hasOwnProperty(nodeId)) {
42752 var object = selection[nodeId];
42753 var s = {
42754 id: object.id,
42755 node: object,
42756 // store original x, y, xFixed and yFixed, make the node temporarily Fixed
42757 x: object.x,
42758 y: object.y,
42759 xFixed: object.options.fixed.x,
42760 yFixed: object.options.fixed.y
42761 };
42762 object.options.fixed.x = true;
42763 object.options.fixed.y = true;
42764 this.drag.selection.push(s);
42765 }
42766 }
42767 } else {
42768 // fallback if no node is selected and thus the view is dragged.
42769 this.selectionHandler._generateClickEvent('dragStart', event, this.drag.pointer, undefined, true);
42770 }
42771 }
42772 /**
42773 * handle drag event
42774 * @param {Event} event
42775 * @private
42776 */
42777
42778 }, {
42779 key: "onDrag",
42780 value: function onDrag(event) {
42781 var _this2 = this;
42782
42783 if (this.drag.pinched === true) {
42784 return;
42785 } // remove the focus on node if it is focussed on by the focusOnNode
42786
42787
42788 this.body.emitter.emit('unlockNode');
42789 var pointer = this.getPointer(event.center);
42790 var selection = this.drag.selection;
42791
42792 if (selection && selection.length && this.options.dragNodes === true) {
42793 this.selectionHandler._generateClickEvent('dragging', event, pointer); // calculate delta's and new location
42794
42795
42796 var deltaX = pointer.x - this.drag.pointer.x;
42797 var deltaY = pointer.y - this.drag.pointer.y; // update position of all selected nodes
42798
42799 selection.forEach(function (selection) {
42800 var node = selection.node; // only move the node if it was not fixed initially
42801
42802 if (selection.xFixed === false) {
42803 node.x = _this2.canvas._XconvertDOMtoCanvas(_this2.canvas._XconvertCanvasToDOM(selection.x) + deltaX);
42804 } // only move the node if it was not fixed initially
42805
42806
42807 if (selection.yFixed === false) {
42808 node.y = _this2.canvas._YconvertDOMtoCanvas(_this2.canvas._YconvertCanvasToDOM(selection.y) + deltaY);
42809 }
42810 }); // start the simulation of the physics
42811
42812 this.body.emitter.emit('startSimulation');
42813 } else {
42814 // move the network
42815 if (this.options.dragView === true) {
42816 this.selectionHandler._generateClickEvent('dragging', event, pointer, undefined, true); // if the drag was not started properly because the click started outside the network div, start it now.
42817
42818
42819 if (this.drag.pointer === undefined) {
42820 this.onDragStart(event);
42821 return;
42822 }
42823
42824 var diffX = pointer.x - this.drag.pointer.x;
42825 var diffY = pointer.y - this.drag.pointer.y;
42826 this.body.view.translation = {
42827 x: this.drag.translation.x + diffX,
42828 y: this.drag.translation.y + diffY
42829 };
42830 this.body.emitter.emit('_requestRedraw');
42831 }
42832 }
42833 }
42834 /**
42835 * handle drag start event
42836 * @param {Event} event
42837 * @private
42838 */
42839
42840 }, {
42841 key: "onDragEnd",
42842 value: function onDragEnd(event) {
42843 this.drag.dragging = false;
42844 var selection = this.drag.selection;
42845
42846 if (selection && selection.length) {
42847 selection.forEach(function (s) {
42848 // restore original xFixed and yFixed
42849 s.node.options.fixed.x = s.xFixed;
42850 s.node.options.fixed.y = s.yFixed;
42851 });
42852
42853 this.selectionHandler._generateClickEvent('dragEnd', event, this.getPointer(event.center));
42854
42855 this.body.emitter.emit('startSimulation');
42856 } else {
42857 this.selectionHandler._generateClickEvent('dragEnd', event, this.getPointer(event.center), undefined, true);
42858
42859 this.body.emitter.emit('_requestRedraw');
42860 }
42861 }
42862 /**
42863 * Handle pinch event
42864 * @param {Event} event The event
42865 * @private
42866 */
42867
42868 }, {
42869 key: "onPinch",
42870 value: function onPinch(event) {
42871 var pointer = this.getPointer(event.center);
42872 this.drag.pinched = true;
42873
42874 if (this.pinch['scale'] === undefined) {
42875 this.pinch.scale = 1;
42876 } // TODO: enabled moving while pinching?
42877
42878
42879 var scale = this.pinch.scale * event.scale;
42880 this.zoom(scale, pointer);
42881 }
42882 /**
42883 * Zoom the network in or out
42884 * @param {number} scale a number around 1, and between 0.01 and 10
42885 * @param {{x: number, y: number}} pointer Position on screen
42886 * @private
42887 */
42888
42889 }, {
42890 key: "zoom",
42891 value: function zoom(scale, pointer) {
42892 if (this.options.zoomView === true) {
42893 var scaleOld = this.body.view.scale;
42894
42895 if (scale < 0.00001) {
42896 scale = 0.00001;
42897 }
42898
42899 if (scale > 10) {
42900 scale = 10;
42901 }
42902
42903 var preScaleDragPointer = undefined;
42904
42905 if (this.drag !== undefined) {
42906 if (this.drag.dragging === true) {
42907 preScaleDragPointer = this.canvas.DOMtoCanvas(this.drag.pointer);
42908 }
42909 } // + this.canvas.frame.canvas.clientHeight / 2
42910
42911
42912 var translation = this.body.view.translation;
42913 var scaleFrac = scale / scaleOld;
42914 var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
42915 var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
42916 this.body.view.scale = scale;
42917 this.body.view.translation = {
42918 x: tx,
42919 y: ty
42920 };
42921
42922 if (preScaleDragPointer != undefined) {
42923 var postScaleDragPointer = this.canvas.canvasToDOM(preScaleDragPointer);
42924 this.drag.pointer.x = postScaleDragPointer.x;
42925 this.drag.pointer.y = postScaleDragPointer.y;
42926 }
42927
42928 this.body.emitter.emit('_requestRedraw');
42929
42930 if (scaleOld < scale) {
42931 this.body.emitter.emit('zoom', {
42932 direction: '+',
42933 scale: this.body.view.scale,
42934 pointer: pointer
42935 });
42936 } else {
42937 this.body.emitter.emit('zoom', {
42938 direction: '-',
42939 scale: this.body.view.scale,
42940 pointer: pointer
42941 });
42942 }
42943 }
42944 }
42945 /**
42946 * Event handler for mouse wheel event, used to zoom the timeline
42947 * See http://adomas.org/javascript-mouse-wheel/
42948 * https://github.com/EightMedia/hammer.js/issues/256
42949 * @param {MouseEvent} event
42950 * @private
42951 */
42952
42953 }, {
42954 key: "onMouseWheel",
42955 value: function onMouseWheel(event) {
42956 if (this.options.zoomView === true) {
42957 // If delta is nonzero, handle it.
42958 // Basically, delta is now positive if wheel was scrolled up,
42959 // and negative, if wheel was scrolled down.
42960 if (event.deltaY !== 0) {
42961 // calculate the new scale
42962 var scale = this.body.view.scale;
42963 scale *= 1 + (event.deltaY < 0 ? 1 : -1) * (this.options.zoomSpeed * 0.1); // calculate the pointer location
42964
42965 var pointer = this.getPointer({
42966 x: event.clientX,
42967 y: event.clientY
42968 }); // apply the new scale
42969
42970 this.zoom(scale, pointer);
42971 } // Prevent default actions caused by mouse wheel.
42972
42973
42974 event.preventDefault();
42975 }
42976 }
42977 /**
42978 * Mouse move handler for checking whether the title moves over a node with a title.
42979 * @param {Event} event
42980 * @private
42981 */
42982
42983 }, {
42984 key: "onMouseMove",
42985 value: function onMouseMove(event) {
42986 var _this3 = this;
42987
42988 var pointer = this.getPointer({
42989 x: event.clientX,
42990 y: event.clientY
42991 });
42992 var popupVisible = false; // check if the previously selected node is still selected
42993
42994 if (this.popup !== undefined) {
42995 if (this.popup.hidden === false) {
42996 this._checkHidePopup(pointer);
42997 } // if the popup was not hidden above
42998
42999
43000 if (this.popup.hidden === false) {
43001 popupVisible = true;
43002 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
43003 this.popup.show();
43004 }
43005 } // if we bind the keyboard to the div, we have to highlight it to use it. This highlights it on mouse over.
43006
43007
43008 if (this.options.keyboard.bindToWindow === false && this.options.keyboard.enabled === true) {
43009 this.canvas.frame.focus();
43010 } // start a timeout that will check if the mouse is positioned above an element
43011
43012
43013 if (popupVisible === false) {
43014 if (this.popupTimer !== undefined) {
43015 clearInterval(this.popupTimer); // stop any running calculationTimer
43016
43017 this.popupTimer = undefined;
43018 }
43019
43020 if (!this.drag.dragging) {
43021 this.popupTimer = setTimeout(function () {
43022 return _this3._checkShowPopup(pointer);
43023 }, this.options.tooltipDelay);
43024 }
43025 } // adding hover highlights
43026
43027
43028 if (this.options.hover === true) {
43029 this.selectionHandler.hoverObject(event, pointer);
43030 }
43031 }
43032 /**
43033 * Check if there is an element on the given position in the network
43034 * (a node or edge). If so, and if this element has a title,
43035 * show a popup window with its title.
43036 *
43037 * @param {{x:number, y:number}} pointer
43038 * @private
43039 */
43040
43041 }, {
43042 key: "_checkShowPopup",
43043 value: function _checkShowPopup(pointer) {
43044 var x = this.canvas._XconvertDOMtoCanvas(pointer.x);
43045
43046 var y = this.canvas._YconvertDOMtoCanvas(pointer.y);
43047
43048 var pointerObj = {
43049 left: x,
43050 top: y,
43051 right: x,
43052 bottom: y
43053 };
43054 var previousPopupObjId = this.popupObj === undefined ? undefined : this.popupObj.id;
43055 var nodeUnderCursor = false;
43056 var popupType = 'node'; // check if a node is under the cursor.
43057
43058 if (this.popupObj === undefined) {
43059 // search the nodes for overlap, select the top one in case of multiple nodes
43060 var nodeIndices = this.body.nodeIndices;
43061 var nodes = this.body.nodes;
43062 var node;
43063 var overlappingNodes = [];
43064
43065 for (var i = 0; i < nodeIndices.length; i++) {
43066 node = nodes[nodeIndices[i]];
43067
43068 if (node.isOverlappingWith(pointerObj) === true) {
43069 nodeUnderCursor = true;
43070
43071 if (node.getTitle() !== undefined) {
43072 overlappingNodes.push(nodeIndices[i]);
43073 }
43074 }
43075 }
43076
43077 if (overlappingNodes.length > 0) {
43078 // if there are overlapping nodes, select the last one, this is the one which is drawn on top of the others
43079 this.popupObj = nodes[overlappingNodes[overlappingNodes.length - 1]]; // if you hover over a node, the title of the edge is not supposed to be shown.
43080
43081 nodeUnderCursor = true;
43082 }
43083 }
43084
43085 if (this.popupObj === undefined && nodeUnderCursor === false) {
43086 // search the edges for overlap
43087 var edgeIndices = this.body.edgeIndices;
43088 var edges = this.body.edges;
43089 var edge;
43090 var overlappingEdges = [];
43091
43092 for (var _i = 0; _i < edgeIndices.length; _i++) {
43093 edge = edges[edgeIndices[_i]];
43094
43095 if (edge.isOverlappingWith(pointerObj) === true) {
43096 if (edge.connected === true && edge.getTitle() !== undefined) {
43097 overlappingEdges.push(edgeIndices[_i]);
43098 }
43099 }
43100 }
43101
43102 if (overlappingEdges.length > 0) {
43103 this.popupObj = edges[overlappingEdges[overlappingEdges.length - 1]];
43104 popupType = 'edge';
43105 }
43106 }
43107
43108 if (this.popupObj !== undefined) {
43109 // show popup message window
43110 if (this.popupObj.id !== previousPopupObjId) {
43111 if (this.popup === undefined) {
43112 this.popup = new Popup(this.canvas.frame);
43113 }
43114
43115 this.popup.popupTargetType = popupType;
43116 this.popup.popupTargetId = this.popupObj.id; // adjust a small offset such that the mouse cursor is located in the
43117 // bottom left location of the popup, and you can easily move over the
43118 // popup area
43119
43120 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
43121 this.popup.setText(this.popupObj.getTitle());
43122 this.popup.show();
43123 this.body.emitter.emit('showPopup', this.popupObj.id);
43124 }
43125 } else {
43126 if (this.popup !== undefined) {
43127 this.popup.hide();
43128 this.body.emitter.emit('hidePopup');
43129 }
43130 }
43131 }
43132 /**
43133 * Check if the popup must be hidden, which is the case when the mouse is no
43134 * longer hovering on the object
43135 * @param {{x:number, y:number}} pointer
43136 * @private
43137 */
43138
43139 }, {
43140 key: "_checkHidePopup",
43141 value: function _checkHidePopup(pointer) {
43142 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
43143
43144 var stillOnObj = false;
43145
43146 if (this.popup.popupTargetType === 'node') {
43147 if (this.body.nodes[this.popup.popupTargetId] !== undefined) {
43148 stillOnObj = this.body.nodes[this.popup.popupTargetId].isOverlappingWith(pointerObj); // if the mouse is still one the node, we have to check if it is not also on one that is drawn on top of it.
43149 // we initially only check stillOnObj because this is much faster.
43150
43151 if (stillOnObj === true) {
43152 var overNode = this.selectionHandler.getNodeAt(pointer);
43153 stillOnObj = overNode === undefined ? false : overNode.id === this.popup.popupTargetId;
43154 }
43155 }
43156 } else {
43157 if (this.selectionHandler.getNodeAt(pointer) === undefined) {
43158 if (this.body.edges[this.popup.popupTargetId] !== undefined) {
43159 stillOnObj = this.body.edges[this.popup.popupTargetId].isOverlappingWith(pointerObj);
43160 }
43161 }
43162 }
43163
43164 if (stillOnObj === false) {
43165 this.popupObj = undefined;
43166 this.popup.hide();
43167 this.body.emitter.emit('hidePopup');
43168 }
43169 }
43170 }]);
43171
43172 return InteractionHandler;
43173 }();
43174
43175 /**
43176 * The handler for selections
43177 */
43178
43179 var SelectionHandler =
43180 /*#__PURE__*/
43181 function () {
43182 /**
43183 * @param {Object} body
43184 * @param {Canvas} canvas
43185 */
43186 function SelectionHandler(body, canvas) {
43187 var _this = this;
43188
43189 _classCallCheck(this, SelectionHandler);
43190
43191 this.body = body;
43192 this.canvas = canvas;
43193 this.selectionObj = {
43194 nodes: [],
43195 edges: []
43196 };
43197 this.hoverObj = {
43198 nodes: {},
43199 edges: {}
43200 };
43201 this.options = {};
43202 this.defaultOptions = {
43203 multiselect: false,
43204 selectable: true,
43205 selectConnectedEdges: true,
43206 hoverConnectedEdges: true
43207 };
43208 extend(this.options, this.defaultOptions);
43209 this.body.emitter.on("_dataChanged", function () {
43210 _this.updateSelection();
43211 });
43212 }
43213 /**
43214 *
43215 * @param {Object} [options]
43216 */
43217
43218
43219 _createClass(SelectionHandler, [{
43220 key: "setOptions",
43221 value: function setOptions(options) {
43222 if (options !== undefined) {
43223 var fields = ['multiselect', 'hoverConnectedEdges', 'selectable', 'selectConnectedEdges'];
43224 selectiveDeepExtend(fields, this.options, options);
43225 }
43226 }
43227 /**
43228 * handles the selection part of the tap;
43229 *
43230 * @param {{x: number, y: number}} pointer
43231 * @returns {boolean}
43232 */
43233
43234 }, {
43235 key: "selectOnPoint",
43236 value: function selectOnPoint(pointer) {
43237 var selected = false;
43238
43239 if (this.options.selectable === true) {
43240 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer); // unselect after getting the objects in order to restore width and height.
43241
43242 this.unselectAll();
43243
43244 if (obj !== undefined) {
43245 selected = this.selectObject(obj);
43246 }
43247
43248 this.body.emitter.emit("_requestRedraw");
43249 }
43250
43251 return selected;
43252 }
43253 /**
43254 *
43255 * @param {{x: number, y: number}} pointer
43256 * @returns {boolean}
43257 */
43258
43259 }, {
43260 key: "selectAdditionalOnPoint",
43261 value: function selectAdditionalOnPoint(pointer) {
43262 var selectionChanged = false;
43263
43264 if (this.options.selectable === true) {
43265 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
43266
43267 if (obj !== undefined) {
43268 selectionChanged = true;
43269
43270 if (obj.isSelected() === true) {
43271 this.deselectObject(obj);
43272 } else {
43273 this.selectObject(obj);
43274 }
43275
43276 this.body.emitter.emit("_requestRedraw");
43277 }
43278 }
43279
43280 return selectionChanged;
43281 }
43282 /**
43283 * Create an object containing the standard fields for an event.
43284 *
43285 * @param {Event} event
43286 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
43287 * @returns {{}}
43288 * @private
43289 */
43290
43291 }, {
43292 key: "_initBaseEvent",
43293 value: function _initBaseEvent(event, pointer) {
43294 var properties = {};
43295 properties['pointer'] = {
43296 DOM: {
43297 x: pointer.x,
43298 y: pointer.y
43299 },
43300 canvas: this.canvas.DOMtoCanvas(pointer)
43301 };
43302 properties['event'] = event;
43303 return properties;
43304 }
43305 /**
43306 * Generate an event which the user can catch.
43307 *
43308 * This adds some extra data to the event with respect to cursor position and
43309 * selected nodes and edges.
43310 *
43311 * @param {string} eventType Name of event to send
43312 * @param {Event} event
43313 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
43314 * @param {Object|undefined} oldSelection If present, selection state before event occured
43315 * @param {boolean|undefined} [emptySelection=false] Indicate if selection data should be passed
43316 */
43317
43318 }, {
43319 key: "_generateClickEvent",
43320 value: function _generateClickEvent(eventType, event, pointer, oldSelection) {
43321 var emptySelection = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
43322
43323 var properties = this._initBaseEvent(event, pointer);
43324
43325 if (emptySelection === true) {
43326 properties.nodes = [];
43327 properties.edges = [];
43328 } else {
43329 var tmp = this.getSelection();
43330 properties.nodes = tmp.nodes;
43331 properties.edges = tmp.edges;
43332 }
43333
43334 if (oldSelection !== undefined) {
43335 properties['previousSelection'] = oldSelection;
43336 }
43337
43338 if (eventType == 'click') {
43339 // For the time being, restrict this functionality to
43340 // just the click event.
43341 properties.items = this.getClickedItems(pointer);
43342 }
43343
43344 if (event.controlEdge !== undefined) {
43345 properties.controlEdge = event.controlEdge;
43346 }
43347
43348 this.body.emitter.emit(eventType, properties);
43349 }
43350 /**
43351 *
43352 * @param {Object} obj
43353 * @param {boolean} [highlightEdges=this.options.selectConnectedEdges]
43354 * @returns {boolean}
43355 */
43356
43357 }, {
43358 key: "selectObject",
43359 value: function selectObject(obj) {
43360 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.selectConnectedEdges;
43361
43362 if (obj !== undefined) {
43363 if (obj instanceof Node) {
43364 if (highlightEdges === true) {
43365 this._selectConnectedEdges(obj);
43366 }
43367 }
43368
43369 obj.select();
43370
43371 this._addToSelection(obj);
43372
43373 return true;
43374 }
43375
43376 return false;
43377 }
43378 /**
43379 *
43380 * @param {Object} obj
43381 */
43382
43383 }, {
43384 key: "deselectObject",
43385 value: function deselectObject(obj) {
43386 if (obj.isSelected() === true) {
43387 obj.selected = false;
43388
43389 this._removeFromSelection(obj);
43390 }
43391 }
43392 /**
43393 * retrieve all nodes overlapping with given object
43394 * @param {Object} object An object with parameters left, top, right, bottom
43395 * @return {number[]} An array with id's of the overlapping nodes
43396 * @private
43397 */
43398
43399 }, {
43400 key: "_getAllNodesOverlappingWith",
43401 value: function _getAllNodesOverlappingWith(object) {
43402 var overlappingNodes = [];
43403 var nodes = this.body.nodes;
43404
43405 for (var i = 0; i < this.body.nodeIndices.length; i++) {
43406 var nodeId = this.body.nodeIndices[i];
43407
43408 if (nodes[nodeId].isOverlappingWith(object)) {
43409 overlappingNodes.push(nodeId);
43410 }
43411 }
43412
43413 return overlappingNodes;
43414 }
43415 /**
43416 * Return a position object in canvasspace from a single point in screenspace
43417 *
43418 * @param {{x: number, y: number}} pointer
43419 * @returns {{left: number, top: number, right: number, bottom: number}}
43420 * @private
43421 */
43422
43423 }, {
43424 key: "_pointerToPositionObject",
43425 value: function _pointerToPositionObject(pointer) {
43426 var canvasPos = this.canvas.DOMtoCanvas(pointer);
43427 return {
43428 left: canvasPos.x - 1,
43429 top: canvasPos.y + 1,
43430 right: canvasPos.x + 1,
43431 bottom: canvasPos.y - 1
43432 };
43433 }
43434 /**
43435 * Get the top node at the passed point (like a click)
43436 *
43437 * @param {{x: number, y: number}} pointer
43438 * @param {boolean} [returnNode=true]
43439 * @return {Node | undefined} node
43440 */
43441
43442 }, {
43443 key: "getNodeAt",
43444 value: function getNodeAt(pointer) {
43445 var returnNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
43446
43447 // we first check if this is an navigation controls element
43448 var positionObject = this._pointerToPositionObject(pointer);
43449
43450 var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); // if there are overlapping nodes, select the last one, this is the
43451 // one which is drawn on top of the others
43452
43453
43454 if (overlappingNodes.length > 0) {
43455 if (returnNode === true) {
43456 return this.body.nodes[overlappingNodes[overlappingNodes.length - 1]];
43457 } else {
43458 return overlappingNodes[overlappingNodes.length - 1];
43459 }
43460 } else {
43461 return undefined;
43462 }
43463 }
43464 /**
43465 * retrieve all edges overlapping with given object, selector is around center
43466 * @param {Object} object An object with parameters left, top, right, bottom
43467 * @param {number[]} overlappingEdges An array with id's of the overlapping nodes
43468 * @private
43469 */
43470
43471 }, {
43472 key: "_getEdgesOverlappingWith",
43473 value: function _getEdgesOverlappingWith(object, overlappingEdges) {
43474 var edges = this.body.edges;
43475
43476 for (var i = 0; i < this.body.edgeIndices.length; i++) {
43477 var edgeId = this.body.edgeIndices[i];
43478
43479 if (edges[edgeId].isOverlappingWith(object)) {
43480 overlappingEdges.push(edgeId);
43481 }
43482 }
43483 }
43484 /**
43485 * retrieve all nodes overlapping with given object
43486 * @param {Object} object An object with parameters left, top, right, bottom
43487 * @return {number[]} An array with id's of the overlapping nodes
43488 * @private
43489 */
43490
43491 }, {
43492 key: "_getAllEdgesOverlappingWith",
43493 value: function _getAllEdgesOverlappingWith(object) {
43494 var overlappingEdges = [];
43495
43496 this._getEdgesOverlappingWith(object, overlappingEdges);
43497
43498 return overlappingEdges;
43499 }
43500 /**
43501 * Get the edges nearest to the passed point (like a click)
43502 *
43503 * @param {{x: number, y: number}} pointer
43504 * @param {boolean} [returnEdge=true]
43505 * @return {Edge | undefined} node
43506 */
43507
43508 }, {
43509 key: "getEdgeAt",
43510 value: function getEdgeAt(pointer) {
43511 var returnEdge = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
43512 // Iterate over edges, pick closest within 10
43513 var canvasPos = this.canvas.DOMtoCanvas(pointer);
43514 var mindist = 10;
43515 var overlappingEdge = null;
43516 var edges = this.body.edges;
43517
43518 for (var i = 0; i < this.body.edgeIndices.length; i++) {
43519 var edgeId = this.body.edgeIndices[i];
43520 var edge = edges[edgeId];
43521
43522 if (edge.connected) {
43523 var xFrom = edge.from.x;
43524 var yFrom = edge.from.y;
43525 var xTo = edge.to.x;
43526 var yTo = edge.to.y;
43527 var dist = edge.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, canvasPos.x, canvasPos.y);
43528
43529 if (dist < mindist) {
43530 overlappingEdge = edgeId;
43531 mindist = dist;
43532 }
43533 }
43534 }
43535
43536 if (overlappingEdge !== null) {
43537 if (returnEdge === true) {
43538 return this.body.edges[overlappingEdge];
43539 } else {
43540 return overlappingEdge;
43541 }
43542 } else {
43543 return undefined;
43544 }
43545 }
43546 /**
43547 * Add object to the selection array.
43548 *
43549 * @param {Object} obj
43550 * @private
43551 */
43552
43553 }, {
43554 key: "_addToSelection",
43555 value: function _addToSelection(obj) {
43556 if (obj instanceof Node) {
43557 this.selectionObj.nodes[obj.id] = obj;
43558 } else {
43559 this.selectionObj.edges[obj.id] = obj;
43560 }
43561 }
43562 /**
43563 * Add object to the selection array.
43564 *
43565 * @param {Object} obj
43566 * @private
43567 */
43568
43569 }, {
43570 key: "_addToHover",
43571 value: function _addToHover(obj) {
43572 if (obj instanceof Node) {
43573 this.hoverObj.nodes[obj.id] = obj;
43574 } else {
43575 this.hoverObj.edges[obj.id] = obj;
43576 }
43577 }
43578 /**
43579 * Remove a single option from selection.
43580 *
43581 * @param {Object} obj
43582 * @private
43583 */
43584
43585 }, {
43586 key: "_removeFromSelection",
43587 value: function _removeFromSelection(obj) {
43588 if (obj instanceof Node) {
43589 delete this.selectionObj.nodes[obj.id];
43590
43591 this._unselectConnectedEdges(obj);
43592 } else {
43593 delete this.selectionObj.edges[obj.id];
43594 }
43595 }
43596 /**
43597 * Unselect all. The selectionObj is useful for this.
43598 */
43599
43600 }, {
43601 key: "unselectAll",
43602 value: function unselectAll() {
43603 for (var nodeId in this.selectionObj.nodes) {
43604 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43605 this.selectionObj.nodes[nodeId].unselect();
43606 }
43607 }
43608
43609 for (var edgeId in this.selectionObj.edges) {
43610 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43611 this.selectionObj.edges[edgeId].unselect();
43612 }
43613 }
43614
43615 this.selectionObj = {
43616 nodes: {},
43617 edges: {}
43618 };
43619 }
43620 /**
43621 * return the number of selected nodes
43622 *
43623 * @returns {number}
43624 * @private
43625 */
43626
43627 }, {
43628 key: "_getSelectedNodeCount",
43629 value: function _getSelectedNodeCount() {
43630 var count = 0;
43631
43632 for (var nodeId in this.selectionObj.nodes) {
43633 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43634 count += 1;
43635 }
43636 }
43637
43638 return count;
43639 }
43640 /**
43641 * return the selected node
43642 *
43643 * @returns {number}
43644 * @private
43645 */
43646
43647 }, {
43648 key: "_getSelectedNode",
43649 value: function _getSelectedNode() {
43650 for (var nodeId in this.selectionObj.nodes) {
43651 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43652 return this.selectionObj.nodes[nodeId];
43653 }
43654 }
43655
43656 return undefined;
43657 }
43658 /**
43659 * return the selected edge
43660 *
43661 * @returns {number}
43662 * @private
43663 */
43664
43665 }, {
43666 key: "_getSelectedEdge",
43667 value: function _getSelectedEdge() {
43668 for (var edgeId in this.selectionObj.edges) {
43669 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43670 return this.selectionObj.edges[edgeId];
43671 }
43672 }
43673
43674 return undefined;
43675 }
43676 /**
43677 * return the number of selected edges
43678 *
43679 * @returns {number}
43680 * @private
43681 */
43682
43683 }, {
43684 key: "_getSelectedEdgeCount",
43685 value: function _getSelectedEdgeCount() {
43686 var count = 0;
43687
43688 for (var edgeId in this.selectionObj.edges) {
43689 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43690 count += 1;
43691 }
43692 }
43693
43694 return count;
43695 }
43696 /**
43697 * return the number of selected objects.
43698 *
43699 * @returns {number}
43700 * @private
43701 */
43702
43703 }, {
43704 key: "_getSelectedObjectCount",
43705 value: function _getSelectedObjectCount() {
43706 var count = 0;
43707
43708 for (var nodeId in this.selectionObj.nodes) {
43709 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43710 count += 1;
43711 }
43712 }
43713
43714 for (var edgeId in this.selectionObj.edges) {
43715 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43716 count += 1;
43717 }
43718 }
43719
43720 return count;
43721 }
43722 /**
43723 * Check if anything is selected
43724 *
43725 * @returns {boolean}
43726 * @private
43727 */
43728
43729 }, {
43730 key: "_selectionIsEmpty",
43731 value: function _selectionIsEmpty() {
43732 for (var nodeId in this.selectionObj.nodes) {
43733 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43734 return false;
43735 }
43736 }
43737
43738 for (var edgeId in this.selectionObj.edges) {
43739 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43740 return false;
43741 }
43742 }
43743
43744 return true;
43745 }
43746 /**
43747 * check if one of the selected nodes is a cluster.
43748 *
43749 * @returns {boolean}
43750 * @private
43751 */
43752
43753 }, {
43754 key: "_clusterInSelection",
43755 value: function _clusterInSelection() {
43756 for (var nodeId in this.selectionObj.nodes) {
43757 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43758 if (this.selectionObj.nodes[nodeId].clusterSize > 1) {
43759 return true;
43760 }
43761 }
43762 }
43763
43764 return false;
43765 }
43766 /**
43767 * select the edges connected to the node that is being selected
43768 *
43769 * @param {Node} node
43770 * @private
43771 */
43772
43773 }, {
43774 key: "_selectConnectedEdges",
43775 value: function _selectConnectedEdges(node) {
43776 for (var i = 0; i < node.edges.length; i++) {
43777 var edge = node.edges[i];
43778 edge.select();
43779
43780 this._addToSelection(edge);
43781 }
43782 }
43783 /**
43784 * select the edges connected to the node that is being selected
43785 *
43786 * @param {Node} node
43787 * @private
43788 */
43789
43790 }, {
43791 key: "_hoverConnectedEdges",
43792 value: function _hoverConnectedEdges(node) {
43793 for (var i = 0; i < node.edges.length; i++) {
43794 var edge = node.edges[i];
43795 edge.hover = true;
43796
43797 this._addToHover(edge);
43798 }
43799 }
43800 /**
43801 * unselect the edges connected to the node that is being selected
43802 *
43803 * @param {Node} node
43804 * @private
43805 */
43806
43807 }, {
43808 key: "_unselectConnectedEdges",
43809 value: function _unselectConnectedEdges(node) {
43810 for (var i = 0; i < node.edges.length; i++) {
43811 var edge = node.edges[i];
43812 edge.unselect();
43813
43814 this._removeFromSelection(edge);
43815 }
43816 }
43817 /**
43818 * Remove the highlight from a node or edge, in response to mouse movement
43819 *
43820 * @param {Event} event
43821 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
43822 * @param {Node|vis.Edge} object
43823 * @private
43824 */
43825
43826 }, {
43827 key: "emitBlurEvent",
43828 value: function emitBlurEvent(event, pointer, object) {
43829 var properties = this._initBaseEvent(event, pointer);
43830
43831 if (object.hover === true) {
43832 object.hover = false;
43833
43834 if (object instanceof Node) {
43835 properties.node = object.id;
43836 this.body.emitter.emit("blurNode", properties);
43837 } else {
43838 properties.edge = object.id;
43839 this.body.emitter.emit("blurEdge", properties);
43840 }
43841 }
43842 }
43843 /**
43844 * Create the highlight for a node or edge, in response to mouse movement
43845 *
43846 * @param {Event} event
43847 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
43848 * @param {Node|vis.Edge} object
43849 * @returns {boolean} hoverChanged
43850 * @private
43851 */
43852
43853 }, {
43854 key: "emitHoverEvent",
43855 value: function emitHoverEvent(event, pointer, object) {
43856 var properties = this._initBaseEvent(event, pointer);
43857
43858 var hoverChanged = false;
43859
43860 if (object.hover === false) {
43861 object.hover = true;
43862
43863 this._addToHover(object);
43864
43865 hoverChanged = true;
43866
43867 if (object instanceof Node) {
43868 properties.node = object.id;
43869 this.body.emitter.emit("hoverNode", properties);
43870 } else {
43871 properties.edge = object.id;
43872 this.body.emitter.emit("hoverEdge", properties);
43873 }
43874 }
43875
43876 return hoverChanged;
43877 }
43878 /**
43879 * Perform actions in response to a mouse movement.
43880 *
43881 * @param {Event} event
43882 * @param {{x: number, y: number}} pointer | object with the x and y screen coordinates of the mouse
43883 */
43884
43885 }, {
43886 key: "hoverObject",
43887 value: function hoverObject(event, pointer) {
43888 var object = this.getNodeAt(pointer);
43889
43890 if (object === undefined) {
43891 object = this.getEdgeAt(pointer);
43892 }
43893
43894 var hoverChanged = false; // remove all node hover highlights
43895
43896 for (var nodeId in this.hoverObj.nodes) {
43897 if (this.hoverObj.nodes.hasOwnProperty(nodeId)) {
43898 if (object === undefined || object instanceof Node && object.id != nodeId || object instanceof Edge) {
43899 this.emitBlurEvent(event, pointer, this.hoverObj.nodes[nodeId]);
43900 delete this.hoverObj.nodes[nodeId];
43901 hoverChanged = true;
43902 }
43903 }
43904 } // removing all edge hover highlights
43905
43906
43907 for (var edgeId in this.hoverObj.edges) {
43908 if (this.hoverObj.edges.hasOwnProperty(edgeId)) {
43909 // if the hover has been changed here it means that the node has been hovered over or off
43910 // we then do not use the emitBlurEvent method here.
43911 if (hoverChanged === true) {
43912 this.hoverObj.edges[edgeId].hover = false;
43913 delete this.hoverObj.edges[edgeId];
43914 } // if the blur remains the same and the object is undefined (mouse off) or another
43915 // edge has been hovered, or another node has been hovered we blur the edge.
43916 else if (object === undefined || object instanceof Edge && object.id != edgeId || object instanceof Node && !object.hover) {
43917 this.emitBlurEvent(event, pointer, this.hoverObj.edges[edgeId]);
43918 delete this.hoverObj.edges[edgeId];
43919 hoverChanged = true;
43920 }
43921 }
43922 }
43923
43924 if (object !== undefined) {
43925 var hoveredEdgesCount = Object.keys(this.hoverObj.edges).length;
43926 var hoveredNodesCount = Object.keys(this.hoverObj.nodes).length;
43927 var newOnlyHoveredEdge = object instanceof Edge && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
43928 var newOnlyHoveredNode = object instanceof Node && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
43929
43930 if (hoverChanged || newOnlyHoveredEdge || newOnlyHoveredNode) {
43931 hoverChanged = this.emitHoverEvent(event, pointer, object);
43932 }
43933
43934 if (object instanceof Node && this.options.hoverConnectedEdges === true) {
43935 this._hoverConnectedEdges(object);
43936 }
43937 }
43938
43939 if (hoverChanged === true) {
43940 this.body.emitter.emit('_requestRedraw');
43941 }
43942 }
43943 /**
43944 *
43945 * retrieve the currently selected objects
43946 * @return {{nodes: Array.<string>, edges: Array.<string>}} selection
43947 */
43948
43949 }, {
43950 key: "getSelection",
43951 value: function getSelection() {
43952 var nodeIds = this.getSelectedNodes();
43953 var edgeIds = this.getSelectedEdges();
43954 return {
43955 nodes: nodeIds,
43956 edges: edgeIds
43957 };
43958 }
43959 /**
43960 *
43961 * retrieve the currently selected nodes
43962 * @return {string[]} selection An array with the ids of the
43963 * selected nodes.
43964 */
43965
43966 }, {
43967 key: "getSelectedNodes",
43968 value: function getSelectedNodes() {
43969 var idArray = [];
43970
43971 if (this.options.selectable === true) {
43972 for (var nodeId in this.selectionObj.nodes) {
43973 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43974 idArray.push(this.selectionObj.nodes[nodeId].id);
43975 }
43976 }
43977 }
43978
43979 return idArray;
43980 }
43981 /**
43982 *
43983 * retrieve the currently selected edges
43984 * @return {Array} selection An array with the ids of the
43985 * selected nodes.
43986 */
43987
43988 }, {
43989 key: "getSelectedEdges",
43990 value: function getSelectedEdges() {
43991 var idArray = [];
43992
43993 if (this.options.selectable === true) {
43994 for (var edgeId in this.selectionObj.edges) {
43995 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43996 idArray.push(this.selectionObj.edges[edgeId].id);
43997 }
43998 }
43999 }
44000
44001 return idArray;
44002 }
44003 /**
44004 * Updates the current selection
44005 * @param {{nodes: Array.<string>, edges: Array.<string>}} selection
44006 * @param {Object} options Options
44007 */
44008
44009 }, {
44010 key: "setSelection",
44011 value: function setSelection(selection) {
44012 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
44013 var i, id;
44014 if (!selection || !selection.nodes && !selection.edges) throw 'Selection must be an object with nodes and/or edges properties'; // first unselect any selected node, if option is true or undefined
44015
44016 if (options.unselectAll || options.unselectAll === undefined) {
44017 this.unselectAll();
44018 }
44019
44020 if (selection.nodes) {
44021 for (i = 0; i < selection.nodes.length; i++) {
44022 id = selection.nodes[i];
44023 var node = this.body.nodes[id];
44024
44025 if (!node) {
44026 throw new RangeError('Node with id "' + id + '" not found');
44027 } // don't select edges with it
44028
44029
44030 this.selectObject(node, options.highlightEdges);
44031 }
44032 }
44033
44034 if (selection.edges) {
44035 for (i = 0; i < selection.edges.length; i++) {
44036 id = selection.edges[i];
44037 var edge = this.body.edges[id];
44038
44039 if (!edge) {
44040 throw new RangeError('Edge with id "' + id + '" not found');
44041 }
44042
44043 this.selectObject(edge);
44044 }
44045 }
44046
44047 this.body.emitter.emit('_requestRedraw');
44048 }
44049 /**
44050 * select zero or more nodes with the option to highlight edges
44051 * @param {number[] | string[]} selection An array with the ids of the
44052 * selected nodes.
44053 * @param {boolean} [highlightEdges]
44054 */
44055
44056 }, {
44057 key: "selectNodes",
44058 value: function selectNodes(selection) {
44059 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
44060 if (!selection || selection.length === undefined) throw 'Selection must be an array with ids';
44061 this.setSelection({
44062 nodes: selection
44063 }, {
44064 highlightEdges: highlightEdges
44065 });
44066 }
44067 /**
44068 * select zero or more edges
44069 * @param {number[] | string[]} selection An array with the ids of the
44070 * selected nodes.
44071 */
44072
44073 }, {
44074 key: "selectEdges",
44075 value: function selectEdges(selection) {
44076 if (!selection || selection.length === undefined) throw 'Selection must be an array with ids';
44077 this.setSelection({
44078 edges: selection
44079 });
44080 }
44081 /**
44082 * Validate the selection: remove ids of nodes which no longer exist
44083 * @private
44084 */
44085
44086 }, {
44087 key: "updateSelection",
44088 value: function updateSelection() {
44089 for (var nodeId in this.selectionObj.nodes) {
44090 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
44091 if (!this.body.nodes.hasOwnProperty(nodeId)) {
44092 delete this.selectionObj.nodes[nodeId];
44093 }
44094 }
44095 }
44096
44097 for (var edgeId in this.selectionObj.edges) {
44098 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
44099 if (!this.body.edges.hasOwnProperty(edgeId)) {
44100 delete this.selectionObj.edges[edgeId];
44101 }
44102 }
44103 }
44104 }
44105 /**
44106 * Determine all the visual elements clicked which are on the given point.
44107 *
44108 * All elements are returned; this includes nodes, edges and their labels.
44109 * The order returned is from highest to lowest, i.e. element 0 of the return
44110 * value is the topmost item clicked on.
44111 *
44112 * The return value consists of an array of the following possible elements:
44113 *
44114 * - `{nodeId:number}` - node with given id clicked on
44115 * - `{nodeId:number, labelId:0}` - label of node with given id clicked on
44116 * - `{edgeId:number}` - edge with given id clicked on
44117 * - `{edge:number, labelId:0}` - label of edge with given id clicked on
44118 *
44119 * ## NOTES
44120 *
44121 * - Currently, there is only one label associated with a node or an edge,
44122 * but this is expected to change somewhere in the future.
44123 * - Since there is no z-indexing yet, it is not really possible to set the nodes and
44124 * edges in the correct order. For the time being, nodes come first.
44125 *
44126 * @param {point} pointer mouse position in screen coordinates
44127 * @returns {Array.<nodeClickItem|nodeLabelClickItem|edgeClickItem|edgeLabelClickItem>}
44128 * @private
44129 */
44130
44131 }, {
44132 key: "getClickedItems",
44133 value: function getClickedItems(pointer) {
44134 var point = this.canvas.DOMtoCanvas(pointer);
44135 var items = []; // Note reverse order; we want the topmost clicked items to be first in the array
44136 // Also note that selected nodes are disregarded here; these normally display on top
44137
44138 var nodeIndices = this.body.nodeIndices;
44139 var nodes = this.body.nodes;
44140
44141 for (var i = nodeIndices.length - 1; i >= 0; i--) {
44142 var node = nodes[nodeIndices[i]];
44143 var ret = node.getItemsOnPoint(point);
44144 items.push.apply(items, ret); // Append the return value to the running list.
44145 }
44146
44147 var edgeIndices = this.body.edgeIndices;
44148 var edges = this.body.edges;
44149
44150 for (var _i = edgeIndices.length - 1; _i >= 0; _i--) {
44151 var edge = edges[edgeIndices[_i]];
44152
44153 var _ret = edge.getItemsOnPoint(point);
44154
44155 items.push.apply(items, _ret); // Append the return value to the running list.
44156 }
44157
44158 return items;
44159 }
44160 }]);
44161
44162 return SelectionHandler;
44163 }();
44164
44165 var nativeSort = [].sort;
44166 var test$3 = [1, 2, 3]; // IE8-
44167
44168 var FAILS_ON_UNDEFINED = fails(function () {
44169 test$3.sort(undefined);
44170 }); // V8 bug
44171
44172 var FAILS_ON_NULL = fails(function () {
44173 test$3.sort(null);
44174 }); // Old WebKit
44175
44176 var SLOPPY_METHOD$2 = sloppyArrayMethod('sort');
44177 var FORCED$3 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || SLOPPY_METHOD$2; // `Array.prototype.sort` method
44178 // https://tc39.github.io/ecma262/#sec-array.prototype.sort
44179
44180 _export({
44181 target: 'Array',
44182 proto: true,
44183 forced: FORCED$3
44184 }, {
44185 sort: function sort(comparefn) {
44186 return comparefn === undefined ? nativeSort.call(toObject(this)) : nativeSort.call(toObject(this), aFunction$1(comparefn));
44187 }
44188 });
44189
44190 var timsort = createCommonjsModule(function (module, exports) {
44191 /****
44192 * The MIT License
44193 *
44194 * Copyright (c) 2015 Marco Ziccardi
44195 *
44196 * Permission is hereby granted, free of charge, to any person obtaining a copy
44197 * of this software and associated documentation files (the "Software"), to deal
44198 * in the Software without restriction, including without limitation the rights
44199 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
44200 * copies of the Software, and to permit persons to whom the Software is
44201 * furnished to do so, subject to the following conditions:
44202 *
44203 * The above copyright notice and this permission notice shall be included in
44204 * all copies or substantial portions of the Software.
44205 *
44206 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44207 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44208 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44209 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44210 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44211 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44212 * THE SOFTWARE.
44213 *
44214 ****/
44215 (function (global, factory) {
44216 {
44217 factory(exports);
44218 }
44219 })(commonjsGlobal, function (exports) {
44220
44221 exports.__esModule = true;
44222 exports.sort = sort;
44223
44224 function _classCallCheck(instance, Constructor) {
44225 if (!(instance instanceof Constructor)) {
44226 throw new TypeError('Cannot call a class as a function');
44227 }
44228 }
44229
44230 var DEFAULT_MIN_MERGE = 32;
44231 var DEFAULT_MIN_GALLOPING = 7;
44232 var DEFAULT_TMP_STORAGE_LENGTH = 256;
44233 var POWERS_OF_TEN = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9];
44234
44235 function log10(x) {
44236 if (x < 1e5) {
44237 if (x < 1e2) {
44238 return x < 1e1 ? 0 : 1;
44239 }
44240
44241 if (x < 1e4) {
44242 return x < 1e3 ? 2 : 3;
44243 }
44244
44245 return 4;
44246 }
44247
44248 if (x < 1e7) {
44249 return x < 1e6 ? 5 : 6;
44250 }
44251
44252 if (x < 1e9) {
44253 return x < 1e8 ? 7 : 8;
44254 }
44255
44256 return 9;
44257 }
44258
44259 function alphabeticalCompare(a, b) {
44260 if (a === b) {
44261 return 0;
44262 }
44263
44264 if (~~a === a && ~~b === b) {
44265 if (a === 0 || b === 0) {
44266 return a < b ? -1 : 1;
44267 }
44268
44269 if (a < 0 || b < 0) {
44270 if (b >= 0) {
44271 return -1;
44272 }
44273
44274 if (a >= 0) {
44275 return 1;
44276 }
44277
44278 a = -a;
44279 b = -b;
44280 }
44281
44282 var al = log10(a);
44283 var bl = log10(b);
44284 var t = 0;
44285
44286 if (al < bl) {
44287 a *= POWERS_OF_TEN[bl - al - 1];
44288 b /= 10;
44289 t = -1;
44290 } else if (al > bl) {
44291 b *= POWERS_OF_TEN[al - bl - 1];
44292 a /= 10;
44293 t = 1;
44294 }
44295
44296 if (a === b) {
44297 return t;
44298 }
44299
44300 return a < b ? -1 : 1;
44301 }
44302
44303 var aStr = String(a);
44304 var bStr = String(b);
44305
44306 if (aStr === bStr) {
44307 return 0;
44308 }
44309
44310 return aStr < bStr ? -1 : 1;
44311 }
44312
44313 function minRunLength(n) {
44314 var r = 0;
44315
44316 while (n >= DEFAULT_MIN_MERGE) {
44317 r |= n & 1;
44318 n >>= 1;
44319 }
44320
44321 return n + r;
44322 }
44323
44324 function makeAscendingRun(array, lo, hi, compare) {
44325 var runHi = lo + 1;
44326
44327 if (runHi === hi) {
44328 return 1;
44329 }
44330
44331 if (compare(array[runHi++], array[lo]) < 0) {
44332 while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
44333 runHi++;
44334 }
44335
44336 reverseRun(array, lo, runHi);
44337 } else {
44338 while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
44339 runHi++;
44340 }
44341 }
44342
44343 return runHi - lo;
44344 }
44345
44346 function reverseRun(array, lo, hi) {
44347 hi--;
44348
44349 while (lo < hi) {
44350 var t = array[lo];
44351 array[lo++] = array[hi];
44352 array[hi--] = t;
44353 }
44354 }
44355
44356 function binaryInsertionSort(array, lo, hi, start, compare) {
44357 if (start === lo) {
44358 start++;
44359 }
44360
44361 for (; start < hi; start++) {
44362 var pivot = array[start];
44363 var left = lo;
44364 var right = start;
44365
44366 while (left < right) {
44367 var mid = left + right >>> 1;
44368
44369 if (compare(pivot, array[mid]) < 0) {
44370 right = mid;
44371 } else {
44372 left = mid + 1;
44373 }
44374 }
44375
44376 var n = start - left;
44377
44378 switch (n) {
44379 case 3:
44380 array[left + 3] = array[left + 2];
44381
44382 case 2:
44383 array[left + 2] = array[left + 1];
44384
44385 case 1:
44386 array[left + 1] = array[left];
44387 break;
44388
44389 default:
44390 while (n > 0) {
44391 array[left + n] = array[left + n - 1];
44392 n--;
44393 }
44394
44395 }
44396
44397 array[left] = pivot;
44398 }
44399 }
44400
44401 function gallopLeft(value, array, start, length, hint, compare) {
44402 var lastOffset = 0;
44403 var maxOffset = 0;
44404 var offset = 1;
44405
44406 if (compare(value, array[start + hint]) > 0) {
44407 maxOffset = length - hint;
44408
44409 while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
44410 lastOffset = offset;
44411 offset = (offset << 1) + 1;
44412
44413 if (offset <= 0) {
44414 offset = maxOffset;
44415 }
44416 }
44417
44418 if (offset > maxOffset) {
44419 offset = maxOffset;
44420 }
44421
44422 lastOffset += hint;
44423 offset += hint;
44424 } else {
44425 maxOffset = hint + 1;
44426
44427 while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
44428 lastOffset = offset;
44429 offset = (offset << 1) + 1;
44430
44431 if (offset <= 0) {
44432 offset = maxOffset;
44433 }
44434 }
44435
44436 if (offset > maxOffset) {
44437 offset = maxOffset;
44438 }
44439
44440 var tmp = lastOffset;
44441 lastOffset = hint - offset;
44442 offset = hint - tmp;
44443 }
44444
44445 lastOffset++;
44446
44447 while (lastOffset < offset) {
44448 var m = lastOffset + (offset - lastOffset >>> 1);
44449
44450 if (compare(value, array[start + m]) > 0) {
44451 lastOffset = m + 1;
44452 } else {
44453 offset = m;
44454 }
44455 }
44456
44457 return offset;
44458 }
44459
44460 function gallopRight(value, array, start, length, hint, compare) {
44461 var lastOffset = 0;
44462 var maxOffset = 0;
44463 var offset = 1;
44464
44465 if (compare(value, array[start + hint]) < 0) {
44466 maxOffset = hint + 1;
44467
44468 while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
44469 lastOffset = offset;
44470 offset = (offset << 1) + 1;
44471
44472 if (offset <= 0) {
44473 offset = maxOffset;
44474 }
44475 }
44476
44477 if (offset > maxOffset) {
44478 offset = maxOffset;
44479 }
44480
44481 var tmp = lastOffset;
44482 lastOffset = hint - offset;
44483 offset = hint - tmp;
44484 } else {
44485 maxOffset = length - hint;
44486
44487 while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
44488 lastOffset = offset;
44489 offset = (offset << 1) + 1;
44490
44491 if (offset <= 0) {
44492 offset = maxOffset;
44493 }
44494 }
44495
44496 if (offset > maxOffset) {
44497 offset = maxOffset;
44498 }
44499
44500 lastOffset += hint;
44501 offset += hint;
44502 }
44503
44504 lastOffset++;
44505
44506 while (lastOffset < offset) {
44507 var m = lastOffset + (offset - lastOffset >>> 1);
44508
44509 if (compare(value, array[start + m]) < 0) {
44510 offset = m;
44511 } else {
44512 lastOffset = m + 1;
44513 }
44514 }
44515
44516 return offset;
44517 }
44518
44519 var TimSort = function () {
44520 function TimSort(array, compare) {
44521 _classCallCheck(this, TimSort);
44522
44523 this.array = null;
44524 this.compare = null;
44525 this.minGallop = DEFAULT_MIN_GALLOPING;
44526 this.length = 0;
44527 this.tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
44528 this.stackLength = 0;
44529 this.runStart = null;
44530 this.runLength = null;
44531 this.stackSize = 0;
44532 this.array = array;
44533 this.compare = compare;
44534 this.length = array.length;
44535
44536 if (this.length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
44537 this.tmpStorageLength = this.length >>> 1;
44538 }
44539
44540 this.tmp = new Array(this.tmpStorageLength);
44541 this.stackLength = this.length < 120 ? 5 : this.length < 1542 ? 10 : this.length < 119151 ? 19 : 40;
44542 this.runStart = new Array(this.stackLength);
44543 this.runLength = new Array(this.stackLength);
44544 }
44545
44546 TimSort.prototype.pushRun = function pushRun(runStart, runLength) {
44547 this.runStart[this.stackSize] = runStart;
44548 this.runLength[this.stackSize] = runLength;
44549 this.stackSize += 1;
44550 };
44551
44552 TimSort.prototype.mergeRuns = function mergeRuns() {
44553 while (this.stackSize > 1) {
44554 var n = this.stackSize - 2;
44555
44556 if (n >= 1 && this.runLength[n - 1] <= this.runLength[n] + this.runLength[n + 1] || n >= 2 && this.runLength[n - 2] <= this.runLength[n] + this.runLength[n - 1]) {
44557 if (this.runLength[n - 1] < this.runLength[n + 1]) {
44558 n--;
44559 }
44560 } else if (this.runLength[n] > this.runLength[n + 1]) {
44561 break;
44562 }
44563
44564 this.mergeAt(n);
44565 }
44566 };
44567
44568 TimSort.prototype.forceMergeRuns = function forceMergeRuns() {
44569 while (this.stackSize > 1) {
44570 var n = this.stackSize - 2;
44571
44572 if (n > 0 && this.runLength[n - 1] < this.runLength[n + 1]) {
44573 n--;
44574 }
44575
44576 this.mergeAt(n);
44577 }
44578 };
44579
44580 TimSort.prototype.mergeAt = function mergeAt(i) {
44581 var compare = this.compare;
44582 var array = this.array;
44583 var start1 = this.runStart[i];
44584 var length1 = this.runLength[i];
44585 var start2 = this.runStart[i + 1];
44586 var length2 = this.runLength[i + 1];
44587 this.runLength[i] = length1 + length2;
44588
44589 if (i === this.stackSize - 3) {
44590 this.runStart[i + 1] = this.runStart[i + 2];
44591 this.runLength[i + 1] = this.runLength[i + 2];
44592 }
44593
44594 this.stackSize--;
44595 var k = gallopRight(array[start2], array, start1, length1, 0, compare);
44596 start1 += k;
44597 length1 -= k;
44598
44599 if (length1 === 0) {
44600 return;
44601 }
44602
44603 length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
44604
44605 if (length2 === 0) {
44606 return;
44607 }
44608
44609 if (length1 <= length2) {
44610 this.mergeLow(start1, length1, start2, length2);
44611 } else {
44612 this.mergeHigh(start1, length1, start2, length2);
44613 }
44614 };
44615
44616 TimSort.prototype.mergeLow = function mergeLow(start1, length1, start2, length2) {
44617 var compare = this.compare;
44618 var array = this.array;
44619 var tmp = this.tmp;
44620 var i = 0;
44621
44622 for (i = 0; i < length1; i++) {
44623 tmp[i] = array[start1 + i];
44624 }
44625
44626 var cursor1 = 0;
44627 var cursor2 = start2;
44628 var dest = start1;
44629 array[dest++] = array[cursor2++];
44630
44631 if (--length2 === 0) {
44632 for (i = 0; i < length1; i++) {
44633 array[dest + i] = tmp[cursor1 + i];
44634 }
44635
44636 return;
44637 }
44638
44639 if (length1 === 1) {
44640 for (i = 0; i < length2; i++) {
44641 array[dest + i] = array[cursor2 + i];
44642 }
44643
44644 array[dest + length2] = tmp[cursor1];
44645 return;
44646 }
44647
44648 var minGallop = this.minGallop;
44649
44650 while (true) {
44651 var count1 = 0;
44652 var count2 = 0;
44653 var exit = false;
44654
44655 do {
44656 if (compare(array[cursor2], tmp[cursor1]) < 0) {
44657 array[dest++] = array[cursor2++];
44658 count2++;
44659 count1 = 0;
44660
44661 if (--length2 === 0) {
44662 exit = true;
44663 break;
44664 }
44665 } else {
44666 array[dest++] = tmp[cursor1++];
44667 count1++;
44668 count2 = 0;
44669
44670 if (--length1 === 1) {
44671 exit = true;
44672 break;
44673 }
44674 }
44675 } while ((count1 | count2) < minGallop);
44676
44677 if (exit) {
44678 break;
44679 }
44680
44681 do {
44682 count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
44683
44684 if (count1 !== 0) {
44685 for (i = 0; i < count1; i++) {
44686 array[dest + i] = tmp[cursor1 + i];
44687 }
44688
44689 dest += count1;
44690 cursor1 += count1;
44691 length1 -= count1;
44692
44693 if (length1 <= 1) {
44694 exit = true;
44695 break;
44696 }
44697 }
44698
44699 array[dest++] = array[cursor2++];
44700
44701 if (--length2 === 0) {
44702 exit = true;
44703 break;
44704 }
44705
44706 count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
44707
44708 if (count2 !== 0) {
44709 for (i = 0; i < count2; i++) {
44710 array[dest + i] = array[cursor2 + i];
44711 }
44712
44713 dest += count2;
44714 cursor2 += count2;
44715 length2 -= count2;
44716
44717 if (length2 === 0) {
44718 exit = true;
44719 break;
44720 }
44721 }
44722
44723 array[dest++] = tmp[cursor1++];
44724
44725 if (--length1 === 1) {
44726 exit = true;
44727 break;
44728 }
44729
44730 minGallop--;
44731 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
44732
44733 if (exit) {
44734 break;
44735 }
44736
44737 if (minGallop < 0) {
44738 minGallop = 0;
44739 }
44740
44741 minGallop += 2;
44742 }
44743
44744 this.minGallop = minGallop;
44745
44746 if (minGallop < 1) {
44747 this.minGallop = 1;
44748 }
44749
44750 if (length1 === 1) {
44751 for (i = 0; i < length2; i++) {
44752 array[dest + i] = array[cursor2 + i];
44753 }
44754
44755 array[dest + length2] = tmp[cursor1];
44756 } else if (length1 === 0) {
44757 throw new Error('mergeLow preconditions were not respected');
44758 } else {
44759 for (i = 0; i < length1; i++) {
44760 array[dest + i] = tmp[cursor1 + i];
44761 }
44762 }
44763 };
44764
44765 TimSort.prototype.mergeHigh = function mergeHigh(start1, length1, start2, length2) {
44766 var compare = this.compare;
44767 var array = this.array;
44768 var tmp = this.tmp;
44769 var i = 0;
44770
44771 for (i = 0; i < length2; i++) {
44772 tmp[i] = array[start2 + i];
44773 }
44774
44775 var cursor1 = start1 + length1 - 1;
44776 var cursor2 = length2 - 1;
44777 var dest = start2 + length2 - 1;
44778 var customCursor = 0;
44779 var customDest = 0;
44780 array[dest--] = array[cursor1--];
44781
44782 if (--length1 === 0) {
44783 customCursor = dest - (length2 - 1);
44784
44785 for (i = 0; i < length2; i++) {
44786 array[customCursor + i] = tmp[i];
44787 }
44788
44789 return;
44790 }
44791
44792 if (length2 === 1) {
44793 dest -= length1;
44794 cursor1 -= length1;
44795 customDest = dest + 1;
44796 customCursor = cursor1 + 1;
44797
44798 for (i = length1 - 1; i >= 0; i--) {
44799 array[customDest + i] = array[customCursor + i];
44800 }
44801
44802 array[dest] = tmp[cursor2];
44803 return;
44804 }
44805
44806 var minGallop = this.minGallop;
44807
44808 while (true) {
44809 var count1 = 0;
44810 var count2 = 0;
44811 var exit = false;
44812
44813 do {
44814 if (compare(tmp[cursor2], array[cursor1]) < 0) {
44815 array[dest--] = array[cursor1--];
44816 count1++;
44817 count2 = 0;
44818
44819 if (--length1 === 0) {
44820 exit = true;
44821 break;
44822 }
44823 } else {
44824 array[dest--] = tmp[cursor2--];
44825 count2++;
44826 count1 = 0;
44827
44828 if (--length2 === 1) {
44829 exit = true;
44830 break;
44831 }
44832 }
44833 } while ((count1 | count2) < minGallop);
44834
44835 if (exit) {
44836 break;
44837 }
44838
44839 do {
44840 count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
44841
44842 if (count1 !== 0) {
44843 dest -= count1;
44844 cursor1 -= count1;
44845 length1 -= count1;
44846 customDest = dest + 1;
44847 customCursor = cursor1 + 1;
44848
44849 for (i = count1 - 1; i >= 0; i--) {
44850 array[customDest + i] = array[customCursor + i];
44851 }
44852
44853 if (length1 === 0) {
44854 exit = true;
44855 break;
44856 }
44857 }
44858
44859 array[dest--] = tmp[cursor2--];
44860
44861 if (--length2 === 1) {
44862 exit = true;
44863 break;
44864 }
44865
44866 count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
44867
44868 if (count2 !== 0) {
44869 dest -= count2;
44870 cursor2 -= count2;
44871 length2 -= count2;
44872 customDest = dest + 1;
44873 customCursor = cursor2 + 1;
44874
44875 for (i = 0; i < count2; i++) {
44876 array[customDest + i] = tmp[customCursor + i];
44877 }
44878
44879 if (length2 <= 1) {
44880 exit = true;
44881 break;
44882 }
44883 }
44884
44885 array[dest--] = array[cursor1--];
44886
44887 if (--length1 === 0) {
44888 exit = true;
44889 break;
44890 }
44891
44892 minGallop--;
44893 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
44894
44895 if (exit) {
44896 break;
44897 }
44898
44899 if (minGallop < 0) {
44900 minGallop = 0;
44901 }
44902
44903 minGallop += 2;
44904 }
44905
44906 this.minGallop = minGallop;
44907
44908 if (minGallop < 1) {
44909 this.minGallop = 1;
44910 }
44911
44912 if (length2 === 1) {
44913 dest -= length1;
44914 cursor1 -= length1;
44915 customDest = dest + 1;
44916 customCursor = cursor1 + 1;
44917
44918 for (i = length1 - 1; i >= 0; i--) {
44919 array[customDest + i] = array[customCursor + i];
44920 }
44921
44922 array[dest] = tmp[cursor2];
44923 } else if (length2 === 0) {
44924 throw new Error('mergeHigh preconditions were not respected');
44925 } else {
44926 customCursor = dest - (length2 - 1);
44927
44928 for (i = 0; i < length2; i++) {
44929 array[customCursor + i] = tmp[i];
44930 }
44931 }
44932 };
44933
44934 return TimSort;
44935 }();
44936
44937 function sort(array, compare, lo, hi) {
44938 if (!Array.isArray(array)) {
44939 throw new TypeError('Can only sort arrays');
44940 }
44941
44942 if (!compare) {
44943 compare = alphabeticalCompare;
44944 } else if (typeof compare !== 'function') {
44945 hi = lo;
44946 lo = compare;
44947 compare = alphabeticalCompare;
44948 }
44949
44950 if (!lo) {
44951 lo = 0;
44952 }
44953
44954 if (!hi) {
44955 hi = array.length;
44956 }
44957
44958 var remaining = hi - lo;
44959
44960 if (remaining < 2) {
44961 return;
44962 }
44963
44964 var runLength = 0;
44965
44966 if (remaining < DEFAULT_MIN_MERGE) {
44967 runLength = makeAscendingRun(array, lo, hi, compare);
44968 binaryInsertionSort(array, lo, hi, lo + runLength, compare);
44969 return;
44970 }
44971
44972 var ts = new TimSort(array, compare);
44973 var minRun = minRunLength(remaining);
44974
44975 do {
44976 runLength = makeAscendingRun(array, lo, hi, compare);
44977
44978 if (runLength < minRun) {
44979 var force = remaining;
44980
44981 if (force > minRun) {
44982 force = minRun;
44983 }
44984
44985 binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
44986 runLength = force;
44987 }
44988
44989 ts.pushRun(lo, runLength);
44990 ts.mergeRuns();
44991 remaining -= runLength;
44992 lo += runLength;
44993 } while (remaining !== 0);
44994
44995 ts.forceMergeRuns();
44996 }
44997 });
44998 });
44999 unwrapExports(timsort);
45000
45001 var timsort$1 = timsort;
45002 var timsort_1 = timsort$1.sort;
45003
45004 /**
45005 * Interface definition for direction strategy classes.
45006 *
45007 * This class describes the interface for the Strategy
45008 * pattern classes used to differentiate horizontal and vertical
45009 * direction of hierarchical results.
45010 *
45011 * For a given direction, one coordinate will be 'fixed', meaning that it is
45012 * determined by level.
45013 * The other coordinate is 'unfixed', meaning that the nodes on a given level
45014 * can still move along that coordinate. So:
45015 *
45016 * - `vertical` layout: `x` unfixed, `y` fixed per level
45017 * - `horizontal` layout: `x` fixed per level, `y` unfixed
45018 *
45019 * The local methods are stubs and should be regarded as abstract.
45020 * Derived classes **must** implement all the methods themselves.
45021 *
45022 * @private
45023 */
45024
45025 var DirectionInterface =
45026 /*#__PURE__*/
45027 function () {
45028 function DirectionInterface() {
45029 _classCallCheck(this, DirectionInterface);
45030 }
45031
45032 _createClass(DirectionInterface, [{
45033 key: "abstract",
45034
45035 /** @ignore **/
45036 value: function abstract() {
45037 throw new Error("Can't instantiate abstract class!");
45038 }
45039 /**
45040 * This is a dummy call which is used to suppress the jsdoc errors of type:
45041 *
45042 * "'param' is assigned a value but never used"
45043 *
45044 * @ignore
45045 **/
45046
45047 }, {
45048 key: "fake_use",
45049 value: function fake_use() {} // Do nothing special
45050
45051 /**
45052 * Type to use to translate dynamic curves to, in the case of hierarchical layout.
45053 * Dynamic curves do not work for these.
45054 *
45055 * The value should be perpendicular to the actual direction of the layout.
45056 *
45057 * @return {string} Direction, either 'vertical' or 'horizontal'
45058 */
45059
45060 }, {
45061 key: "curveType",
45062 value: function curveType() {
45063 return this.abstract();
45064 }
45065 /**
45066 * Return the value of the coordinate that is not fixed for this direction.
45067 *
45068 * @param {Node} node The node to read
45069 * @return {number} Value of the unfixed coordinate
45070 */
45071
45072 }, {
45073 key: "getPosition",
45074 value: function getPosition(node) {
45075 this.fake_use(node);
45076 return this.abstract();
45077 }
45078 /**
45079 * Set the value of the coordinate that is not fixed for this direction.
45080 *
45081 * @param {Node} node The node to adjust
45082 * @param {number} position
45083 * @param {number} [level] if specified, the hierarchy level that this node should be fixed to
45084 */
45085
45086 }, {
45087 key: "setPosition",
45088 value: function setPosition(node, position) {
45089 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
45090 this.fake_use(node, position, level);
45091 this.abstract();
45092 }
45093 /**
45094 * Get the width of a tree.
45095 *
45096 * A `tree` here is a subset of nodes within the network which are not connected to other nodes,
45097 * only among themselves. In essence, it is a sub-network.
45098 *
45099 * @param {number} index The index number of a tree
45100 * @return {number} the width of a tree in the view coordinates
45101 */
45102
45103 }, {
45104 key: "getTreeSize",
45105 value: function getTreeSize(index) {
45106 this.fake_use(index);
45107 return this.abstract();
45108 }
45109 /**
45110 * Sort array of nodes on the unfixed coordinates.
45111 *
45112 * **Note:** chrome has non-stable sorting implementation, which
45113 * has a tendency to change the order of the array items,
45114 * even if the custom sort function returns 0.
45115 *
45116 * For this reason, an external sort implementation is used,
45117 * which has the added benefit of being faster than the standard
45118 * platforms implementation. This has been verified on `node.js`,
45119 * `firefox` and `chrome` (all linux).
45120 *
45121 * @param {Array.<Node>} nodeArray array of nodes to sort
45122 */
45123
45124 }, {
45125 key: "sort",
45126 value: function sort(nodeArray) {
45127 this.fake_use(nodeArray);
45128 this.abstract();
45129 }
45130 /**
45131 * Assign the fixed coordinate of the node to the given level
45132 *
45133 * @param {Node} node The node to adjust
45134 * @param {number} level The level to fix to
45135 */
45136
45137 }, {
45138 key: "fix",
45139 value: function fix(node, level) {
45140 this.fake_use(node, level);
45141 this.abstract();
45142 }
45143 /**
45144 * Add an offset to the unfixed coordinate of the given node.
45145 *
45146 * @param {NodeId} nodeId Id of the node to adjust
45147 * @param {number} diff Offset to add to the unfixed coordinate
45148 */
45149
45150 }, {
45151 key: "shift",
45152 value: function shift(nodeId, diff) {
45153 this.fake_use(nodeId, diff);
45154 this.abstract();
45155 }
45156 }]);
45157
45158 return DirectionInterface;
45159 }();
45160 /**
45161 * Vertical Strategy
45162 *
45163 * Coordinate `y` is fixed on levels, coordinate `x` is unfixed.
45164 *
45165 * @extends DirectionInterface
45166 * @private
45167 */
45168
45169
45170 var VerticalStrategy =
45171 /*#__PURE__*/
45172 function (_DirectionInterface) {
45173 _inherits(VerticalStrategy, _DirectionInterface);
45174
45175 /**
45176 * Constructor
45177 *
45178 * @param {Object} layout reference to the parent LayoutEngine instance.
45179 */
45180 function VerticalStrategy(layout) {
45181 var _this;
45182
45183 _classCallCheck(this, VerticalStrategy);
45184
45185 _this = _possibleConstructorReturn(this, _getPrototypeOf(VerticalStrategy).call(this));
45186 _this.layout = layout;
45187 return _this;
45188 }
45189 /** @inheritdoc */
45190
45191
45192 _createClass(VerticalStrategy, [{
45193 key: "curveType",
45194 value: function curveType() {
45195 return 'horizontal';
45196 }
45197 /** @inheritdoc */
45198
45199 }, {
45200 key: "getPosition",
45201 value: function getPosition(node) {
45202 return node.x;
45203 }
45204 /** @inheritdoc */
45205
45206 }, {
45207 key: "setPosition",
45208 value: function setPosition(node, position) {
45209 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
45210
45211 if (level !== undefined) {
45212 this.layout.hierarchical.addToOrdering(node, level);
45213 }
45214
45215 node.x = position;
45216 }
45217 /** @inheritdoc */
45218
45219 }, {
45220 key: "getTreeSize",
45221 value: function getTreeSize(index) {
45222 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
45223 return {
45224 min: res.min_x,
45225 max: res.max_x
45226 };
45227 }
45228 /** @inheritdoc */
45229
45230 }, {
45231 key: "sort",
45232 value: function sort(nodeArray) {
45233 timsort_1(nodeArray, function (a, b) {
45234 return a.x - b.x;
45235 });
45236 }
45237 /** @inheritdoc */
45238
45239 }, {
45240 key: "fix",
45241 value: function fix(node, level) {
45242 node.y = this.layout.options.hierarchical.levelSeparation * level;
45243 node.options.fixed.y = true;
45244 }
45245 /** @inheritdoc */
45246
45247 }, {
45248 key: "shift",
45249 value: function shift(nodeId, diff) {
45250 this.layout.body.nodes[nodeId].x += diff;
45251 }
45252 }]);
45253
45254 return VerticalStrategy;
45255 }(DirectionInterface);
45256 /**
45257 * Horizontal Strategy
45258 *
45259 * Coordinate `x` is fixed on levels, coordinate `y` is unfixed.
45260 *
45261 * @extends DirectionInterface
45262 * @private
45263 */
45264
45265
45266 var HorizontalStrategy =
45267 /*#__PURE__*/
45268 function (_DirectionInterface2) {
45269 _inherits(HorizontalStrategy, _DirectionInterface2);
45270
45271 /**
45272 * Constructor
45273 *
45274 * @param {Object} layout reference to the parent LayoutEngine instance.
45275 */
45276 function HorizontalStrategy(layout) {
45277 var _this2;
45278
45279 _classCallCheck(this, HorizontalStrategy);
45280
45281 _this2 = _possibleConstructorReturn(this, _getPrototypeOf(HorizontalStrategy).call(this));
45282 _this2.layout = layout;
45283 return _this2;
45284 }
45285 /** @inheritdoc */
45286
45287
45288 _createClass(HorizontalStrategy, [{
45289 key: "curveType",
45290 value: function curveType() {
45291 return 'vertical';
45292 }
45293 /** @inheritdoc */
45294
45295 }, {
45296 key: "getPosition",
45297 value: function getPosition(node) {
45298 return node.y;
45299 }
45300 /** @inheritdoc */
45301
45302 }, {
45303 key: "setPosition",
45304 value: function setPosition(node, position) {
45305 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
45306
45307 if (level !== undefined) {
45308 this.layout.hierarchical.addToOrdering(node, level);
45309 }
45310
45311 node.y = position;
45312 }
45313 /** @inheritdoc */
45314
45315 }, {
45316 key: "getTreeSize",
45317 value: function getTreeSize(index) {
45318 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
45319 return {
45320 min: res.min_y,
45321 max: res.max_y
45322 };
45323 }
45324 /** @inheritdoc */
45325
45326 }, {
45327 key: "sort",
45328 value: function sort(nodeArray) {
45329 timsort_1(nodeArray, function (a, b) {
45330 return a.y - b.y;
45331 });
45332 }
45333 /** @inheritdoc */
45334
45335 }, {
45336 key: "fix",
45337 value: function fix(node, level) {
45338 node.x = this.layout.options.hierarchical.levelSeparation * level;
45339 node.options.fixed.x = true;
45340 }
45341 /** @inheritdoc */
45342
45343 }, {
45344 key: "shift",
45345 value: function shift(nodeId, diff) {
45346 this.layout.body.nodes[nodeId].y += diff;
45347 }
45348 }]);
45349
45350 return HorizontalStrategy;
45351 }(DirectionInterface);
45352
45353 var nativeGetOwnPropertyNames = objectGetOwnPropertyNames.f;
45354 var toString$2 = {}.toString;
45355 var windowNames$1 = typeof window == 'object' && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : [];
45356
45357 var getWindowNames$1 = function (it) {
45358 try {
45359 return nativeGetOwnPropertyNames(it);
45360 } catch (error) {
45361 return windowNames$1.slice();
45362 }
45363 }; // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
45364
45365
45366 var f$7 = function getOwnPropertyNames(it) {
45367 return windowNames$1 && toString$2.call(it) == '[object Window]' ? getWindowNames$1(it) : nativeGetOwnPropertyNames(toIndexedObject(it));
45368 };
45369
45370 var objectGetOwnPropertyNamesExternal = {
45371 f: f$7
45372 };
45373
45374 var f$8 = wellKnownSymbol;
45375 var wrappedWellKnownSymbol = {
45376 f: f$8
45377 };
45378
45379 var defineProperty$8 = objectDefineProperty.f;
45380
45381 var defineWellKnownSymbol = function (NAME) {
45382 var Symbol = path.Symbol || (path.Symbol = {});
45383 if (!has(Symbol, NAME)) defineProperty$8(Symbol, NAME, {
45384 value: wrappedWellKnownSymbol.f(NAME)
45385 });
45386 };
45387
45388 var $forEach$1 = arrayIteration.forEach;
45389 var HIDDEN$1 = sharedKey('hidden');
45390 var SYMBOL = 'Symbol';
45391 var PROTOTYPE$4 = 'prototype';
45392 var TO_PRIMITIVE$1 = wellKnownSymbol('toPrimitive');
45393 var setInternalState$2 = internalState.set;
45394 var getInternalState$2 = internalState.getterFor(SYMBOL);
45395 var ObjectPrototype$3 = Object[PROTOTYPE$4];
45396 var $Symbol$1 = global_1.Symbol;
45397 var JSON$1 = global_1.JSON;
45398 var nativeJSONStringify = JSON$1 && JSON$1.stringify;
45399 var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
45400 var nativeDefineProperty$1 = objectDefineProperty.f;
45401 var nativeGetOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f;
45402 var nativePropertyIsEnumerable$1 = objectPropertyIsEnumerable.f;
45403 var AllSymbols$1 = shared('symbols');
45404 var ObjectPrototypeSymbols = shared('op-symbols');
45405 var StringToSymbolRegistry = shared('string-to-symbol-registry');
45406 var SymbolToStringRegistry = shared('symbol-to-string-registry');
45407 var WellKnownSymbolsStore = shared('wks');
45408 var QObject$1 = global_1.QObject; // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
45409
45410 var USE_SETTER = !QObject$1 || !QObject$1[PROTOTYPE$4] || !QObject$1[PROTOTYPE$4].findChild; // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
45411
45412 var setSymbolDescriptor = descriptors && fails(function () {
45413 return objectCreate(nativeDefineProperty$1({}, 'a', {
45414 get: function () {
45415 return nativeDefineProperty$1(this, 'a', {
45416 value: 7
45417 }).a;
45418 }
45419 })).a != 7;
45420 }) ? function (O, P, Attributes) {
45421 var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype$3, P);
45422 if (ObjectPrototypeDescriptor) delete ObjectPrototype$3[P];
45423 nativeDefineProperty$1(O, P, Attributes);
45424
45425 if (ObjectPrototypeDescriptor && O !== ObjectPrototype$3) {
45426 nativeDefineProperty$1(ObjectPrototype$3, P, ObjectPrototypeDescriptor);
45427 }
45428 } : nativeDefineProperty$1;
45429
45430 var wrap$1 = function (tag, description) {
45431 var symbol = AllSymbols$1[tag] = objectCreate($Symbol$1[PROTOTYPE$4]);
45432 setInternalState$2(symbol, {
45433 type: SYMBOL,
45434 tag: tag,
45435 description: description
45436 });
45437 if (!descriptors) symbol.description = description;
45438 return symbol;
45439 };
45440
45441 var isSymbol$1 = nativeSymbol && typeof $Symbol$1.iterator == 'symbol' ? function (it) {
45442 return typeof it == 'symbol';
45443 } : function (it) {
45444 return Object(it) instanceof $Symbol$1;
45445 };
45446
45447 var $defineProperty$1 = function defineProperty(O, P, Attributes) {
45448 if (O === ObjectPrototype$3) $defineProperty$1(ObjectPrototypeSymbols, P, Attributes);
45449 anObject(O);
45450 var key = toPrimitive(P, true);
45451 anObject(Attributes);
45452
45453 if (has(AllSymbols$1, key)) {
45454 if (!Attributes.enumerable) {
45455 if (!has(O, HIDDEN$1)) nativeDefineProperty$1(O, HIDDEN$1, createPropertyDescriptor(1, {}));
45456 O[HIDDEN$1][key] = true;
45457 } else {
45458 if (has(O, HIDDEN$1) && O[HIDDEN$1][key]) O[HIDDEN$1][key] = false;
45459 Attributes = objectCreate(Attributes, {
45460 enumerable: createPropertyDescriptor(0, false)
45461 });
45462 }
45463
45464 return setSymbolDescriptor(O, key, Attributes);
45465 }
45466
45467 return nativeDefineProperty$1(O, key, Attributes);
45468 };
45469
45470 var $defineProperties$1 = function defineProperties(O, Properties) {
45471 anObject(O);
45472 var properties = toIndexedObject(Properties);
45473 var keys = objectKeys(properties).concat($getOwnPropertySymbols$1(properties));
45474 $forEach$1(keys, function (key) {
45475 if (!descriptors || $propertyIsEnumerable$1.call(properties, key)) $defineProperty$1(O, key, properties[key]);
45476 });
45477 return O;
45478 };
45479
45480 var $create$1 = function create(O, Properties) {
45481 return Properties === undefined ? objectCreate(O) : $defineProperties$1(objectCreate(O), Properties);
45482 };
45483
45484 var $propertyIsEnumerable$1 = function propertyIsEnumerable(V) {
45485 var P = toPrimitive(V, true);
45486 var enumerable = nativePropertyIsEnumerable$1.call(this, P);
45487 if (this === ObjectPrototype$3 && has(AllSymbols$1, P) && !has(ObjectPrototypeSymbols, P)) return false;
45488 return enumerable || !has(this, P) || !has(AllSymbols$1, P) || has(this, HIDDEN$1) && this[HIDDEN$1][P] ? enumerable : true;
45489 };
45490
45491 var $getOwnPropertyDescriptor$1 = function getOwnPropertyDescriptor(O, P) {
45492 var it = toIndexedObject(O);
45493 var key = toPrimitive(P, true);
45494 if (it === ObjectPrototype$3 && has(AllSymbols$1, key) && !has(ObjectPrototypeSymbols, key)) return;
45495 var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);
45496
45497 if (descriptor && has(AllSymbols$1, key) && !(has(it, HIDDEN$1) && it[HIDDEN$1][key])) {
45498 descriptor.enumerable = true;
45499 }
45500
45501 return descriptor;
45502 };
45503
45504 var $getOwnPropertyNames$1 = function getOwnPropertyNames(O) {
45505 var names = nativeGetOwnPropertyNames$1(toIndexedObject(O));
45506 var result = [];
45507 $forEach$1(names, function (key) {
45508 if (!has(AllSymbols$1, key) && !has(hiddenKeys, key)) result.push(key);
45509 });
45510 return result;
45511 };
45512
45513 var $getOwnPropertySymbols$1 = function getOwnPropertySymbols(O) {
45514 var IS_OBJECT_PROTOTYPE = O === ObjectPrototype$3;
45515 var names = nativeGetOwnPropertyNames$1(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));
45516 var result = [];
45517 $forEach$1(names, function (key) {
45518 if (has(AllSymbols$1, key) && (!IS_OBJECT_PROTOTYPE || has(ObjectPrototype$3, key))) {
45519 result.push(AllSymbols$1[key]);
45520 }
45521 });
45522 return result;
45523 }; // `Symbol` constructor
45524 // https://tc39.github.io/ecma262/#sec-symbol-constructor
45525
45526
45527 if (!nativeSymbol) {
45528 $Symbol$1 = function Symbol() {
45529 if (this instanceof $Symbol$1) throw TypeError('Symbol is not a constructor');
45530 var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
45531 var tag = uid(description);
45532
45533 var setter = function (value) {
45534 if (this === ObjectPrototype$3) setter.call(ObjectPrototypeSymbols, value);
45535 if (has(this, HIDDEN$1) && has(this[HIDDEN$1], tag)) this[HIDDEN$1][tag] = false;
45536 setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
45537 };
45538
45539 if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype$3, tag, {
45540 configurable: true,
45541 set: setter
45542 });
45543 return wrap$1(tag, description);
45544 };
45545
45546 redefine($Symbol$1[PROTOTYPE$4], 'toString', function toString() {
45547 return getInternalState$2(this).tag;
45548 });
45549 objectPropertyIsEnumerable.f = $propertyIsEnumerable$1;
45550 objectDefineProperty.f = $defineProperty$1;
45551 objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor$1;
45552 objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames$1;
45553 objectGetOwnPropertySymbols.f = $getOwnPropertySymbols$1;
45554
45555 if (descriptors) {
45556 // https://github.com/tc39/proposal-Symbol-description
45557 nativeDefineProperty$1($Symbol$1[PROTOTYPE$4], 'description', {
45558 configurable: true,
45559 get: function description() {
45560 return getInternalState$2(this).description;
45561 }
45562 });
45563
45564 {
45565 redefine(ObjectPrototype$3, 'propertyIsEnumerable', $propertyIsEnumerable$1, {
45566 unsafe: true
45567 });
45568 }
45569 }
45570
45571 wrappedWellKnownSymbol.f = function (name) {
45572 return wrap$1(wellKnownSymbol(name), name);
45573 };
45574 }
45575
45576 _export({
45577 global: true,
45578 wrap: true,
45579 forced: !nativeSymbol,
45580 sham: !nativeSymbol
45581 }, {
45582 Symbol: $Symbol$1
45583 });
45584 $forEach$1(objectKeys(WellKnownSymbolsStore), function (name) {
45585 defineWellKnownSymbol(name);
45586 });
45587 _export({
45588 target: SYMBOL,
45589 stat: true,
45590 forced: !nativeSymbol
45591 }, {
45592 // `Symbol.for` method
45593 // https://tc39.github.io/ecma262/#sec-symbol.for
45594 'for': function (key) {
45595 var string = String(key);
45596 if (has(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
45597 var symbol = $Symbol$1(string);
45598 StringToSymbolRegistry[string] = symbol;
45599 SymbolToStringRegistry[symbol] = string;
45600 return symbol;
45601 },
45602 // `Symbol.keyFor` method
45603 // https://tc39.github.io/ecma262/#sec-symbol.keyfor
45604 keyFor: function keyFor(sym) {
45605 if (!isSymbol$1(sym)) throw TypeError(sym + ' is not a symbol');
45606 if (has(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
45607 },
45608 useSetter: function () {
45609 USE_SETTER = true;
45610 },
45611 useSimple: function () {
45612 USE_SETTER = false;
45613 }
45614 });
45615 _export({
45616 target: 'Object',
45617 stat: true,
45618 forced: !nativeSymbol,
45619 sham: !descriptors
45620 }, {
45621 // `Object.create` method
45622 // https://tc39.github.io/ecma262/#sec-object.create
45623 create: $create$1,
45624 // `Object.defineProperty` method
45625 // https://tc39.github.io/ecma262/#sec-object.defineproperty
45626 defineProperty: $defineProperty$1,
45627 // `Object.defineProperties` method
45628 // https://tc39.github.io/ecma262/#sec-object.defineproperties
45629 defineProperties: $defineProperties$1,
45630 // `Object.getOwnPropertyDescriptor` method
45631 // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptors
45632 getOwnPropertyDescriptor: $getOwnPropertyDescriptor$1
45633 });
45634 _export({
45635 target: 'Object',
45636 stat: true,
45637 forced: !nativeSymbol
45638 }, {
45639 // `Object.getOwnPropertyNames` method
45640 // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
45641 getOwnPropertyNames: $getOwnPropertyNames$1,
45642 // `Object.getOwnPropertySymbols` method
45643 // https://tc39.github.io/ecma262/#sec-object.getownpropertysymbols
45644 getOwnPropertySymbols: $getOwnPropertySymbols$1
45645 }); // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
45646 // https://bugs.chromium.org/p/v8/issues/detail?id=3443
45647
45648 _export({
45649 target: 'Object',
45650 stat: true,
45651 forced: fails(function () {
45652 objectGetOwnPropertySymbols.f(1);
45653 })
45654 }, {
45655 getOwnPropertySymbols: function getOwnPropertySymbols(it) {
45656 return objectGetOwnPropertySymbols.f(toObject(it));
45657 }
45658 }); // `JSON.stringify` method behavior with symbols
45659 // https://tc39.github.io/ecma262/#sec-json.stringify
45660
45661 JSON$1 && _export({
45662 target: 'JSON',
45663 stat: true,
45664 forced: !nativeSymbol || fails(function () {
45665 var symbol = $Symbol$1(); // MS Edge converts symbol values to JSON as {}
45666
45667 return nativeJSONStringify([symbol]) != '[null]' // WebKit converts symbol values to JSON as null
45668 || nativeJSONStringify({
45669 a: symbol
45670 }) != '{}' // V8 throws on boxed symbols
45671 || nativeJSONStringify(Object(symbol)) != '{}';
45672 })
45673 }, {
45674 stringify: function stringify(it) {
45675 var args = [it];
45676 var index = 1;
45677 var replacer, $replacer;
45678
45679 while (arguments.length > index) args.push(arguments[index++]);
45680
45681 $replacer = replacer = args[1];
45682 if (!isObject(replacer) && it === undefined || isSymbol$1(it)) return; // IE8 returns string on undefined
45683
45684 if (!isArray(replacer)) replacer = function (key, value) {
45685 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
45686 if (!isSymbol$1(value)) return value;
45687 };
45688 args[1] = replacer;
45689 return nativeJSONStringify.apply(JSON$1, args);
45690 }
45691 }); // `Symbol.prototype[@@toPrimitive]` method
45692 // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@toprimitive
45693
45694 if (!$Symbol$1[PROTOTYPE$4][TO_PRIMITIVE$1]) {
45695 createNonEnumerableProperty($Symbol$1[PROTOTYPE$4], TO_PRIMITIVE$1, $Symbol$1[PROTOTYPE$4].valueOf);
45696 } // `Symbol.prototype[@@toStringTag]` property
45697 // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@tostringtag
45698
45699
45700 setToStringTag($Symbol$1, SYMBOL);
45701 hiddenKeys[HIDDEN$1] = true;
45702
45703 var defineProperty$9 = objectDefineProperty.f;
45704 var NativeSymbol = global_1.Symbol;
45705
45706 if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) || // Safari 12 bug
45707 NativeSymbol().description !== undefined)) {
45708 var EmptyStringDescriptionStore = {}; // wrap Symbol constructor for correct work with undefined description
45709
45710 var SymbolWrapper = function Symbol() {
45711 var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
45712 var result = this instanceof SymbolWrapper ? new NativeSymbol(description) // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
45713 : description === undefined ? NativeSymbol() : NativeSymbol(description);
45714 if (description === '') EmptyStringDescriptionStore[result] = true;
45715 return result;
45716 };
45717
45718 copyConstructorProperties(SymbolWrapper, NativeSymbol);
45719 var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
45720 symbolPrototype.constructor = SymbolWrapper;
45721 var symbolToString = symbolPrototype.toString;
45722 var native = String(NativeSymbol('test')) == 'Symbol(test)';
45723 var regexp = /^Symbol\((.*)\)[^)]+$/;
45724 defineProperty$9(symbolPrototype, 'description', {
45725 configurable: true,
45726 get: function description() {
45727 var symbol = isObject(this) ? this.valueOf() : this;
45728 var string = symbolToString.call(symbol);
45729 if (has(EmptyStringDescriptionStore, symbol)) return '';
45730 var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
45731 return desc === '' ? undefined : desc;
45732 }
45733 });
45734 _export({
45735 global: true,
45736 forced: true
45737 }, {
45738 Symbol: SymbolWrapper
45739 });
45740 }
45741
45742 // https://tc39.github.io/ecma262/#sec-symbol.iterator
45743
45744 defineWellKnownSymbol('iterator');
45745
45746 var $every = arrayIteration.every; // `Array.prototype.every` method
45747 // https://tc39.github.io/ecma262/#sec-array.prototype.every
45748
45749 _export({
45750 target: 'Array',
45751 proto: true,
45752 forced: sloppyArrayMethod('every')
45753 }, {
45754 every: function every(callbackfn
45755 /* , thisArg */
45756 ) {
45757 return $every(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
45758 }
45759 });
45760
45761 var $filter = arrayIteration.filter; // `Array.prototype.filter` method
45762 // https://tc39.github.io/ecma262/#sec-array.prototype.filter
45763 // with adding support of @@species
45764
45765 _export({
45766 target: 'Array',
45767 proto: true,
45768 forced: !arrayMethodHasSpeciesSupport('filter')
45769 }, {
45770 filter: function filter(callbackfn
45771 /* , thisArg */
45772 ) {
45773 return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
45774 }
45775 });
45776
45777 var freezing = !fails(function () {
45778 return Object.isExtensible(Object.preventExtensions({}));
45779 });
45780
45781 var internalMetadata = createCommonjsModule(function (module) {
45782 var defineProperty = objectDefineProperty.f;
45783 var METADATA = uid('meta');
45784 var id = 0;
45785
45786 var isExtensible = Object.isExtensible || function () {
45787 return true;
45788 };
45789
45790 var setMetadata = function (it) {
45791 defineProperty(it, METADATA, {
45792 value: {
45793 objectID: 'O' + ++id,
45794 // object ID
45795 weakData: {} // weak collections IDs
45796
45797 }
45798 });
45799 };
45800
45801 var fastKey = function (it, create) {
45802 // return a primitive with prefix
45803 if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
45804
45805 if (!has(it, METADATA)) {
45806 // can't set metadata to uncaught frozen object
45807 if (!isExtensible(it)) return 'F'; // not necessary to add metadata
45808
45809 if (!create) return 'E'; // add missing metadata
45810
45811 setMetadata(it); // return object ID
45812 }
45813
45814 return it[METADATA].objectID;
45815 };
45816
45817 var getWeakData = function (it, create) {
45818 if (!has(it, METADATA)) {
45819 // can't set metadata to uncaught frozen object
45820 if (!isExtensible(it)) return true; // not necessary to add metadata
45821
45822 if (!create) return false; // add missing metadata
45823
45824 setMetadata(it); // return the store of weak collections IDs
45825 }
45826
45827 return it[METADATA].weakData;
45828 }; // add metadata on freeze-family methods calling
45829
45830
45831 var onFreeze = function (it) {
45832 if (freezing && meta.REQUIRED && isExtensible(it) && !has(it, METADATA)) setMetadata(it);
45833 return it;
45834 };
45835
45836 var meta = module.exports = {
45837 REQUIRED: false,
45838 fastKey: fastKey,
45839 getWeakData: getWeakData,
45840 onFreeze: onFreeze
45841 };
45842 hiddenKeys[METADATA] = true;
45843 });
45844 var internalMetadata_1 = internalMetadata.REQUIRED;
45845 var internalMetadata_2 = internalMetadata.fastKey;
45846 var internalMetadata_3 = internalMetadata.getWeakData;
45847 var internalMetadata_4 = internalMetadata.onFreeze;
45848
45849 var ITERATOR$5 = wellKnownSymbol('iterator');
45850 var ArrayPrototype$1 = Array.prototype; // check on default Array iterator
45851
45852 var isArrayIteratorMethod = function (it) {
45853 return it !== undefined && (iterators.Array === it || ArrayPrototype$1[ITERATOR$5] === it);
45854 };
45855
45856 var ITERATOR$6 = wellKnownSymbol('iterator');
45857
45858 var getIteratorMethod = function (it) {
45859 if (it != undefined) return it[ITERATOR$6] || it['@@iterator'] || iterators[classof(it)];
45860 };
45861
45862 var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
45863 try {
45864 return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value); // 7.4.6 IteratorClose(iterator, completion)
45865 } catch (error) {
45866 var returnMethod = iterator['return'];
45867 if (returnMethod !== undefined) anObject(returnMethod.call(iterator));
45868 throw error;
45869 }
45870 };
45871
45872 var iterate_1 = createCommonjsModule(function (module) {
45873 var Result = function (stopped, result) {
45874 this.stopped = stopped;
45875 this.result = result;
45876 };
45877
45878 var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITERATOR) {
45879 var boundFunction = bindContext(fn, that, AS_ENTRIES ? 2 : 1);
45880 var iterator, iterFn, index, length, result, next, step;
45881
45882 if (IS_ITERATOR) {
45883 iterator = iterable;
45884 } else {
45885 iterFn = getIteratorMethod(iterable);
45886 if (typeof iterFn != 'function') throw TypeError('Target is not iterable'); // optimisation for array iterators
45887
45888 if (isArrayIteratorMethod(iterFn)) {
45889 for (index = 0, length = toLength(iterable.length); length > index; index++) {
45890 result = AS_ENTRIES ? boundFunction(anObject(step = iterable[index])[0], step[1]) : boundFunction(iterable[index]);
45891 if (result && result instanceof Result) return result;
45892 }
45893
45894 return new Result(false);
45895 }
45896
45897 iterator = iterFn.call(iterable);
45898 }
45899
45900 next = iterator.next;
45901
45902 while (!(step = next.call(iterator)).done) {
45903 result = callWithSafeIterationClosing(iterator, boundFunction, step.value, AS_ENTRIES);
45904 if (typeof result == 'object' && result && result instanceof Result) return result;
45905 }
45906
45907 return new Result(false);
45908 };
45909
45910 iterate.stop = function (result) {
45911 return new Result(true, result);
45912 };
45913 });
45914
45915 var ITERATOR$7 = wellKnownSymbol('iterator');
45916 var SAFE_CLOSING = false;
45917
45918 try {
45919 var called = 0;
45920 var iteratorWithReturn = {
45921 next: function () {
45922 return {
45923 done: !!called++
45924 };
45925 },
45926 'return': function () {
45927 SAFE_CLOSING = true;
45928 }
45929 };
45930
45931 iteratorWithReturn[ITERATOR$7] = function () {
45932 return this;
45933 }; // eslint-disable-next-line no-throw-literal
45934
45935
45936 Array.from(iteratorWithReturn, function () {
45937 throw 2;
45938 });
45939 } catch (error) {
45940 /* empty */
45941 }
45942
45943 var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
45944 if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
45945 var ITERATION_SUPPORT = false;
45946
45947 try {
45948 var object = {};
45949
45950 object[ITERATOR$7] = function () {
45951 return {
45952 next: function () {
45953 return {
45954 done: ITERATION_SUPPORT = true
45955 };
45956 }
45957 };
45958 };
45959
45960 exec(object);
45961 } catch (error) {
45962 /* empty */
45963 }
45964
45965 return ITERATION_SUPPORT;
45966 };
45967
45968 var collection = function (CONSTRUCTOR_NAME, wrapper, common, IS_MAP, IS_WEAK) {
45969 var NativeConstructor = global_1[CONSTRUCTOR_NAME];
45970 var NativePrototype = NativeConstructor && NativeConstructor.prototype;
45971 var Constructor = NativeConstructor;
45972 var ADDER = IS_MAP ? 'set' : 'add';
45973 var exported = {};
45974
45975 var fixMethod = function (KEY) {
45976 var nativeMethod = NativePrototype[KEY];
45977 redefine(NativePrototype, KEY, KEY == 'add' ? function add(value) {
45978 nativeMethod.call(this, value === 0 ? 0 : value);
45979 return this;
45980 } : KEY == 'delete' ? function (key) {
45981 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
45982 } : KEY == 'get' ? function get(key) {
45983 return IS_WEAK && !isObject(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
45984 } : KEY == 'has' ? function has(key) {
45985 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
45986 } : function set(key, value) {
45987 nativeMethod.call(this, key === 0 ? 0 : key, value);
45988 return this;
45989 });
45990 }; // eslint-disable-next-line max-len
45991
45992
45993 if (isForced_1(CONSTRUCTOR_NAME, typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
45994 new NativeConstructor().entries().next();
45995 })))) {
45996 // create collection constructor
45997 Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
45998 internalMetadata.REQUIRED = true;
45999 } else if (isForced_1(CONSTRUCTOR_NAME, true)) {
46000 var instance = new Constructor(); // early implementations not supports chaining
46001
46002 var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance; // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
46003
46004 var THROWS_ON_PRIMITIVES = fails(function () {
46005 instance.has(1);
46006 }); // most early implementations doesn't supports iterables, most modern - not close it correctly
46007 // eslint-disable-next-line no-new
46008
46009 var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) {
46010 new NativeConstructor(iterable);
46011 }); // for early implementations -0 and +0 not the same
46012
46013 var BUGGY_ZERO = !IS_WEAK && fails(function () {
46014 // V8 ~ Chromium 42- fails only with 5+ elements
46015 var $instance = new NativeConstructor();
46016 var index = 5;
46017
46018 while (index--) $instance[ADDER](index, index);
46019
46020 return !$instance.has(-0);
46021 });
46022
46023 if (!ACCEPT_ITERABLES) {
46024 Constructor = wrapper(function (dummy, iterable) {
46025 anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
46026 var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
46027 if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
46028 return that;
46029 });
46030 Constructor.prototype = NativePrototype;
46031 NativePrototype.constructor = Constructor;
46032 }
46033
46034 if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
46035 fixMethod('delete');
46036 fixMethod('has');
46037 IS_MAP && fixMethod('get');
46038 }
46039
46040 if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER); // weak collections should not contains .clear method
46041
46042 if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
46043 }
46044
46045 exported[CONSTRUCTOR_NAME] = Constructor;
46046 _export({
46047 global: true,
46048 forced: Constructor != NativeConstructor
46049 }, exported);
46050 setToStringTag(Constructor, CONSTRUCTOR_NAME);
46051 if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
46052 return Constructor;
46053 };
46054
46055 var defineProperty$a = objectDefineProperty.f;
46056 var fastKey = internalMetadata.fastKey;
46057 var setInternalState$3 = internalState.set;
46058 var internalStateGetterFor = internalState.getterFor;
46059 var collectionStrong = {
46060 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
46061 var C = wrapper(function (that, iterable) {
46062 anInstance(that, C, CONSTRUCTOR_NAME);
46063 setInternalState$3(that, {
46064 type: CONSTRUCTOR_NAME,
46065 index: objectCreate(null),
46066 first: undefined,
46067 last: undefined,
46068 size: 0
46069 });
46070 if (!descriptors) that.size = 0;
46071 if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
46072 });
46073 var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
46074
46075 var define = function (that, key, value) {
46076 var state = getInternalState(that);
46077 var entry = getEntry(that, key);
46078 var previous, index; // change existing entry
46079
46080 if (entry) {
46081 entry.value = value; // create new entry
46082 } else {
46083 state.last = entry = {
46084 index: index = fastKey(key, true),
46085 key: key,
46086 value: value,
46087 previous: previous = state.last,
46088 next: undefined,
46089 removed: false
46090 };
46091 if (!state.first) state.first = entry;
46092 if (previous) previous.next = entry;
46093 if (descriptors) state.size++;else that.size++; // add to index
46094
46095 if (index !== 'F') state.index[index] = entry;
46096 }
46097
46098 return that;
46099 };
46100
46101 var getEntry = function (that, key) {
46102 var state = getInternalState(that); // fast case
46103
46104 var index = fastKey(key);
46105 var entry;
46106 if (index !== 'F') return state.index[index]; // frozen object case
46107
46108 for (entry = state.first; entry; entry = entry.next) {
46109 if (entry.key == key) return entry;
46110 }
46111 };
46112
46113 redefineAll(C.prototype, {
46114 // 23.1.3.1 Map.prototype.clear()
46115 // 23.2.3.2 Set.prototype.clear()
46116 clear: function clear() {
46117 var that = this;
46118 var state = getInternalState(that);
46119 var data = state.index;
46120 var entry = state.first;
46121
46122 while (entry) {
46123 entry.removed = true;
46124 if (entry.previous) entry.previous = entry.previous.next = undefined;
46125 delete data[entry.index];
46126 entry = entry.next;
46127 }
46128
46129 state.first = state.last = undefined;
46130 if (descriptors) state.size = 0;else that.size = 0;
46131 },
46132 // 23.1.3.3 Map.prototype.delete(key)
46133 // 23.2.3.4 Set.prototype.delete(value)
46134 'delete': function (key) {
46135 var that = this;
46136 var state = getInternalState(that);
46137 var entry = getEntry(that, key);
46138
46139 if (entry) {
46140 var next = entry.next;
46141 var prev = entry.previous;
46142 delete state.index[entry.index];
46143 entry.removed = true;
46144 if (prev) prev.next = next;
46145 if (next) next.previous = prev;
46146 if (state.first == entry) state.first = next;
46147 if (state.last == entry) state.last = prev;
46148 if (descriptors) state.size--;else that.size--;
46149 }
46150
46151 return !!entry;
46152 },
46153 // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
46154 // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
46155 forEach: function forEach(callbackfn
46156 /* , that = undefined */
46157 ) {
46158 var state = getInternalState(this);
46159 var boundFunction = bindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
46160 var entry;
46161
46162 while (entry = entry ? entry.next : state.first) {
46163 boundFunction(entry.value, entry.key, this); // revert to the last existing entry
46164
46165 while (entry && entry.removed) entry = entry.previous;
46166 }
46167 },
46168 // 23.1.3.7 Map.prototype.has(key)
46169 // 23.2.3.7 Set.prototype.has(value)
46170 has: function has(key) {
46171 return !!getEntry(this, key);
46172 }
46173 });
46174 redefineAll(C.prototype, IS_MAP ? {
46175 // 23.1.3.6 Map.prototype.get(key)
46176 get: function get(key) {
46177 var entry = getEntry(this, key);
46178 return entry && entry.value;
46179 },
46180 // 23.1.3.9 Map.prototype.set(key, value)
46181 set: function set(key, value) {
46182 return define(this, key === 0 ? 0 : key, value);
46183 }
46184 } : {
46185 // 23.2.3.1 Set.prototype.add(value)
46186 add: function add(value) {
46187 return define(this, value = value === 0 ? 0 : value, value);
46188 }
46189 });
46190 if (descriptors) defineProperty$a(C.prototype, 'size', {
46191 get: function () {
46192 return getInternalState(this).size;
46193 }
46194 });
46195 return C;
46196 },
46197 setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
46198 var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
46199 var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
46200 var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME); // add .keys, .values, .entries, [@@iterator]
46201 // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11
46202
46203 defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
46204 setInternalState$3(this, {
46205 type: ITERATOR_NAME,
46206 target: iterated,
46207 state: getInternalCollectionState(iterated),
46208 kind: kind,
46209 last: undefined
46210 });
46211 }, function () {
46212 var state = getInternalIteratorState(this);
46213 var kind = state.kind;
46214 var entry = state.last; // revert to the last existing entry
46215
46216 while (entry && entry.removed) entry = entry.previous; // get next entry
46217
46218
46219 if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
46220 // or finish the iteration
46221 state.target = undefined;
46222 return {
46223 value: undefined,
46224 done: true
46225 };
46226 } // return step by kind
46227
46228
46229 if (kind == 'keys') return {
46230 value: entry.key,
46231 done: false
46232 };
46233 if (kind == 'values') return {
46234 value: entry.value,
46235 done: false
46236 };
46237 return {
46238 value: [entry.key, entry.value],
46239 done: false
46240 };
46241 }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); // add [@@species], 23.1.2.2, 23.2.2.2
46242
46243 setSpecies(CONSTRUCTOR_NAME);
46244 }
46245 };
46246
46247 // https://tc39.github.io/ecma262/#sec-set-objects
46248
46249
46250 var es_set = collection('Set', function (get) {
46251 return function Set() {
46252 return get(this, arguments.length ? arguments[0] : undefined);
46253 };
46254 }, collectionStrong);
46255
46256 var charAt$1 = stringMultibyte.charAt;
46257 var STRING_ITERATOR = 'String Iterator';
46258 var setInternalState$4 = internalState.set;
46259 var getInternalState$3 = internalState.getterFor(STRING_ITERATOR); // `String.prototype[@@iterator]` method
46260 // https://tc39.github.io/ecma262/#sec-string.prototype-@@iterator
46261
46262 defineIterator(String, 'String', function (iterated) {
46263 setInternalState$4(this, {
46264 type: STRING_ITERATOR,
46265 string: String(iterated),
46266 index: 0
46267 }); // `%StringIteratorPrototype%.next` method
46268 // https://tc39.github.io/ecma262/#sec-%stringiteratorprototype%.next
46269 }, function next() {
46270 var state = getInternalState$3(this);
46271 var string = state.string;
46272 var index = state.index;
46273 var point;
46274 if (index >= string.length) return {
46275 value: undefined,
46276 done: true
46277 };
46278 point = charAt$1(string, index);
46279 state.index += point.length;
46280 return {
46281 value: point,
46282 done: false
46283 };
46284 });
46285
46286 /**
46287 * Try to assign levels to nodes according to their positions in the cyclic “hierarchy”.
46288 *
46289 * @param nodes - Nodes of the graph.
46290 * @param levels - If present levels will be added to it, if not a new object will be created.
46291 *
46292 * @returns Populated node levels.
46293 */
46294 function fillLevelsByDirectionCyclic(nodes, levels) {
46295 var edges = new Set();
46296 nodes.forEach(function (node) {
46297 node.edges.forEach(function (edge) {
46298 if (edge.connected) {
46299 edges.add(edge);
46300 }
46301 });
46302 });
46303 edges.forEach(function (edge) {
46304 var fromId = edge.from.id;
46305 var toId = edge.to.id;
46306
46307 if (levels[fromId] == null) {
46308 levels[fromId] = 0;
46309 }
46310
46311 if (levels[toId] == null || levels[fromId] >= levels[toId]) {
46312 levels[toId] = levels[fromId] + 1;
46313 }
46314 });
46315 return levels;
46316 }
46317 /**
46318 * Assign levels to nodes according to their positions in the hierarchy. Leaves will be lined up at the bottom and all other nodes as close to their children as possible.
46319 *
46320 * @param nodes - Nodes of the graph.
46321 * @param levels - If present levels will be added to it, if not a new object will be created.
46322 *
46323 * @returns Populated node levels.
46324 */
46325
46326
46327 function fillLevelsByDirectionLeaves(nodes) {
46328 var levels = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Object.create(null);
46329 return fillLevelsByDirection( // Pick only leaves (nodes without children).
46330 function (node) {
46331 return !node.edges.every(function (edge) {
46332 return edge.to === node;
46333 });
46334 }, // Use the lowest level.
46335 function (newLevel, oldLevel) {
46336 return oldLevel > newLevel;
46337 }, // Go against the direction of the edges.
46338 "from", nodes, levels);
46339 }
46340 /**
46341 * Assign levels to nodes according to their positions in the hierarchy. Roots will be lined up at the top and all nodes as close to their parents as possible.
46342 *
46343 * @param nodes - Nodes of the graph.
46344 * @param levels - If present levels will be added to it, if not a new object will be created.
46345 *
46346 * @returns Populated node levels.
46347 */
46348
46349 function fillLevelsByDirectionRoots(nodes) {
46350 var levels = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Object.create(null);
46351 return fillLevelsByDirection( // Pick only roots (nodes without parents).
46352 function (node) {
46353 return !node.edges.every(function (edge) {
46354 return edge.from === node;
46355 });
46356 }, // Use the highest level.
46357 function (newLevel, oldLevel) {
46358 return oldLevel < newLevel;
46359 }, // Go in the direction of the edges.
46360 "to", nodes, levels);
46361 }
46362 /**
46363 * Assign levels to nodes according to their positions in the hierarchy.
46364 *
46365 * @param isEntryNode - Checks and return true if the graph should be traversed from this node.
46366 * @param shouldLevelBeReplaced - Checks and returns true if the level of given node should be updated to the new value.
46367 * @param direction - Wheter the graph should be traversed in the direction of the edges `"to"` or in the other way `"from"`.
46368 * @param nodes - Nodes of the graph.
46369 * @param levels - If present levels will be added to it, if not a new object will be created.
46370 *
46371 * @returns Populated node levels.
46372 */
46373
46374 function fillLevelsByDirection(isEntryNode, shouldLevelBeReplaced, direction, nodes, levels) {
46375 var limit = nodes.length;
46376 var edgeIdProp = direction + "Id";
46377 var newLevelDiff = direction === "to" ? 1 : -1;
46378 var _iteratorNormalCompletion = true;
46379 var _didIteratorError = false;
46380 var _iteratorError = undefined;
46381
46382 try {
46383 var _loop = function _loop() {
46384 var entryNode = _step.value;
46385
46386 if (isEntryNode(entryNode)) {
46387 return "continue";
46388 } // Line up all the entry nodes on level 0.
46389
46390
46391 levels[entryNode.id] = 0;
46392 var stack = [entryNode];
46393 var done = 0;
46394 var node = void 0;
46395
46396 var _loop2 = function _loop2() {
46397 var newLevel = levels[node.id] + newLevelDiff;
46398 node.edges.filter(function (edge) {
46399 return (// Ignore disconnected edges.
46400 edge.connected && // Ignore circular edges.
46401 edge.to !== edge.from && // Ignore edges leading to the node that's currently being processed.
46402 edge[direction] !== node
46403 );
46404 }).forEach(function (edge) {
46405 var targetNodeId = edge[edgeIdProp];
46406 var oldLevel = levels[targetNodeId];
46407
46408 if (oldLevel == null || shouldLevelBeReplaced(newLevel, oldLevel)) {
46409 levels[targetNodeId] = newLevel;
46410 stack.push(edge[direction]);
46411 }
46412 });
46413
46414 if (done > limit) {
46415 // This would run forever on a cyclic graph.
46416 return {
46417 v: {
46418 v: fillLevelsByDirectionCyclic(nodes, levels)
46419 }
46420 };
46421 } else {
46422 ++done;
46423 }
46424 };
46425
46426 while (node = stack.pop()) {
46427 var _ret2 = _loop2();
46428
46429 if (_typeof$1(_ret2) === "object") return _ret2.v;
46430 }
46431 };
46432
46433 for (var _iterator = nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
46434 var _ret = _loop();
46435
46436 switch (_ret) {
46437 case "continue":
46438 continue;
46439
46440 default:
46441 if (_typeof$1(_ret) === "object") return _ret.v;
46442 }
46443 }
46444 } catch (err) {
46445 _didIteratorError = true;
46446 _iteratorError = err;
46447 } finally {
46448 try {
46449 if (!_iteratorNormalCompletion && _iterator.return != null) {
46450 _iterator.return();
46451 }
46452 } finally {
46453 if (_didIteratorError) {
46454 throw _iteratorError;
46455 }
46456 }
46457 }
46458
46459 return levels;
46460 }
46461
46462 /**
46463 * There's a mix-up with terms in the code. Following are the formal definitions:
46464 *
46465 * tree - a strict hierarchical network, i.e. every node has at most one parent
46466 * forest - a collection of trees. These distinct trees are thus not connected.
46467 *
46468 * So:
46469 * - in a network that is not a tree, there exist nodes with multiple parents.
46470 * - a network consisting of unconnected sub-networks, of which at least one
46471 * is not a tree, is not a forest.
46472 *
46473 * In the code, the definitions are:
46474 *
46475 * tree - any disconnected sub-network, strict hierarchical or not.
46476 * forest - a bunch of these sub-networks
46477 *
46478 * The difference between tree and not-tree is important in the code, notably within
46479 * to the block-shifting algorithm. The algorithm assumes formal trees and fails
46480 * for not-trees, often in a spectacular manner (search for 'exploding network' in the issues).
46481 *
46482 * In order to distinguish the definitions in the following code, the adjective 'formal' is
46483 * used. If 'formal' is absent, you must assume the non-formal definition.
46484 *
46485 * ----------------------------------------------------------------------------------
46486 * NOTES
46487 * =====
46488 *
46489 * A hierarchical layout is a different thing from a hierarchical network.
46490 * The layout is a way to arrange the nodes in the view; this can be done
46491 * on non-hierarchical networks as well. The converse is also possible.
46492 */
46493 /**
46494 * Container for derived data on current network, relating to hierarchy.
46495 *
46496 * @private
46497 */
46498
46499 var HierarchicalStatus =
46500 /*#__PURE__*/
46501 function () {
46502 /**
46503 * @ignore
46504 */
46505 function HierarchicalStatus() {
46506 _classCallCheck(this, HierarchicalStatus);
46507
46508 this.childrenReference = {}; // child id's per node id
46509
46510 this.parentReference = {}; // parent id's per node id
46511
46512 this.trees = {}; // tree id per node id; i.e. to which tree does given node id belong
46513
46514 this.distributionOrdering = {}; // The nodes per level, in the display order
46515
46516 this.levels = {}; // hierarchy level per node id
46517
46518 this.distributionIndex = {}; // The position of the node in the level sorting order, per node id.
46519
46520 this.isTree = false; // True if current network is a formal tree
46521
46522 this.treeIndex = -1; // Highest tree id in current network.
46523 }
46524 /**
46525 * Add the relation between given nodes to the current state.
46526 *
46527 * @param {Node.id} parentNodeId
46528 * @param {Node.id} childNodeId
46529 */
46530
46531
46532 _createClass(HierarchicalStatus, [{
46533 key: "addRelation",
46534 value: function addRelation(parentNodeId, childNodeId) {
46535 if (this.childrenReference[parentNodeId] === undefined) {
46536 this.childrenReference[parentNodeId] = [];
46537 }
46538
46539 this.childrenReference[parentNodeId].push(childNodeId);
46540
46541 if (this.parentReference[childNodeId] === undefined) {
46542 this.parentReference[childNodeId] = [];
46543 }
46544
46545 this.parentReference[childNodeId].push(parentNodeId);
46546 }
46547 /**
46548 * Check if the current state is for a formal tree or formal forest.
46549 *
46550 * This is the case if every node has at most one parent.
46551 *
46552 * Pre: parentReference init'ed properly for current network
46553 */
46554
46555 }, {
46556 key: "checkIfTree",
46557 value: function checkIfTree() {
46558 for (var i in this.parentReference) {
46559 if (this.parentReference[i].length > 1) {
46560 this.isTree = false;
46561 return;
46562 }
46563 }
46564
46565 this.isTree = true;
46566 }
46567 /**
46568 * Return the number of separate trees in the current network.
46569 * @returns {number}
46570 */
46571
46572 }, {
46573 key: "numTrees",
46574 value: function numTrees() {
46575 return this.treeIndex + 1; // This assumes the indexes are assigned consecitively
46576 }
46577 /**
46578 * Assign a tree id to a node
46579 * @param {Node} node
46580 * @param {string|number} treeId
46581 */
46582
46583 }, {
46584 key: "setTreeIndex",
46585 value: function setTreeIndex(node, treeId) {
46586 if (treeId === undefined) return; // Don't bother
46587
46588 if (this.trees[node.id] === undefined) {
46589 this.trees[node.id] = treeId;
46590 this.treeIndex = Math.max(treeId, this.treeIndex);
46591 }
46592 }
46593 /**
46594 * Ensure level for given id is defined.
46595 *
46596 * Sets level to zero for given node id if not already present
46597 *
46598 * @param {Node.id} nodeId
46599 */
46600
46601 }, {
46602 key: "ensureLevel",
46603 value: function ensureLevel(nodeId) {
46604 if (this.levels[nodeId] === undefined) {
46605 this.levels[nodeId] = 0;
46606 }
46607 }
46608 /**
46609 * get the maximum level of a branch.
46610 *
46611 * TODO: Never entered; find a test case to test this!
46612 * @param {Node.id} nodeId
46613 * @returns {number}
46614 */
46615
46616 }, {
46617 key: "getMaxLevel",
46618 value: function getMaxLevel(nodeId) {
46619 var _this = this;
46620
46621 var accumulator = {};
46622
46623 var _getMaxLevel = function _getMaxLevel(nodeId) {
46624 if (accumulator[nodeId] !== undefined) {
46625 return accumulator[nodeId];
46626 }
46627
46628 var level = _this.levels[nodeId];
46629
46630 if (_this.childrenReference[nodeId]) {
46631 var children = _this.childrenReference[nodeId];
46632
46633 if (children.length > 0) {
46634 for (var i = 0; i < children.length; i++) {
46635 level = Math.max(level, _getMaxLevel(children[i]));
46636 }
46637 }
46638 }
46639
46640 accumulator[nodeId] = level;
46641 return level;
46642 };
46643
46644 return _getMaxLevel(nodeId);
46645 }
46646 /**
46647 *
46648 * @param {Node} nodeA
46649 * @param {Node} nodeB
46650 */
46651
46652 }, {
46653 key: "levelDownstream",
46654 value: function levelDownstream(nodeA, nodeB) {
46655 if (this.levels[nodeB.id] === undefined) {
46656 // set initial level
46657 if (this.levels[nodeA.id] === undefined) {
46658 this.levels[nodeA.id] = 0;
46659 } // set level
46660
46661
46662 this.levels[nodeB.id] = this.levels[nodeA.id] + 1;
46663 }
46664 }
46665 /**
46666 * Small util method to set the minimum levels of the nodes to zero.
46667 *
46668 * @param {Array.<Node>} nodes
46669 */
46670
46671 }, {
46672 key: "setMinLevelToZero",
46673 value: function setMinLevelToZero(nodes) {
46674 var minLevel = 1e9; // get the minimum level
46675
46676 for (var nodeId in nodes) {
46677 if (nodes.hasOwnProperty(nodeId)) {
46678 if (this.levels[nodeId] !== undefined) {
46679 minLevel = Math.min(this.levels[nodeId], minLevel);
46680 }
46681 }
46682 } // subtract the minimum from the set so we have a range starting from 0
46683
46684
46685 for (var _nodeId in nodes) {
46686 if (nodes.hasOwnProperty(_nodeId)) {
46687 if (this.levels[_nodeId] !== undefined) {
46688 this.levels[_nodeId] -= minLevel;
46689 }
46690 }
46691 }
46692 }
46693 /**
46694 * Get the min and max xy-coordinates of a given tree
46695 *
46696 * @param {Array.<Node>} nodes
46697 * @param {number} index
46698 * @returns {{min_x: number, max_x: number, min_y: number, max_y: number}}
46699 */
46700
46701 }, {
46702 key: "getTreeSize",
46703 value: function getTreeSize(nodes, index) {
46704 var min_x = 1e9;
46705 var max_x = -1e9;
46706 var min_y = 1e9;
46707 var max_y = -1e9;
46708
46709 for (var nodeId in this.trees) {
46710 if (this.trees.hasOwnProperty(nodeId)) {
46711 if (this.trees[nodeId] === index) {
46712 var node = nodes[nodeId];
46713 min_x = Math.min(node.x, min_x);
46714 max_x = Math.max(node.x, max_x);
46715 min_y = Math.min(node.y, min_y);
46716 max_y = Math.max(node.y, max_y);
46717 }
46718 }
46719 }
46720
46721 return {
46722 min_x: min_x,
46723 max_x: max_x,
46724 min_y: min_y,
46725 max_y: max_y
46726 };
46727 }
46728 /**
46729 * Check if two nodes have the same parent(s)
46730 *
46731 * @param {Node} node1
46732 * @param {Node} node2
46733 * @return {boolean} true if the two nodes have a same ancestor node, false otherwise
46734 */
46735
46736 }, {
46737 key: "hasSameParent",
46738 value: function hasSameParent(node1, node2) {
46739 var parents1 = this.parentReference[node1.id];
46740 var parents2 = this.parentReference[node2.id];
46741
46742 if (parents1 === undefined || parents2 === undefined) {
46743 return false;
46744 }
46745
46746 for (var i = 0; i < parents1.length; i++) {
46747 for (var j = 0; j < parents2.length; j++) {
46748 if (parents1[i] == parents2[j]) {
46749 return true;
46750 }
46751 }
46752 }
46753
46754 return false;
46755 }
46756 /**
46757 * Check if two nodes are in the same tree.
46758 *
46759 * @param {Node} node1
46760 * @param {Node} node2
46761 * @return {Boolean} true if this is so, false otherwise
46762 */
46763
46764 }, {
46765 key: "inSameSubNetwork",
46766 value: function inSameSubNetwork(node1, node2) {
46767 return this.trees[node1.id] === this.trees[node2.id];
46768 }
46769 /**
46770 * Get a list of the distinct levels in the current network
46771 *
46772 * @returns {Array}
46773 */
46774
46775 }, {
46776 key: "getLevels",
46777 value: function getLevels() {
46778 return Object.keys(this.distributionOrdering);
46779 }
46780 /**
46781 * Add a node to the ordering per level
46782 *
46783 * @param {Node} node
46784 * @param {number} level
46785 */
46786
46787 }, {
46788 key: "addToOrdering",
46789 value: function addToOrdering(node, level) {
46790 if (this.distributionOrdering[level] === undefined) {
46791 this.distributionOrdering[level] = [];
46792 }
46793
46794 var isPresent = false;
46795 var curLevel = this.distributionOrdering[level];
46796
46797 for (var n in curLevel) {
46798 //if (curLevel[n].id === node.id) {
46799 if (curLevel[n] === node) {
46800 isPresent = true;
46801 break;
46802 }
46803 }
46804
46805 if (!isPresent) {
46806 this.distributionOrdering[level].push(node);
46807 this.distributionIndex[node.id] = this.distributionOrdering[level].length - 1;
46808 }
46809 }
46810 }]);
46811
46812 return HierarchicalStatus;
46813 }();
46814 /**
46815 * The Layout Engine
46816 */
46817
46818
46819 var LayoutEngine =
46820 /*#__PURE__*/
46821 function () {
46822 /**
46823 * @param {Object} body
46824 */
46825 function LayoutEngine(body) {
46826 _classCallCheck(this, LayoutEngine);
46827
46828 this.body = body;
46829 this.initialRandomSeed = Math.round(Math.random() * 1000000);
46830 this.randomSeed = this.initialRandomSeed;
46831 this.setPhysics = false;
46832 this.options = {};
46833 this.optionsBackup = {
46834 physics: {}
46835 };
46836 this.defaultOptions = {
46837 randomSeed: undefined,
46838 improvedLayout: true,
46839 clusterThreshold: 150,
46840 hierarchical: {
46841 enabled: false,
46842 levelSeparation: 150,
46843 nodeSpacing: 100,
46844 treeSpacing: 200,
46845 blockShifting: true,
46846 edgeMinimization: true,
46847 parentCentralization: true,
46848 direction: 'UD',
46849 // UD, DU, LR, RL
46850 sortMethod: 'hubsize' // hubsize, directed
46851
46852 }
46853 };
46854 extend(this.options, this.defaultOptions);
46855 this.bindEventListeners();
46856 }
46857 /**
46858 * Binds event listeners
46859 */
46860
46861
46862 _createClass(LayoutEngine, [{
46863 key: "bindEventListeners",
46864 value: function bindEventListeners() {
46865 var _this2 = this;
46866
46867 this.body.emitter.on('_dataChanged', function () {
46868 _this2.setupHierarchicalLayout();
46869 });
46870 this.body.emitter.on('_dataLoaded', function () {
46871 _this2.layoutNetwork();
46872 });
46873 this.body.emitter.on('_resetHierarchicalLayout', function () {
46874 _this2.setupHierarchicalLayout();
46875 });
46876 this.body.emitter.on('_adjustEdgesForHierarchicalLayout', function () {
46877 if (_this2.options.hierarchical.enabled !== true) {
46878 return;
46879 } // get the type of static smooth curve in case it is required
46880
46881
46882 var type = _this2.direction.curveType(); // force all edges into static smooth curves.
46883
46884
46885 _this2.body.emitter.emit('_forceDisableDynamicCurves', type, false);
46886 });
46887 }
46888 /**
46889 *
46890 * @param {Object} options
46891 * @param {Object} allOptions
46892 * @returns {Object}
46893 */
46894
46895 }, {
46896 key: "setOptions",
46897 value: function setOptions(options, allOptions) {
46898 if (options !== undefined) {
46899 var hierarchical = this.options.hierarchical;
46900 var prevHierarchicalState = hierarchical.enabled;
46901 selectiveDeepExtend(["randomSeed", "improvedLayout", "clusterThreshold"], this.options, options);
46902 mergeOptions(this.options, options, 'hierarchical');
46903
46904 if (options.randomSeed !== undefined) {
46905 this.initialRandomSeed = options.randomSeed;
46906 }
46907
46908 if (hierarchical.enabled === true) {
46909 if (prevHierarchicalState === true) {
46910 // refresh the overridden options for nodes and edges.
46911 this.body.emitter.emit('refresh', true);
46912 } // make sure the level separation is the right way up
46913
46914
46915 if (hierarchical.direction === 'RL' || hierarchical.direction === 'DU') {
46916 if (hierarchical.levelSeparation > 0) {
46917 hierarchical.levelSeparation *= -1;
46918 }
46919 } else {
46920 if (hierarchical.levelSeparation < 0) {
46921 hierarchical.levelSeparation *= -1;
46922 }
46923 }
46924
46925 this.setDirectionStrategy();
46926 this.body.emitter.emit('_resetHierarchicalLayout'); // because the hierarchical system needs it's own physics and smooth curve settings,
46927 // we adapt the other options if needed.
46928
46929 return this.adaptAllOptionsForHierarchicalLayout(allOptions);
46930 } else {
46931 if (prevHierarchicalState === true) {
46932 // refresh the overridden options for nodes and edges.
46933 this.body.emitter.emit('refresh');
46934 return deepExtend(allOptions, this.optionsBackup);
46935 }
46936 }
46937 }
46938
46939 return allOptions;
46940 }
46941 /**
46942 *
46943 * @param {Object} allOptions
46944 * @returns {Object}
46945 */
46946
46947 }, {
46948 key: "adaptAllOptionsForHierarchicalLayout",
46949 value: function adaptAllOptionsForHierarchicalLayout(allOptions) {
46950 if (this.options.hierarchical.enabled === true) {
46951 var backupPhysics = this.optionsBackup.physics; // set the physics
46952
46953 if (allOptions.physics === undefined || allOptions.physics === true) {
46954 allOptions.physics = {
46955 enabled: backupPhysics.enabled === undefined ? true : backupPhysics.enabled,
46956 solver: 'hierarchicalRepulsion'
46957 };
46958 backupPhysics.enabled = backupPhysics.enabled === undefined ? true : backupPhysics.enabled;
46959 backupPhysics.solver = backupPhysics.solver || 'barnesHut';
46960 } else if (_typeof$1(allOptions.physics) === 'object') {
46961 backupPhysics.enabled = allOptions.physics.enabled === undefined ? true : allOptions.physics.enabled;
46962 backupPhysics.solver = allOptions.physics.solver || 'barnesHut';
46963 allOptions.physics.solver = 'hierarchicalRepulsion';
46964 } else if (allOptions.physics !== false) {
46965 backupPhysics.solver = 'barnesHut';
46966 allOptions.physics = {
46967 solver: 'hierarchicalRepulsion'
46968 };
46969 } // get the type of static smooth curve in case it is required
46970
46971
46972 var type = this.direction.curveType(); // disable smooth curves if nothing is defined. If smooth curves have been turned on,
46973 // turn them into static smooth curves.
46974
46975 if (allOptions.edges === undefined) {
46976 this.optionsBackup.edges = {
46977 smooth: {
46978 enabled: true,
46979 type: 'dynamic'
46980 }
46981 };
46982 allOptions.edges = {
46983 smooth: false
46984 };
46985 } else if (allOptions.edges.smooth === undefined) {
46986 this.optionsBackup.edges = {
46987 smooth: {
46988 enabled: true,
46989 type: 'dynamic'
46990 }
46991 };
46992 allOptions.edges.smooth = false;
46993 } else {
46994 if (typeof allOptions.edges.smooth === 'boolean') {
46995 this.optionsBackup.edges = {
46996 smooth: allOptions.edges.smooth
46997 };
46998 allOptions.edges.smooth = {
46999 enabled: allOptions.edges.smooth,
47000 type: type
47001 };
47002 } else {
47003 var smooth = allOptions.edges.smooth; // allow custom types except for dynamic
47004
47005 if (smooth.type !== undefined && smooth.type !== 'dynamic') {
47006 type = smooth.type;
47007 } // TODO: this is options merging; see if the standard routines can be used here.
47008
47009
47010 this.optionsBackup.edges = {
47011 smooth: smooth.enabled === undefined ? true : smooth.enabled,
47012 type: smooth.type === undefined ? 'dynamic' : smooth.type,
47013 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
47014 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
47015 }; // NOTE: Copying an object to self; this is basically setting defaults for undefined variables
47016
47017 allOptions.edges.smooth = {
47018 enabled: smooth.enabled === undefined ? true : smooth.enabled,
47019 type: type,
47020 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
47021 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
47022 };
47023 }
47024 } // Force all edges into static smooth curves.
47025 // Only applies to edges that do not use the global options for smooth.
47026
47027
47028 this.body.emitter.emit('_forceDisableDynamicCurves', type);
47029 }
47030
47031 return allOptions;
47032 }
47033 /**
47034 *
47035 * @returns {number}
47036 */
47037
47038 }, {
47039 key: "seededRandom",
47040 value: function seededRandom() {
47041 var x = Math.sin(this.randomSeed++) * 10000;
47042 return x - Math.floor(x);
47043 }
47044 /**
47045 *
47046 * @param {Array.<Node>} nodesArray
47047 */
47048
47049 }, {
47050 key: "positionInitially",
47051 value: function positionInitially(nodesArray) {
47052 if (this.options.hierarchical.enabled !== true) {
47053 this.randomSeed = this.initialRandomSeed;
47054 var radius = nodesArray.length + 50;
47055
47056 for (var i = 0; i < nodesArray.length; i++) {
47057 var node = nodesArray[i];
47058 var angle = 2 * Math.PI * this.seededRandom();
47059
47060 if (node.x === undefined) {
47061 node.x = radius * Math.cos(angle);
47062 }
47063
47064 if (node.y === undefined) {
47065 node.y = radius * Math.sin(angle);
47066 }
47067 }
47068 }
47069 }
47070 /**
47071 * Use Kamada Kawai to position nodes. This is quite a heavy algorithm so if there are a lot of nodes we
47072 * cluster them first to reduce the amount.
47073 */
47074
47075 }, {
47076 key: "layoutNetwork",
47077 value: function layoutNetwork() {
47078 if (this.options.hierarchical.enabled !== true && this.options.improvedLayout === true) {
47079 var indices = this.body.nodeIndices; // first check if we should Kamada Kawai to layout. The threshold is if less than half of the visible
47080 // nodes have predefined positions we use this.
47081
47082 var positionDefined = 0;
47083
47084 for (var i = 0; i < indices.length; i++) {
47085 var node = this.body.nodes[indices[i]];
47086
47087 if (node.predefinedPosition === true) {
47088 positionDefined += 1;
47089 }
47090 } // if less than half of the nodes have a predefined position we continue
47091
47092
47093 if (positionDefined < 0.5 * indices.length) {
47094 var MAX_LEVELS = 10;
47095 var level = 0;
47096 var clusterThreshold = this.options.clusterThreshold; //
47097 // Define the options for the hidden cluster nodes
47098 // These options don't propagate outside the clustering phase.
47099 //
47100 // Some options are explicitly disabled, because they may be set in group or default node options.
47101 // The clusters are never displayed, so most explicit settings here serve as performance optimizations.
47102 //
47103 // The explicit setting of 'shape' is to avoid `shape: 'image'`; images are not passed to the hidden
47104 // cluster nodes, leading to an exception on creation.
47105 //
47106 // All settings here are performance related, except when noted otherwise.
47107 //
47108
47109 var clusterOptions = {
47110 clusterNodeProperties: {
47111 shape: 'ellipse',
47112 // Bugfix: avoid type 'image', no images supplied
47113 label: '',
47114 // avoid label handling
47115 group: '',
47116 // avoid group handling
47117 font: {
47118 multi: false
47119 } // avoid font propagation
47120
47121 },
47122 clusterEdgeProperties: {
47123 label: '',
47124 // avoid label handling
47125 font: {
47126 multi: false
47127 },
47128 // avoid font propagation
47129 smooth: {
47130 enabled: false // avoid drawing penalty for complex edges
47131
47132 }
47133 }
47134 }; // if there are a lot of nodes, we cluster before we run the algorithm.
47135 // NOTE: this part fails to find clusters for large scale-free networks, which should
47136 // be easily clusterable.
47137 // TODO: examine why this is so
47138
47139 if (indices.length > clusterThreshold) {
47140 var startLength = indices.length;
47141
47142 while (indices.length > clusterThreshold && level <= MAX_LEVELS) {
47143 //console.time("clustering")
47144 level += 1;
47145 var before = indices.length; // if there are many nodes we do a hubsize cluster
47146
47147 if (level % 3 === 0) {
47148 this.body.modules.clustering.clusterBridges(clusterOptions);
47149 } else {
47150 this.body.modules.clustering.clusterOutliers(clusterOptions);
47151 }
47152
47153 var after = indices.length;
47154
47155 if (before == after && level % 3 !== 0) {
47156 this._declusterAll();
47157
47158 this.body.emitter.emit("_layoutFailed");
47159 console.info("This network could not be positioned by this version of the improved layout algorithm." + " Please disable improvedLayout for better performance.");
47160 return;
47161 } //console.timeEnd("clustering")
47162 //console.log(before,level,after);
47163
47164 } // increase the size of the edges
47165
47166
47167 this.body.modules.kamadaKawai.setOptions({
47168 springLength: Math.max(150, 2 * startLength)
47169 });
47170 }
47171
47172 if (level > MAX_LEVELS) {
47173 console.info("The clustering didn't succeed within the amount of interations allowed," + " progressing with partial result.");
47174 } // position the system for these nodes and edges
47175
47176
47177 this.body.modules.kamadaKawai.solve(indices, this.body.edgeIndices, true); // shift to center point
47178
47179 this._shiftToCenter(); // perturb the nodes a little bit to force the physics to kick in
47180
47181
47182 var offset = 70;
47183
47184 for (var _i = 0; _i < indices.length; _i++) {
47185 // Only perturb the nodes that aren't fixed
47186 var _node = this.body.nodes[indices[_i]];
47187
47188 if (_node.predefinedPosition === false) {
47189 _node.x += (0.5 - this.seededRandom()) * offset;
47190 _node.y += (0.5 - this.seededRandom()) * offset;
47191 }
47192 } // uncluster all clusters
47193
47194
47195 this._declusterAll(); // reposition all bezier nodes.
47196
47197
47198 this.body.emitter.emit("_repositionBezierNodes");
47199 }
47200 }
47201 }
47202 /**
47203 * Move all the nodes towards to the center so gravitational pull wil not move the nodes away from view
47204 * @private
47205 */
47206
47207 }, {
47208 key: "_shiftToCenter",
47209 value: function _shiftToCenter() {
47210 var range = NetworkUtil.getRangeCore(this.body.nodes, this.body.nodeIndices);
47211 var center = NetworkUtil.findCenter(range);
47212
47213 for (var i = 0; i < this.body.nodeIndices.length; i++) {
47214 var node = this.body.nodes[this.body.nodeIndices[i]];
47215 node.x -= center.x;
47216 node.y -= center.y;
47217 }
47218 }
47219 /**
47220 * Expands all clusters
47221 * @private
47222 */
47223
47224 }, {
47225 key: "_declusterAll",
47226 value: function _declusterAll() {
47227 var clustersPresent = true;
47228
47229 while (clustersPresent === true) {
47230 clustersPresent = false;
47231
47232 for (var i = 0; i < this.body.nodeIndices.length; i++) {
47233 if (this.body.nodes[this.body.nodeIndices[i]].isCluster === true) {
47234 clustersPresent = true;
47235 this.body.modules.clustering.openCluster(this.body.nodeIndices[i], {}, false);
47236 }
47237 }
47238
47239 if (clustersPresent === true) {
47240 this.body.emitter.emit('_dataChanged');
47241 }
47242 }
47243 }
47244 /**
47245 *
47246 * @returns {number|*}
47247 */
47248
47249 }, {
47250 key: "getSeed",
47251 value: function getSeed() {
47252 return this.initialRandomSeed;
47253 }
47254 /**
47255 * This is the main function to layout the nodes in a hierarchical way.
47256 * It checks if the node details are supplied correctly
47257 *
47258 * @private
47259 */
47260
47261 }, {
47262 key: "setupHierarchicalLayout",
47263 value: function setupHierarchicalLayout() {
47264 if (this.options.hierarchical.enabled === true && this.body.nodeIndices.length > 0) {
47265 // get the size of the largest hubs and check if the user has defined a level for a node.
47266 var node, nodeId;
47267 var definedLevel = false;
47268 var undefinedLevel = false;
47269 this.lastNodeOnLevel = {};
47270 this.hierarchical = new HierarchicalStatus();
47271
47272 for (nodeId in this.body.nodes) {
47273 if (this.body.nodes.hasOwnProperty(nodeId)) {
47274 node = this.body.nodes[nodeId];
47275
47276 if (node.options.level !== undefined) {
47277 definedLevel = true;
47278 this.hierarchical.levels[nodeId] = node.options.level;
47279 } else {
47280 undefinedLevel = true;
47281 }
47282 }
47283 } // if the user defined some levels but not all, alert and run without hierarchical layout
47284
47285
47286 if (undefinedLevel === true && definedLevel === true) {
47287 throw new Error('To use the hierarchical layout, nodes require either no predefined levels' + ' or levels have to be defined for all nodes.');
47288 } else {
47289 // define levels if undefined by the users. Based on hubsize.
47290 if (undefinedLevel === true) {
47291 var sortMethod = this.options.hierarchical.sortMethod;
47292
47293 if (sortMethod === 'hubsize') {
47294 this._determineLevelsByHubsize();
47295 } else if (sortMethod === 'directed') {
47296 this._determineLevelsDirected();
47297 } else if (sortMethod === 'custom') {
47298 this._determineLevelsCustomCallback();
47299 }
47300 } // fallback for cases where there are nodes but no edges
47301
47302
47303 for (var _nodeId2 in this.body.nodes) {
47304 if (this.body.nodes.hasOwnProperty(_nodeId2)) {
47305 this.hierarchical.ensureLevel(_nodeId2);
47306 }
47307 } // check the distribution of the nodes per level.
47308
47309
47310 var distribution = this._getDistribution(); // get the parent children relations.
47311
47312
47313 this._generateMap(); // place the nodes on the canvas.
47314
47315
47316 this._placeNodesByHierarchy(distribution); // condense the whitespace.
47317
47318
47319 this._condenseHierarchy(); // shift to center so gravity does not have to do much
47320
47321
47322 this._shiftToCenter();
47323 }
47324 }
47325 }
47326 /**
47327 * @private
47328 */
47329
47330 }, {
47331 key: "_condenseHierarchy",
47332 value: function _condenseHierarchy() {
47333 var _this3 = this;
47334
47335 // Global var in this scope to define when the movement has stopped.
47336 var stillShifting = false;
47337 var branches = {}; // first we have some methods to help shifting trees around.
47338 // the main method to shift the trees
47339
47340 var shiftTrees = function shiftTrees() {
47341 var treeSizes = getTreeSizes();
47342 var shiftBy = 0;
47343
47344 for (var i = 0; i < treeSizes.length - 1; i++) {
47345 var diff = treeSizes[i].max - treeSizes[i + 1].min;
47346 shiftBy += diff + _this3.options.hierarchical.treeSpacing;
47347 shiftTree(i + 1, shiftBy);
47348 }
47349 }; // shift a single tree by an offset
47350
47351
47352 var shiftTree = function shiftTree(index, offset) {
47353 var trees = _this3.hierarchical.trees;
47354
47355 for (var nodeId in trees) {
47356 if (trees.hasOwnProperty(nodeId)) {
47357 if (trees[nodeId] === index) {
47358 _this3.direction.shift(nodeId, offset);
47359 }
47360 }
47361 }
47362 }; // get the width of all trees
47363
47364
47365 var getTreeSizes = function getTreeSizes() {
47366 var treeWidths = [];
47367
47368 for (var i = 0; i < _this3.hierarchical.numTrees(); i++) {
47369 treeWidths.push(_this3.direction.getTreeSize(i));
47370 }
47371
47372 return treeWidths;
47373 }; // get a map of all nodes in this branch
47374
47375
47376 var getBranchNodes = function getBranchNodes(source, map) {
47377 if (map[source.id]) {
47378 return;
47379 }
47380
47381 map[source.id] = true;
47382
47383 if (_this3.hierarchical.childrenReference[source.id]) {
47384 var children = _this3.hierarchical.childrenReference[source.id];
47385
47386 if (children.length > 0) {
47387 for (var i = 0; i < children.length; i++) {
47388 getBranchNodes(_this3.body.nodes[children[i]], map);
47389 }
47390 }
47391 }
47392 }; // get a min max width as well as the maximum movement space it has on either sides
47393 // we use min max terminology because width and height can interchange depending on the direction of the layout
47394
47395
47396 var getBranchBoundary = function getBranchBoundary(branchMap) {
47397 var maxLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1e9;
47398 var minSpace = 1e9;
47399 var maxSpace = 1e9;
47400 var min = 1e9;
47401 var max = -1e9;
47402
47403 for (var branchNode in branchMap) {
47404 if (branchMap.hasOwnProperty(branchNode)) {
47405 var node = _this3.body.nodes[branchNode];
47406 var level = _this3.hierarchical.levels[node.id];
47407
47408 var position = _this3.direction.getPosition(node); // get the space around the node.
47409
47410
47411 var _this3$_getSpaceAroun = _this3._getSpaceAroundNode(node, branchMap),
47412 _this3$_getSpaceAroun2 = _slicedToArray(_this3$_getSpaceAroun, 2),
47413 minSpaceNode = _this3$_getSpaceAroun2[0],
47414 maxSpaceNode = _this3$_getSpaceAroun2[1];
47415
47416 minSpace = Math.min(minSpaceNode, minSpace);
47417 maxSpace = Math.min(maxSpaceNode, maxSpace); // the width is only relevant for the levels two nodes have in common. This is why we filter on this.
47418
47419 if (level <= maxLevel) {
47420 min = Math.min(position, min);
47421 max = Math.max(position, max);
47422 }
47423 }
47424 }
47425
47426 return [min, max, minSpace, maxSpace];
47427 }; // check what the maximum level is these nodes have in common.
47428
47429
47430 var getCollisionLevel = function getCollisionLevel(node1, node2) {
47431 var maxLevel1 = _this3.hierarchical.getMaxLevel(node1.id);
47432
47433 var maxLevel2 = _this3.hierarchical.getMaxLevel(node2.id);
47434
47435 return Math.min(maxLevel1, maxLevel2);
47436 };
47437 /**
47438 * Condense elements. These can be nodes or branches depending on the callback.
47439 *
47440 * @param {function} callback
47441 * @param {Array.<number>} levels
47442 * @param {*} centerParents
47443 */
47444
47445
47446 var shiftElementsCloser = function shiftElementsCloser(callback, levels, centerParents) {
47447 var hier = _this3.hierarchical;
47448
47449 for (var i = 0; i < levels.length; i++) {
47450 var level = levels[i];
47451 var levelNodes = hier.distributionOrdering[level];
47452
47453 if (levelNodes.length > 1) {
47454 for (var j = 0; j < levelNodes.length - 1; j++) {
47455 var node1 = levelNodes[j];
47456 var node2 = levelNodes[j + 1]; // NOTE: logic maintained as it was; if nodes have same ancestor,
47457 // then of course they are in the same sub-network.
47458
47459 if (hier.hasSameParent(node1, node2) && hier.inSameSubNetwork(node1, node2)) {
47460 callback(node1, node2, centerParents);
47461 }
47462 }
47463 }
47464 }
47465 }; // callback for shifting branches
47466
47467
47468 var branchShiftCallback = function branchShiftCallback(node1, node2) {
47469 var centerParent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
47470
47471 //window.CALLBACKS.push(() => {
47472 var pos1 = _this3.direction.getPosition(node1);
47473
47474 var pos2 = _this3.direction.getPosition(node2);
47475
47476 var diffAbs = Math.abs(pos2 - pos1);
47477 var nodeSpacing = _this3.options.hierarchical.nodeSpacing; //console.log("NOW CHECKING:", node1.id, node2.id, diffAbs);
47478
47479 if (diffAbs > nodeSpacing) {
47480 var branchNodes1 = {};
47481 var branchNodes2 = {};
47482 getBranchNodes(node1, branchNodes1);
47483 getBranchNodes(node2, branchNodes2); // check the largest distance between the branches
47484
47485 var maxLevel = getCollisionLevel(node1, node2);
47486 var branchNodeBoundary1 = getBranchBoundary(branchNodes1, maxLevel);
47487 var branchNodeBoundary2 = getBranchBoundary(branchNodes2, maxLevel);
47488 var max1 = branchNodeBoundary1[1];
47489 var min2 = branchNodeBoundary2[0];
47490 var minSpace2 = branchNodeBoundary2[2]; //console.log(node1.id, getBranchBoundary(branchNodes1, maxLevel), node2.id,
47491 // getBranchBoundary(branchNodes2, maxLevel), maxLevel);
47492
47493 var diffBranch = Math.abs(max1 - min2);
47494
47495 if (diffBranch > nodeSpacing) {
47496 var offset = max1 - min2 + nodeSpacing;
47497
47498 if (offset < -minSpace2 + nodeSpacing) {
47499 offset = -minSpace2 + nodeSpacing; //console.log("RESETTING OFFSET", max1 - min2 + this.options.hierarchical.nodeSpacing, -minSpace2, offset);
47500 }
47501
47502 if (offset < 0) {
47503 //console.log("SHIFTING", node2.id, offset);
47504 _this3._shiftBlock(node2.id, offset);
47505
47506 stillShifting = true;
47507 if (centerParent === true) _this3._centerParent(node2);
47508 }
47509 }
47510 } //this.body.emitter.emit("_redraw");})
47511
47512 };
47513
47514 var minimizeEdgeLength = function minimizeEdgeLength(iterations, node) {
47515 //window.CALLBACKS.push(() => {
47516 // console.log("ts",node.id);
47517 var nodeId = node.id;
47518 var allEdges = node.edges;
47519 var nodeLevel = _this3.hierarchical.levels[node.id]; // gather constants
47520
47521 var C2 = _this3.options.hierarchical.levelSeparation * _this3.options.hierarchical.levelSeparation;
47522 var referenceNodes = {};
47523 var aboveEdges = [];
47524
47525 for (var i = 0; i < allEdges.length; i++) {
47526 var edge = allEdges[i];
47527
47528 if (edge.toId != edge.fromId) {
47529 var otherNode = edge.toId == nodeId ? edge.from : edge.to;
47530 referenceNodes[allEdges[i].id] = otherNode;
47531
47532 if (_this3.hierarchical.levels[otherNode.id] < nodeLevel) {
47533 aboveEdges.push(edge);
47534 }
47535 }
47536 } // differentiated sum of lengths based on only moving one node over one axis
47537
47538
47539 var getFx = function getFx(point, edges) {
47540 var sum = 0;
47541
47542 for (var _i2 = 0; _i2 < edges.length; _i2++) {
47543 if (referenceNodes[edges[_i2].id] !== undefined) {
47544 var a = _this3.direction.getPosition(referenceNodes[edges[_i2].id]) - point;
47545 sum += a / Math.sqrt(a * a + C2);
47546 }
47547 }
47548
47549 return sum;
47550 }; // doubly differentiated sum of lengths based on only moving one node over one axis
47551
47552
47553 var getDFx = function getDFx(point, edges) {
47554 var sum = 0;
47555
47556 for (var _i3 = 0; _i3 < edges.length; _i3++) {
47557 if (referenceNodes[edges[_i3].id] !== undefined) {
47558 var a = _this3.direction.getPosition(referenceNodes[edges[_i3].id]) - point;
47559 sum -= C2 * Math.pow(a * a + C2, -1.5);
47560 }
47561 }
47562
47563 return sum;
47564 };
47565
47566 var getGuess = function getGuess(iterations, edges) {
47567 var guess = _this3.direction.getPosition(node); // Newton's method for optimization
47568
47569
47570 var guessMap = {};
47571
47572 for (var _i4 = 0; _i4 < iterations; _i4++) {
47573 var fx = getFx(guess, edges);
47574 var dfx = getDFx(guess, edges); // we limit the movement to avoid instability.
47575
47576 var limit = 40;
47577 var ratio = Math.max(-limit, Math.min(limit, Math.round(fx / dfx)));
47578 guess = guess - ratio; // reduce duplicates
47579
47580 if (guessMap[guess] !== undefined) {
47581 break;
47582 }
47583
47584 guessMap[guess] = _i4;
47585 }
47586
47587 return guess;
47588 };
47589
47590 var moveBranch = function moveBranch(guess) {
47591 // position node if there is space
47592 var nodePosition = _this3.direction.getPosition(node); // check movable area of the branch
47593
47594
47595 if (branches[node.id] === undefined) {
47596 var branchNodes = {};
47597 getBranchNodes(node, branchNodes);
47598 branches[node.id] = branchNodes;
47599 }
47600
47601 var branchBoundary = getBranchBoundary(branches[node.id]);
47602 var minSpaceBranch = branchBoundary[2];
47603 var maxSpaceBranch = branchBoundary[3];
47604 var diff = guess - nodePosition; // check if we are allowed to move the node:
47605
47606 var branchOffset = 0;
47607
47608 if (diff > 0) {
47609 branchOffset = Math.min(diff, maxSpaceBranch - _this3.options.hierarchical.nodeSpacing);
47610 } else if (diff < 0) {
47611 branchOffset = -Math.min(-diff, minSpaceBranch - _this3.options.hierarchical.nodeSpacing);
47612 }
47613
47614 if (branchOffset != 0) {
47615 //console.log("moving branch:",branchOffset, maxSpaceBranch, minSpaceBranch)
47616 _this3._shiftBlock(node.id, branchOffset); //this.body.emitter.emit("_redraw");
47617
47618
47619 stillShifting = true;
47620 }
47621 };
47622
47623 var moveNode = function moveNode(guess) {
47624 var nodePosition = _this3.direction.getPosition(node); // position node if there is space
47625
47626
47627 var _this3$_getSpaceAroun3 = _this3._getSpaceAroundNode(node),
47628 _this3$_getSpaceAroun4 = _slicedToArray(_this3$_getSpaceAroun3, 2),
47629 minSpace = _this3$_getSpaceAroun4[0],
47630 maxSpace = _this3$_getSpaceAroun4[1];
47631
47632 var diff = guess - nodePosition; // check if we are allowed to move the node:
47633
47634 var newPosition = nodePosition;
47635
47636 if (diff > 0) {
47637 newPosition = Math.min(nodePosition + (maxSpace - _this3.options.hierarchical.nodeSpacing), guess);
47638 } else if (diff < 0) {
47639 newPosition = Math.max(nodePosition - (minSpace - _this3.options.hierarchical.nodeSpacing), guess);
47640 }
47641
47642 if (newPosition !== nodePosition) {
47643 //console.log("moving Node:",diff, minSpace, maxSpace);
47644 _this3.direction.setPosition(node, newPosition); //this.body.emitter.emit("_redraw");
47645
47646
47647 stillShifting = true;
47648 }
47649 };
47650
47651 var guess = getGuess(iterations, aboveEdges);
47652 moveBranch(guess);
47653 guess = getGuess(iterations, allEdges);
47654 moveNode(guess); //})
47655 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
47656
47657
47658 var minimizeEdgeLengthBottomUp = function minimizeEdgeLengthBottomUp(iterations) {
47659 var levels = _this3.hierarchical.getLevels();
47660
47661 levels = levels.reverse();
47662
47663 for (var i = 0; i < iterations; i++) {
47664 stillShifting = false;
47665
47666 for (var j = 0; j < levels.length; j++) {
47667 var level = levels[j];
47668 var levelNodes = _this3.hierarchical.distributionOrdering[level];
47669
47670 for (var k = 0; k < levelNodes.length; k++) {
47671 minimizeEdgeLength(1000, levelNodes[k]);
47672 }
47673 }
47674
47675 if (stillShifting !== true) {
47676 //console.log("FINISHED minimizeEdgeLengthBottomUp IN " + i);
47677 break;
47678 }
47679 }
47680 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
47681
47682
47683 var shiftBranchesCloserBottomUp = function shiftBranchesCloserBottomUp(iterations) {
47684 var levels = _this3.hierarchical.getLevels();
47685
47686 levels = levels.reverse();
47687
47688 for (var i = 0; i < iterations; i++) {
47689 stillShifting = false;
47690 shiftElementsCloser(branchShiftCallback, levels, true);
47691
47692 if (stillShifting !== true) {
47693 //console.log("FINISHED shiftBranchesCloserBottomUp IN " + (i+1));
47694 break;
47695 }
47696 }
47697 }; // center all parents
47698
47699
47700 var centerAllParents = function centerAllParents() {
47701 for (var nodeId in _this3.body.nodes) {
47702 if (_this3.body.nodes.hasOwnProperty(nodeId)) _this3._centerParent(_this3.body.nodes[nodeId]);
47703 }
47704 }; // center all parents
47705
47706
47707 var centerAllParentsBottomUp = function centerAllParentsBottomUp() {
47708 var levels = _this3.hierarchical.getLevels();
47709
47710 levels = levels.reverse();
47711
47712 for (var i = 0; i < levels.length; i++) {
47713 var level = levels[i];
47714 var levelNodes = _this3.hierarchical.distributionOrdering[level];
47715
47716 for (var j = 0; j < levelNodes.length; j++) {
47717 _this3._centerParent(levelNodes[j]);
47718 }
47719 }
47720 }; // the actual work is done here.
47721
47722
47723 if (this.options.hierarchical.blockShifting === true) {
47724 shiftBranchesCloserBottomUp(5);
47725 centerAllParents();
47726 } // minimize edge length
47727
47728
47729 if (this.options.hierarchical.edgeMinimization === true) {
47730 minimizeEdgeLengthBottomUp(20);
47731 }
47732
47733 if (this.options.hierarchical.parentCentralization === true) {
47734 centerAllParentsBottomUp();
47735 }
47736
47737 shiftTrees();
47738 }
47739 /**
47740 * This gives the space around the node. IF a map is supplied, it will only check against nodes NOT in the map.
47741 * This is used to only get the distances to nodes outside of a branch.
47742 * @param {Node} node
47743 * @param {{Node.id: vis.Node}} map
47744 * @returns {number[]}
47745 * @private
47746 */
47747
47748 }, {
47749 key: "_getSpaceAroundNode",
47750 value: function _getSpaceAroundNode(node, map) {
47751 var useMap = true;
47752
47753 if (map === undefined) {
47754 useMap = false;
47755 }
47756
47757 var level = this.hierarchical.levels[node.id];
47758
47759 if (level !== undefined) {
47760 var index = this.hierarchical.distributionIndex[node.id];
47761 var position = this.direction.getPosition(node);
47762 var ordering = this.hierarchical.distributionOrdering[level];
47763 var minSpace = 1e9;
47764 var maxSpace = 1e9;
47765
47766 if (index !== 0) {
47767 var prevNode = ordering[index - 1];
47768
47769 if (useMap === true && map[prevNode.id] === undefined || useMap === false) {
47770 var prevPos = this.direction.getPosition(prevNode);
47771 minSpace = position - prevPos;
47772 }
47773 }
47774
47775 if (index != ordering.length - 1) {
47776 var nextNode = ordering[index + 1];
47777
47778 if (useMap === true && map[nextNode.id] === undefined || useMap === false) {
47779 var nextPos = this.direction.getPosition(nextNode);
47780 maxSpace = Math.min(maxSpace, nextPos - position);
47781 }
47782 }
47783
47784 return [minSpace, maxSpace];
47785 } else {
47786 return [0, 0];
47787 }
47788 }
47789 /**
47790 * We use this method to center a parent node and check if it does not cross other nodes when it does.
47791 * @param {Node} node
47792 * @private
47793 */
47794
47795 }, {
47796 key: "_centerParent",
47797 value: function _centerParent(node) {
47798 if (this.hierarchical.parentReference[node.id]) {
47799 var parents = this.hierarchical.parentReference[node.id];
47800
47801 for (var i = 0; i < parents.length; i++) {
47802 var parentId = parents[i];
47803 var parentNode = this.body.nodes[parentId];
47804 var children = this.hierarchical.childrenReference[parentId];
47805
47806 if (children !== undefined) {
47807 // get the range of the children
47808 var newPosition = this._getCenterPosition(children);
47809
47810 var position = this.direction.getPosition(parentNode);
47811
47812 var _this$_getSpaceAround = this._getSpaceAroundNode(parentNode),
47813 _this$_getSpaceAround2 = _slicedToArray(_this$_getSpaceAround, 2),
47814 minSpace = _this$_getSpaceAround2[0],
47815 maxSpace = _this$_getSpaceAround2[1];
47816
47817 var diff = position - newPosition;
47818
47819 if (diff < 0 && Math.abs(diff) < maxSpace - this.options.hierarchical.nodeSpacing || diff > 0 && Math.abs(diff) < minSpace - this.options.hierarchical.nodeSpacing) {
47820 this.direction.setPosition(parentNode, newPosition);
47821 }
47822 }
47823 }
47824 }
47825 }
47826 /**
47827 * This function places the nodes on the canvas based on the hierarchial distribution.
47828 *
47829 * @param {Object} distribution | obtained by the function this._getDistribution()
47830 * @private
47831 */
47832
47833 }, {
47834 key: "_placeNodesByHierarchy",
47835 value: function _placeNodesByHierarchy(distribution) {
47836 this.positionedNodes = {}; // start placing all the level 0 nodes first. Then recursively position their branches.
47837
47838 for (var level in distribution) {
47839 if (distribution.hasOwnProperty(level)) {
47840 // sort nodes in level by position:
47841 var nodeArray = Object.keys(distribution[level]);
47842 nodeArray = this._indexArrayToNodes(nodeArray);
47843 this.direction.sort(nodeArray);
47844 var handledNodeCount = 0;
47845
47846 for (var i = 0; i < nodeArray.length; i++) {
47847 var node = nodeArray[i];
47848
47849 if (this.positionedNodes[node.id] === undefined) {
47850 var spacing = this.options.hierarchical.nodeSpacing;
47851 var pos = spacing * handledNodeCount; // We get the X or Y values we need and store them in pos and previousPos.
47852 // The get and set make sure we get X or Y
47853
47854 if (handledNodeCount > 0) {
47855 pos = this.direction.getPosition(nodeArray[i - 1]) + spacing;
47856 }
47857
47858 this.direction.setPosition(node, pos, level);
47859
47860 this._validatePositionAndContinue(node, level, pos);
47861
47862 handledNodeCount++;
47863 }
47864 }
47865 }
47866 }
47867 }
47868 /**
47869 * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes
47870 * on a X position that ensures there will be no overlap.
47871 *
47872 * @param {Node.id} parentId
47873 * @param {number} parentLevel
47874 * @private
47875 */
47876
47877 }, {
47878 key: "_placeBranchNodes",
47879 value: function _placeBranchNodes(parentId, parentLevel) {
47880 var childRef = this.hierarchical.childrenReference[parentId]; // if this is not a parent, cancel the placing. This can happen with multiple parents to one child.
47881
47882 if (childRef === undefined) {
47883 return;
47884 } // get a list of childNodes
47885
47886
47887 var childNodes = [];
47888
47889 for (var i = 0; i < childRef.length; i++) {
47890 childNodes.push(this.body.nodes[childRef[i]]);
47891 } // use the positions to order the nodes.
47892
47893
47894 this.direction.sort(childNodes); // position the childNodes
47895
47896 for (var _i5 = 0; _i5 < childNodes.length; _i5++) {
47897 var childNode = childNodes[_i5];
47898 var childNodeLevel = this.hierarchical.levels[childNode.id]; // check if the child node is below the parent node and if it has already been positioned.
47899
47900 if (childNodeLevel > parentLevel && this.positionedNodes[childNode.id] === undefined) {
47901 // get the amount of space required for this node. If parent the width is based on the amount of children.
47902 var spacing = this.options.hierarchical.nodeSpacing;
47903 var pos = void 0; // we get the X or Y values we need and store them in pos and previousPos.
47904 // The get and set make sure we get X or Y
47905
47906 if (_i5 === 0) {
47907 pos = this.direction.getPosition(this.body.nodes[parentId]);
47908 } else {
47909 pos = this.direction.getPosition(childNodes[_i5 - 1]) + spacing;
47910 }
47911
47912 this.direction.setPosition(childNode, pos, childNodeLevel);
47913
47914 this._validatePositionAndContinue(childNode, childNodeLevel, pos);
47915 } else {
47916 return;
47917 }
47918 } // center the parent nodes.
47919
47920
47921 var center = this._getCenterPosition(childNodes);
47922
47923 this.direction.setPosition(this.body.nodes[parentId], center, parentLevel);
47924 }
47925 /**
47926 * This method checks for overlap and if required shifts the branch. It also keeps records of positioned nodes.
47927 * Finally it will call _placeBranchNodes to place the branch nodes.
47928 * @param {Node} node
47929 * @param {number} level
47930 * @param {number} pos
47931 * @private
47932 */
47933
47934 }, {
47935 key: "_validatePositionAndContinue",
47936 value: function _validatePositionAndContinue(node, level, pos) {
47937 // This method only works for formal trees and formal forests
47938 // Early exit if this is not the case
47939 if (!this.hierarchical.isTree) return; // if overlap has been detected, we shift the branch
47940
47941 if (this.lastNodeOnLevel[level] !== undefined) {
47942 var previousPos = this.direction.getPosition(this.body.nodes[this.lastNodeOnLevel[level]]);
47943
47944 if (pos - previousPos < this.options.hierarchical.nodeSpacing) {
47945 var diff = previousPos + this.options.hierarchical.nodeSpacing - pos;
47946
47947 var sharedParent = this._findCommonParent(this.lastNodeOnLevel[level], node.id);
47948
47949 this._shiftBlock(sharedParent.withChild, diff);
47950 }
47951 }
47952
47953 this.lastNodeOnLevel[level] = node.id; // store change in position.
47954
47955 this.positionedNodes[node.id] = true;
47956
47957 this._placeBranchNodes(node.id, level);
47958 }
47959 /**
47960 * Receives an array with node indices and returns an array with the actual node references.
47961 * Used for sorting based on node properties.
47962 * @param {Array.<Node.id>} idArray
47963 * @returns {Array.<Node>}
47964 */
47965
47966 }, {
47967 key: "_indexArrayToNodes",
47968 value: function _indexArrayToNodes(idArray) {
47969 var array = [];
47970
47971 for (var i = 0; i < idArray.length; i++) {
47972 array.push(this.body.nodes[idArray[i]]);
47973 }
47974
47975 return array;
47976 }
47977 /**
47978 * This function get the distribution of levels based on hubsize
47979 *
47980 * @returns {Object}
47981 * @private
47982 */
47983
47984 }, {
47985 key: "_getDistribution",
47986 value: function _getDistribution() {
47987 var distribution = {};
47988 var nodeId, node; // we fix Y because the hierarchy is vertical,
47989 // we fix X so we do not give a node an x position for a second time.
47990 // the fix of X is removed after the x value has been set.
47991
47992 for (nodeId in this.body.nodes) {
47993 if (this.body.nodes.hasOwnProperty(nodeId)) {
47994 node = this.body.nodes[nodeId];
47995 var level = this.hierarchical.levels[nodeId] === undefined ? 0 : this.hierarchical.levels[nodeId];
47996 this.direction.fix(node, level);
47997
47998 if (distribution[level] === undefined) {
47999 distribution[level] = {};
48000 }
48001
48002 distribution[level][nodeId] = node;
48003 }
48004 }
48005
48006 return distribution;
48007 }
48008 /**
48009 * Return the active (i.e. visible) edges for this node
48010 *
48011 * @param {Node} node
48012 * @returns {Array.<vis.Edge>} Array of edge instances
48013 * @private
48014 */
48015
48016 }, {
48017 key: "_getActiveEdges",
48018 value: function _getActiveEdges(node) {
48019 var _this4 = this;
48020
48021 var result = [];
48022 forEach(node.edges, function (edge) {
48023 if (_this4.body.edgeIndices.indexOf(edge.id) !== -1) {
48024 result.push(edge);
48025 }
48026 });
48027 return result;
48028 }
48029 /**
48030 * Get the hubsizes for all active nodes.
48031 *
48032 * @returns {number}
48033 * @private
48034 */
48035
48036 }, {
48037 key: "_getHubSizes",
48038 value: function _getHubSizes() {
48039 var _this5 = this;
48040
48041 var hubSizes = {};
48042 var nodeIds = this.body.nodeIndices;
48043 forEach(nodeIds, function (nodeId) {
48044 var node = _this5.body.nodes[nodeId];
48045
48046 var hubSize = _this5._getActiveEdges(node).length;
48047
48048 hubSizes[hubSize] = true;
48049 }); // Make an array of the size sorted descending
48050
48051 var result = [];
48052 forEach(hubSizes, function (size) {
48053 result.push(Number(size));
48054 });
48055 timsort$1.sort(result, function (a, b) {
48056 return b - a;
48057 });
48058 return result;
48059 }
48060 /**
48061 * this function allocates nodes in levels based on the recursive branching from the largest hubs.
48062 *
48063 * @private
48064 */
48065
48066 }, {
48067 key: "_determineLevelsByHubsize",
48068 value: function _determineLevelsByHubsize() {
48069 var _this6 = this;
48070
48071 var levelDownstream = function levelDownstream(nodeA, nodeB) {
48072 _this6.hierarchical.levelDownstream(nodeA, nodeB);
48073 };
48074
48075 var hubSizes = this._getHubSizes();
48076
48077 var _loop = function _loop(i) {
48078 var hubSize = hubSizes[i];
48079 if (hubSize === 0) return "break";
48080 forEach(_this6.body.nodeIndices, function (nodeId) {
48081 var node = _this6.body.nodes[nodeId];
48082
48083 if (hubSize === _this6._getActiveEdges(node).length) {
48084 _this6._crawlNetwork(levelDownstream, nodeId);
48085 }
48086 });
48087 };
48088
48089 for (var i = 0; i < hubSizes.length; ++i) {
48090 var _ret = _loop(i);
48091
48092 if (_ret === "break") break;
48093 }
48094 }
48095 /**
48096 * TODO: release feature
48097 * TODO: Determine if this feature is needed at all
48098 *
48099 * @private
48100 */
48101
48102 }, {
48103 key: "_determineLevelsCustomCallback",
48104 value: function _determineLevelsCustomCallback() {
48105 var _this7 = this;
48106
48107 var minLevel = 100000; // TODO: this should come from options.
48108
48109 var customCallback = function customCallback(nodeA, nodeB, edge) {// eslint-disable-line no-unused-vars
48110 }; // TODO: perhaps move to HierarchicalStatus.
48111 // But I currently don't see the point, this method is not used.
48112
48113
48114 var levelByDirection = function levelByDirection(nodeA, nodeB, edge) {
48115 var levelA = _this7.hierarchical.levels[nodeA.id]; // set initial level
48116
48117 if (levelA === undefined) {
48118 levelA = _this7.hierarchical.levels[nodeA.id] = minLevel;
48119 }
48120
48121 var diff = customCallback(NetworkUtil.cloneOptions(nodeA, 'node'), NetworkUtil.cloneOptions(nodeB, 'node'), NetworkUtil.cloneOptions(edge, 'edge'));
48122 _this7.hierarchical.levels[nodeB.id] = levelA + diff;
48123 };
48124
48125 this._crawlNetwork(levelByDirection);
48126
48127 this.hierarchical.setMinLevelToZero(this.body.nodes);
48128 }
48129 /**
48130 * Allocate nodes in levels based on the direction of the edges.
48131 *
48132 * @private
48133 */
48134
48135 }, {
48136 key: "_determineLevelsDirected",
48137 value: function _determineLevelsDirected() {
48138 var _this8 = this;
48139
48140 var nodes = this.body.nodeIndices.map(function (id) {
48141 return _this8.body.nodes[id];
48142 });
48143 var levels = this.hierarchical.levels;
48144
48145 if (this.options.hierarchical.shakeTowards === "roots") {
48146 this.hierarchical.levels = fillLevelsByDirectionRoots(nodes, this.hierarchical.levels);
48147 } else {
48148 this.hierarchical.levels = fillLevelsByDirectionLeaves(nodes, this.hierarchical.levels);
48149 }
48150
48151 this.hierarchical.setMinLevelToZero(this.body.nodes);
48152 }
48153 /**
48154 * Update the bookkeeping of parent and child.
48155 * @private
48156 */
48157
48158 }, {
48159 key: "_generateMap",
48160 value: function _generateMap() {
48161 var _this9 = this;
48162
48163 var fillInRelations = function fillInRelations(parentNode, childNode) {
48164 if (_this9.hierarchical.levels[childNode.id] > _this9.hierarchical.levels[parentNode.id]) {
48165 _this9.hierarchical.addRelation(parentNode.id, childNode.id);
48166 }
48167 };
48168
48169 this._crawlNetwork(fillInRelations);
48170
48171 this.hierarchical.checkIfTree();
48172 }
48173 /**
48174 * Crawl over the entire network and use a callback on each node couple that is connected to each other.
48175 * @param {function} [callback=function(){}] | will receive nodeA, nodeB and the connecting edge. A and B are distinct.
48176 * @param {Node.id} startingNodeId
48177 * @private
48178 */
48179
48180 }, {
48181 key: "_crawlNetwork",
48182 value: function _crawlNetwork() {
48183 var _this10 = this;
48184
48185 var callback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
48186 var startingNodeId = arguments.length > 1 ? arguments[1] : undefined;
48187 var progress = {};
48188
48189 var crawler = function crawler(node, tree) {
48190 if (progress[node.id] === undefined) {
48191 _this10.hierarchical.setTreeIndex(node, tree);
48192
48193 progress[node.id] = true;
48194 var childNode;
48195
48196 var edges = _this10._getActiveEdges(node);
48197
48198 for (var i = 0; i < edges.length; i++) {
48199 var edge = edges[i];
48200
48201 if (edge.connected === true) {
48202 if (edge.toId == node.id) {
48203 // Not '===' because id's can be string and numeric
48204 childNode = edge.from;
48205 } else {
48206 childNode = edge.to;
48207 }
48208
48209 if (node.id != childNode.id) {
48210 // Not '!==' because id's can be string and numeric
48211 callback(node, childNode, edge);
48212 crawler(childNode, tree);
48213 }
48214 }
48215 }
48216 }
48217 };
48218
48219 if (startingNodeId === undefined) {
48220 // Crawl over all nodes
48221 var treeIndex = 0; // Serves to pass a unique id for the current distinct tree
48222
48223 for (var i = 0; i < this.body.nodeIndices.length; i++) {
48224 var nodeId = this.body.nodeIndices[i];
48225
48226 if (progress[nodeId] === undefined) {
48227 var node = this.body.nodes[nodeId];
48228 crawler(node, treeIndex);
48229 treeIndex += 1;
48230 }
48231 }
48232 } else {
48233 // Crawl from the given starting node
48234 var _node2 = this.body.nodes[startingNodeId];
48235
48236 if (_node2 === undefined) {
48237 console.error("Node not found:", startingNodeId);
48238 return;
48239 }
48240
48241 crawler(_node2);
48242 }
48243 }
48244 /**
48245 * Shift a branch a certain distance
48246 * @param {Node.id} parentId
48247 * @param {number} diff
48248 * @private
48249 */
48250
48251 }, {
48252 key: "_shiftBlock",
48253 value: function _shiftBlock(parentId, diff) {
48254 var _this11 = this;
48255
48256 var progress = {};
48257
48258 var shifter = function shifter(parentId) {
48259 if (progress[parentId]) {
48260 return;
48261 }
48262
48263 progress[parentId] = true;
48264
48265 _this11.direction.shift(parentId, diff);
48266
48267 var childRef = _this11.hierarchical.childrenReference[parentId];
48268
48269 if (childRef !== undefined) {
48270 for (var i = 0; i < childRef.length; i++) {
48271 shifter(childRef[i]);
48272 }
48273 }
48274 };
48275
48276 shifter(parentId);
48277 }
48278 /**
48279 * Find a common parent between branches.
48280 * @param {Node.id} childA
48281 * @param {Node.id} childB
48282 * @returns {{foundParent, withChild}}
48283 * @private
48284 */
48285
48286 }, {
48287 key: "_findCommonParent",
48288 value: function _findCommonParent(childA, childB) {
48289 var _this12 = this;
48290
48291 var parents = {};
48292
48293 var iterateParents = function iterateParents(parents, child) {
48294 var parentRef = _this12.hierarchical.parentReference[child];
48295
48296 if (parentRef !== undefined) {
48297 for (var i = 0; i < parentRef.length; i++) {
48298 var parent = parentRef[i];
48299 parents[parent] = true;
48300 iterateParents(parents, parent);
48301 }
48302 }
48303 };
48304
48305 var findParent = function findParent(parents, child) {
48306 var parentRef = _this12.hierarchical.parentReference[child];
48307
48308 if (parentRef !== undefined) {
48309 for (var i = 0; i < parentRef.length; i++) {
48310 var parent = parentRef[i];
48311
48312 if (parents[parent] !== undefined) {
48313 return {
48314 foundParent: parent,
48315 withChild: child
48316 };
48317 }
48318
48319 var branch = findParent(parents, parent);
48320
48321 if (branch.foundParent !== null) {
48322 return branch;
48323 }
48324 }
48325 }
48326
48327 return {
48328 foundParent: null,
48329 withChild: child
48330 };
48331 };
48332
48333 iterateParents(parents, childA);
48334 return findParent(parents, childB);
48335 }
48336 /**
48337 * Set the strategy pattern for handling the coordinates given the current direction.
48338 *
48339 * The individual instances contain all the operations and data specific to a layout direction.
48340 *
48341 * @param {Node} node
48342 * @param {{x: number, y: number}} position
48343 * @param {number} level
48344 * @param {boolean} [doNotUpdate=false]
48345 * @private
48346 */
48347
48348 }, {
48349 key: "setDirectionStrategy",
48350 value: function setDirectionStrategy() {
48351 var isVertical = this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU';
48352
48353 if (isVertical) {
48354 this.direction = new VerticalStrategy(this);
48355 } else {
48356 this.direction = new HorizontalStrategy(this);
48357 }
48358 }
48359 /**
48360 * Determine the center position of a branch from the passed list of child nodes
48361 *
48362 * This takes into account the positions of all the child nodes.
48363 * @param {Array.<Node|vis.Node.id>} childNodes Array of either child nodes or node id's
48364 * @return {number}
48365 * @private
48366 */
48367
48368 }, {
48369 key: "_getCenterPosition",
48370 value: function _getCenterPosition(childNodes) {
48371 var minPos = 1e9;
48372 var maxPos = -1e9;
48373
48374 for (var i = 0; i < childNodes.length; i++) {
48375 var childNode = void 0;
48376
48377 if (childNodes[i].id !== undefined) {
48378 childNode = childNodes[i];
48379 } else {
48380 var childNodeId = childNodes[i];
48381 childNode = this.body.nodes[childNodeId];
48382 }
48383
48384 var position = this.direction.getPosition(childNode);
48385 minPos = Math.min(minPos, position);
48386 maxPos = Math.max(maxPos, position);
48387 }
48388
48389 return 0.5 * (minPos + maxPos);
48390 }
48391 }]);
48392
48393 return LayoutEngine;
48394 }();
48395
48396 /**
48397 * Clears the toolbar div element of children
48398 *
48399 * @private
48400 */
48401
48402 var ManipulationSystem =
48403 /*#__PURE__*/
48404 function () {
48405 /**
48406 * @param {Object} body
48407 * @param {Canvas} canvas
48408 * @param {SelectionHandler} selectionHandler
48409 */
48410 function ManipulationSystem(body, canvas, selectionHandler, interactionHandler) {
48411 var _this = this;
48412
48413 _classCallCheck(this, ManipulationSystem);
48414
48415 this.body = body;
48416 this.canvas = canvas;
48417 this.selectionHandler = selectionHandler;
48418 this.interactionHandler = interactionHandler;
48419 this.editMode = false;
48420 this.manipulationDiv = undefined;
48421 this.editModeDiv = undefined;
48422 this.closeDiv = undefined;
48423 this.manipulationHammers = [];
48424 this.temporaryUIFunctions = {};
48425 this.temporaryEventFunctions = [];
48426 this.touchTime = 0;
48427 this.temporaryIds = {
48428 nodes: [],
48429 edges: []
48430 };
48431 this.guiEnabled = false;
48432 this.inMode = false;
48433 this.selectedControlNode = undefined;
48434 this.options = {};
48435 this.defaultOptions = {
48436 enabled: false,
48437 initiallyActive: false,
48438 addNode: true,
48439 addEdge: true,
48440 editNode: undefined,
48441 editEdge: true,
48442 deleteNode: true,
48443 deleteEdge: true,
48444 controlNodeStyle: {
48445 shape: 'dot',
48446 size: 6,
48447 color: {
48448 background: '#ff0000',
48449 border: '#3c3c3c',
48450 highlight: {
48451 background: '#07f968',
48452 border: '#3c3c3c'
48453 }
48454 },
48455 borderWidth: 2,
48456 borderWidthSelected: 2
48457 }
48458 };
48459 extend(this.options, this.defaultOptions);
48460 this.body.emitter.on('destroy', function () {
48461 _this._clean();
48462 });
48463 this.body.emitter.on('_dataChanged', this._restore.bind(this));
48464 this.body.emitter.on('_resetData', this._restore.bind(this));
48465 }
48466 /**
48467 * If something changes in the data during editing, switch back to the initial datamanipulation state and close all edit modes.
48468 * @private
48469 */
48470
48471
48472 _createClass(ManipulationSystem, [{
48473 key: "_restore",
48474 value: function _restore() {
48475 if (this.inMode !== false) {
48476 if (this.options.initiallyActive === true) {
48477 this.enableEditMode();
48478 } else {
48479 this.disableEditMode();
48480 }
48481 }
48482 }
48483 /**
48484 * Set the Options
48485 *
48486 * @param {Object} options
48487 * @param {Object} allOptions
48488 * @param {Object} globalOptions
48489 */
48490
48491 }, {
48492 key: "setOptions",
48493 value: function setOptions(options, allOptions, globalOptions) {
48494 if (allOptions !== undefined) {
48495 if (allOptions.locale !== undefined) {
48496 this.options.locale = allOptions.locale;
48497 } else {
48498 this.options.locale = globalOptions.locale;
48499 }
48500
48501 if (allOptions.locales !== undefined) {
48502 this.options.locales = allOptions.locales;
48503 } else {
48504 this.options.locales = globalOptions.locales;
48505 }
48506 }
48507
48508 if (options !== undefined) {
48509 if (typeof options === 'boolean') {
48510 this.options.enabled = options;
48511 } else {
48512 this.options.enabled = true;
48513 deepExtend(this.options, options);
48514 }
48515
48516 if (this.options.initiallyActive === true) {
48517 this.editMode = true;
48518 }
48519
48520 this._setup();
48521 }
48522 }
48523 /**
48524 * Enable or disable edit-mode. Draws the DOM required and cleans up after itself.
48525 *
48526 * @private
48527 */
48528
48529 }, {
48530 key: "toggleEditMode",
48531 value: function toggleEditMode() {
48532 if (this.editMode === true) {
48533 this.disableEditMode();
48534 } else {
48535 this.enableEditMode();
48536 }
48537 }
48538 /**
48539 * Enables Edit Mode
48540 */
48541
48542 }, {
48543 key: "enableEditMode",
48544 value: function enableEditMode() {
48545 this.editMode = true;
48546
48547 this._clean();
48548
48549 if (this.guiEnabled === true) {
48550 this.manipulationDiv.style.display = 'block';
48551 this.closeDiv.style.display = 'block';
48552 this.editModeDiv.style.display = 'none';
48553 this.showManipulatorToolbar();
48554 }
48555 }
48556 /**
48557 * Disables Edit Mode
48558 */
48559
48560 }, {
48561 key: "disableEditMode",
48562 value: function disableEditMode() {
48563 this.editMode = false;
48564
48565 this._clean();
48566
48567 if (this.guiEnabled === true) {
48568 this.manipulationDiv.style.display = 'none';
48569 this.closeDiv.style.display = 'none';
48570 this.editModeDiv.style.display = 'block';
48571
48572 this._createEditButton();
48573 }
48574 }
48575 /**
48576 * Creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar.
48577 *
48578 * @private
48579 */
48580
48581 }, {
48582 key: "showManipulatorToolbar",
48583 value: function showManipulatorToolbar() {
48584 // restore the state of any bound functions or events, remove control nodes, restore physics
48585 this._clean(); // reset global variables
48586
48587
48588 this.manipulationDOM = {}; // if the gui is enabled, draw all elements.
48589
48590 if (this.guiEnabled === true) {
48591 // a _restore will hide these menus
48592 this.editMode = true;
48593 this.manipulationDiv.style.display = 'block';
48594 this.closeDiv.style.display = 'block';
48595
48596 var selectedNodeCount = this.selectionHandler._getSelectedNodeCount();
48597
48598 var selectedEdgeCount = this.selectionHandler._getSelectedEdgeCount();
48599
48600 var selectedTotalCount = selectedNodeCount + selectedEdgeCount;
48601 var locale = this.options.locales[this.options.locale];
48602 var needSeperator = false;
48603
48604 if (this.options.addNode !== false) {
48605 this._createAddNodeButton(locale);
48606
48607 needSeperator = true;
48608 }
48609
48610 if (this.options.addEdge !== false) {
48611 if (needSeperator === true) {
48612 this._createSeperator(1);
48613 } else {
48614 needSeperator = true;
48615 }
48616
48617 this._createAddEdgeButton(locale);
48618 }
48619
48620 if (selectedNodeCount === 1 && typeof this.options.editNode === 'function') {
48621 if (needSeperator === true) {
48622 this._createSeperator(2);
48623 } else {
48624 needSeperator = true;
48625 }
48626
48627 this._createEditNodeButton(locale);
48628 } else if (selectedEdgeCount === 1 && selectedNodeCount === 0 && this.options.editEdge !== false) {
48629 if (needSeperator === true) {
48630 this._createSeperator(3);
48631 } else {
48632 needSeperator = true;
48633 }
48634
48635 this._createEditEdgeButton(locale);
48636 } // remove buttons
48637
48638
48639 if (selectedTotalCount !== 0) {
48640 if (selectedNodeCount > 0 && this.options.deleteNode !== false) {
48641 if (needSeperator === true) {
48642 this._createSeperator(4);
48643 }
48644
48645 this._createDeleteButton(locale);
48646 } else if (selectedNodeCount === 0 && this.options.deleteEdge !== false) {
48647 if (needSeperator === true) {
48648 this._createSeperator(4);
48649 }
48650
48651 this._createDeleteButton(locale);
48652 }
48653 } // bind the close button
48654
48655
48656 this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this)); // refresh this bar based on what has been selected
48657
48658
48659 this._temporaryBindEvent('select', this.showManipulatorToolbar.bind(this));
48660 } // redraw to show any possible changes
48661
48662
48663 this.body.emitter.emit('_redraw');
48664 }
48665 /**
48666 * Create the toolbar for adding Nodes
48667 */
48668
48669 }, {
48670 key: "addNodeMode",
48671 value: function addNodeMode() {
48672 // when using the gui, enable edit mode if it wasnt already.
48673 if (this.editMode !== true) {
48674 this.enableEditMode();
48675 } // restore the state of any bound functions or events, remove control nodes, restore physics
48676
48677
48678 this._clean();
48679
48680 this.inMode = 'addNode';
48681
48682 if (this.guiEnabled === true) {
48683 var locale = this.options.locales[this.options.locale];
48684 this.manipulationDOM = {};
48685
48686 this._createBackButton(locale);
48687
48688 this._createSeperator();
48689
48690 this._createDescription(locale['addDescription'] || this.options.locales['en']['addDescription']); // bind the close button
48691
48692
48693 this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
48694 }
48695
48696 this._temporaryBindEvent('click', this._performAddNode.bind(this));
48697 }
48698 /**
48699 * call the bound function to handle the editing of the node. The node has to be selected.
48700 */
48701
48702 }, {
48703 key: "editNode",
48704 value: function editNode() {
48705 var _this2 = this;
48706
48707 // when using the gui, enable edit mode if it wasnt already.
48708 if (this.editMode !== true) {
48709 this.enableEditMode();
48710 } // restore the state of any bound functions or events, remove control nodes, restore physics
48711
48712
48713 this._clean();
48714
48715 var node = this.selectionHandler._getSelectedNode();
48716
48717 if (node !== undefined) {
48718 this.inMode = 'editNode';
48719
48720 if (typeof this.options.editNode === 'function') {
48721 if (node.isCluster !== true) {
48722 var data = deepExtend({}, node.options, false);
48723 data.x = node.x;
48724 data.y = node.y;
48725
48726 if (this.options.editNode.length === 2) {
48727 this.options.editNode(data, function (finalizedData) {
48728 if (finalizedData !== null && finalizedData !== undefined && _this2.inMode === 'editNode') {
48729 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
48730 _this2.body.data.nodes.getDataSet().update(finalizedData);
48731 }
48732
48733 _this2.showManipulatorToolbar();
48734 });
48735 } else {
48736 throw new Error('The function for edit does not support two arguments (data, callback)');
48737 }
48738 } else {
48739 alert(this.options.locales[this.options.locale]['editClusterError'] || this.options.locales['en']['editClusterError']);
48740 }
48741 } else {
48742 throw new Error('No function has been configured to handle the editing of nodes.');
48743 }
48744 } else {
48745 this.showManipulatorToolbar();
48746 }
48747 }
48748 /**
48749 * create the toolbar to connect nodes
48750 */
48751
48752 }, {
48753 key: "addEdgeMode",
48754 value: function addEdgeMode() {
48755 // when using the gui, enable edit mode if it wasnt already.
48756 if (this.editMode !== true) {
48757 this.enableEditMode();
48758 } // restore the state of any bound functions or events, remove control nodes, restore physics
48759
48760
48761 this._clean();
48762
48763 this.inMode = 'addEdge';
48764
48765 if (this.guiEnabled === true) {
48766 var locale = this.options.locales[this.options.locale];
48767 this.manipulationDOM = {};
48768
48769 this._createBackButton(locale);
48770
48771 this._createSeperator();
48772
48773 this._createDescription(locale['edgeDescription'] || this.options.locales['en']['edgeDescription']); // bind the close button
48774
48775
48776 this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
48777 } // temporarily overload functions
48778
48779
48780 this._temporaryBindUI('onTouch', this._handleConnect.bind(this));
48781
48782 this._temporaryBindUI('onDragEnd', this._finishConnect.bind(this));
48783
48784 this._temporaryBindUI('onDrag', this._dragControlNode.bind(this));
48785
48786 this._temporaryBindUI('onRelease', this._finishConnect.bind(this));
48787
48788 this._temporaryBindUI('onDragStart', this._dragStartEdge.bind(this));
48789
48790 this._temporaryBindUI('onHold', function () {});
48791 }
48792 /**
48793 * create the toolbar to edit edges
48794 */
48795
48796 }, {
48797 key: "editEdgeMode",
48798 value: function editEdgeMode() {
48799 // when using the gui, enable edit mode if it wasn't already.
48800 if (this.editMode !== true) {
48801 this.enableEditMode();
48802 } // restore the state of any bound functions or events, remove control nodes, restore physics
48803
48804
48805 this._clean();
48806
48807 this.inMode = 'editEdge';
48808
48809 if (_typeof$1(this.options.editEdge) === 'object' && typeof this.options.editEdge.editWithoutDrag === "function") {
48810 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdges()[0];
48811
48812 if (this.edgeBeingEditedId !== undefined) {
48813 var edge = this.body.edges[this.edgeBeingEditedId];
48814
48815 this._performEditEdge(edge.from.id, edge.to.id);
48816
48817 return;
48818 }
48819 }
48820
48821 if (this.guiEnabled === true) {
48822 var locale = this.options.locales[this.options.locale];
48823 this.manipulationDOM = {};
48824
48825 this._createBackButton(locale);
48826
48827 this._createSeperator();
48828
48829 this._createDescription(locale['editEdgeDescription'] || this.options.locales['en']['editEdgeDescription']); // bind the close button
48830
48831
48832 this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
48833 }
48834
48835 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdges()[0];
48836
48837 if (this.edgeBeingEditedId !== undefined) {
48838 var _edge = this.body.edges[this.edgeBeingEditedId]; // create control nodes
48839
48840 var controlNodeFrom = this._getNewTargetNode(_edge.from.x, _edge.from.y);
48841
48842 var controlNodeTo = this._getNewTargetNode(_edge.to.x, _edge.to.y);
48843
48844 this.temporaryIds.nodes.push(controlNodeFrom.id);
48845 this.temporaryIds.nodes.push(controlNodeTo.id);
48846 this.body.nodes[controlNodeFrom.id] = controlNodeFrom;
48847 this.body.nodeIndices.push(controlNodeFrom.id);
48848 this.body.nodes[controlNodeTo.id] = controlNodeTo;
48849 this.body.nodeIndices.push(controlNodeTo.id); // temporarily overload UI functions, cleaned up automatically because of _temporaryBindUI
48850
48851 this._temporaryBindUI('onTouch', this._controlNodeTouch.bind(this)); // used to get the position
48852
48853
48854 this._temporaryBindUI('onTap', function () {}); // disabled
48855
48856
48857 this._temporaryBindUI('onHold', function () {}); // disabled
48858
48859
48860 this._temporaryBindUI('onDragStart', this._controlNodeDragStart.bind(this)); // used to select control node
48861
48862
48863 this._temporaryBindUI('onDrag', this._controlNodeDrag.bind(this)); // used to drag control node
48864
48865
48866 this._temporaryBindUI('onDragEnd', this._controlNodeDragEnd.bind(this)); // used to connect or revert control nodes
48867
48868
48869 this._temporaryBindUI('onMouseMove', function () {}); // disabled
48870 // create function to position control nodes correctly on movement
48871 // automatically cleaned up because we use the temporary bind
48872
48873
48874 this._temporaryBindEvent('beforeDrawing', function (ctx) {
48875 var positions = _edge.edgeType.findBorderPositions(ctx);
48876
48877 if (controlNodeFrom.selected === false) {
48878 controlNodeFrom.x = positions.from.x;
48879 controlNodeFrom.y = positions.from.y;
48880 }
48881
48882 if (controlNodeTo.selected === false) {
48883 controlNodeTo.x = positions.to.x;
48884 controlNodeTo.y = positions.to.y;
48885 }
48886 });
48887
48888 this.body.emitter.emit('_redraw');
48889 } else {
48890 this.showManipulatorToolbar();
48891 }
48892 }
48893 /**
48894 * delete everything in the selection
48895 */
48896
48897 }, {
48898 key: "deleteSelected",
48899 value: function deleteSelected() {
48900 var _this3 = this;
48901
48902 // when using the gui, enable edit mode if it wasnt already.
48903 if (this.editMode !== true) {
48904 this.enableEditMode();
48905 } // restore the state of any bound functions or events, remove control nodes, restore physics
48906
48907
48908 this._clean();
48909
48910 this.inMode = 'delete';
48911 var selectedNodes = this.selectionHandler.getSelectedNodes();
48912 var selectedEdges = this.selectionHandler.getSelectedEdges();
48913 var deleteFunction = undefined;
48914
48915 if (selectedNodes.length > 0) {
48916 for (var i = 0; i < selectedNodes.length; i++) {
48917 if (this.body.nodes[selectedNodes[i]].isCluster === true) {
48918 alert(this.options.locales[this.options.locale]['deleteClusterError'] || this.options.locales['en']['deleteClusterError']);
48919 return;
48920 }
48921 }
48922
48923 if (typeof this.options.deleteNode === 'function') {
48924 deleteFunction = this.options.deleteNode;
48925 }
48926 } else if (selectedEdges.length > 0) {
48927 if (typeof this.options.deleteEdge === 'function') {
48928 deleteFunction = this.options.deleteEdge;
48929 }
48930 }
48931
48932 if (typeof deleteFunction === 'function') {
48933 var data = {
48934 nodes: selectedNodes,
48935 edges: selectedEdges
48936 };
48937
48938 if (deleteFunction.length === 2) {
48939 deleteFunction(data, function (finalizedData) {
48940 if (finalizedData !== null && finalizedData !== undefined && _this3.inMode === 'delete') {
48941 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
48942 _this3.body.data.edges.getDataSet().remove(finalizedData.edges);
48943
48944 _this3.body.data.nodes.getDataSet().remove(finalizedData.nodes);
48945
48946 _this3.body.emitter.emit('startSimulation');
48947
48948 _this3.showManipulatorToolbar();
48949 } else {
48950 _this3.body.emitter.emit('startSimulation');
48951
48952 _this3.showManipulatorToolbar();
48953 }
48954 });
48955 } else {
48956 throw new Error('The function for delete does not support two arguments (data, callback)');
48957 }
48958 } else {
48959 this.body.data.edges.getDataSet().remove(selectedEdges);
48960 this.body.data.nodes.getDataSet().remove(selectedNodes);
48961 this.body.emitter.emit('startSimulation');
48962 this.showManipulatorToolbar();
48963 }
48964 } //********************************************** PRIVATE ***************************************//
48965
48966 /**
48967 * draw or remove the DOM
48968 * @private
48969 */
48970
48971 }, {
48972 key: "_setup",
48973 value: function _setup() {
48974 if (this.options.enabled === true) {
48975 // Enable the GUI
48976 this.guiEnabled = true;
48977
48978 this._createWrappers();
48979
48980 if (this.editMode === false) {
48981 this._createEditButton();
48982 } else {
48983 this.showManipulatorToolbar();
48984 }
48985 } else {
48986 this._removeManipulationDOM(); // disable the gui
48987
48988
48989 this.guiEnabled = false;
48990 }
48991 }
48992 /**
48993 * create the div overlays that contain the DOM
48994 * @private
48995 */
48996
48997 }, {
48998 key: "_createWrappers",
48999 value: function _createWrappers() {
49000 // load the manipulator HTML elements. All styling done in css.
49001 if (this.manipulationDiv === undefined) {
49002 this.manipulationDiv = document.createElement('div');
49003 this.manipulationDiv.className = 'vis-manipulation';
49004
49005 if (this.editMode === true) {
49006 this.manipulationDiv.style.display = 'block';
49007 } else {
49008 this.manipulationDiv.style.display = 'none';
49009 }
49010
49011 this.canvas.frame.appendChild(this.manipulationDiv);
49012 } // container for the edit button.
49013
49014
49015 if (this.editModeDiv === undefined) {
49016 this.editModeDiv = document.createElement('div');
49017 this.editModeDiv.className = 'vis-edit-mode';
49018
49019 if (this.editMode === true) {
49020 this.editModeDiv.style.display = 'none';
49021 } else {
49022 this.editModeDiv.style.display = 'block';
49023 }
49024
49025 this.canvas.frame.appendChild(this.editModeDiv);
49026 } // container for the close div button
49027
49028
49029 if (this.closeDiv === undefined) {
49030 this.closeDiv = document.createElement('div');
49031 this.closeDiv.className = 'vis-close';
49032 this.closeDiv.style.display = this.manipulationDiv.style.display;
49033 this.canvas.frame.appendChild(this.closeDiv);
49034 }
49035 }
49036 /**
49037 * generate a new target node. Used for creating new edges and editing edges
49038 *
49039 * @param {number} x
49040 * @param {number} y
49041 * @returns {Node}
49042 * @private
49043 */
49044
49045 }, {
49046 key: "_getNewTargetNode",
49047 value: function _getNewTargetNode(x, y) {
49048 var controlNodeStyle = deepExtend({}, this.options.controlNodeStyle);
49049 controlNodeStyle.id = 'targetNode' + uuid4();
49050 controlNodeStyle.hidden = false;
49051 controlNodeStyle.physics = false;
49052 controlNodeStyle.x = x;
49053 controlNodeStyle.y = y; // we have to define the bounding box in order for the nodes to be drawn immediately
49054
49055 var node = this.body.functions.createNode(controlNodeStyle);
49056 node.shape.boundingBox = {
49057 left: x,
49058 right: x,
49059 top: y,
49060 bottom: y
49061 };
49062 return node;
49063 }
49064 /**
49065 * Create the edit button
49066 */
49067
49068 }, {
49069 key: "_createEditButton",
49070 value: function _createEditButton() {
49071 // restore everything to it's original state (if applicable)
49072 this._clean(); // reset the manipulationDOM
49073
49074
49075 this.manipulationDOM = {}; // empty the editModeDiv
49076
49077 recursiveDOMDelete(this.editModeDiv); // create the contents for the editMode button
49078
49079 var locale = this.options.locales[this.options.locale];
49080
49081 var button = this._createButton('editMode', 'vis-button vis-edit vis-edit-mode', locale['edit'] || this.options.locales['en']['edit']);
49082
49083 this.editModeDiv.appendChild(button); // bind a hammer listener to the button, calling the function toggleEditMode.
49084
49085 this._bindHammerToDiv(button, this.toggleEditMode.bind(this));
49086 }
49087 /**
49088 * this function cleans up after everything this module does. Temporary elements, functions and events are removed, physics restored, hammers removed.
49089 * @private
49090 */
49091
49092 }, {
49093 key: "_clean",
49094 value: function _clean() {
49095 // not in mode
49096 this.inMode = false; // _clean the divs
49097
49098 if (this.guiEnabled === true) {
49099 recursiveDOMDelete(this.editModeDiv);
49100 recursiveDOMDelete(this.manipulationDiv); // removes all the bindings and overloads
49101
49102 this._cleanManipulatorHammers();
49103 } // remove temporary nodes and edges
49104
49105
49106 this._cleanupTemporaryNodesAndEdges(); // restore overloaded UI functions
49107
49108
49109 this._unbindTemporaryUIs(); // remove the temporaryEventFunctions
49110
49111
49112 this._unbindTemporaryEvents(); // restore the physics if required
49113
49114
49115 this.body.emitter.emit('restorePhysics');
49116 }
49117 /**
49118 * Each dom element has it's own hammer. They are stored in this.manipulationHammers. This cleans them up.
49119 * @private
49120 */
49121
49122 }, {
49123 key: "_cleanManipulatorHammers",
49124 value: function _cleanManipulatorHammers() {
49125 // _clean hammer bindings
49126 if (this.manipulationHammers.length != 0) {
49127 for (var i = 0; i < this.manipulationHammers.length; i++) {
49128 this.manipulationHammers[i].destroy();
49129 }
49130
49131 this.manipulationHammers = [];
49132 }
49133 }
49134 /**
49135 * Remove all DOM elements created by this module.
49136 * @private
49137 */
49138
49139 }, {
49140 key: "_removeManipulationDOM",
49141 value: function _removeManipulationDOM() {
49142 // removes all the bindings and overloads
49143 this._clean(); // empty the manipulation divs
49144
49145
49146 recursiveDOMDelete(this.manipulationDiv);
49147 recursiveDOMDelete(this.editModeDiv);
49148 recursiveDOMDelete(this.closeDiv); // remove the manipulation divs
49149
49150 if (this.manipulationDiv) {
49151 this.canvas.frame.removeChild(this.manipulationDiv);
49152 }
49153
49154 if (this.editModeDiv) {
49155 this.canvas.frame.removeChild(this.editModeDiv);
49156 }
49157
49158 if (this.closeDiv) {
49159 this.canvas.frame.removeChild(this.closeDiv);
49160 } // set the references to undefined
49161
49162
49163 this.manipulationDiv = undefined;
49164 this.editModeDiv = undefined;
49165 this.closeDiv = undefined;
49166 }
49167 /**
49168 * create a seperator line. the index is to differentiate in the manipulation dom
49169 * @param {number} [index=1]
49170 * @private
49171 */
49172
49173 }, {
49174 key: "_createSeperator",
49175 value: function _createSeperator() {
49176 var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
49177 this.manipulationDOM['seperatorLineDiv' + index] = document.createElement('div');
49178 this.manipulationDOM['seperatorLineDiv' + index].className = 'vis-separator-line';
49179 this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv' + index]);
49180 } // ---------------------- DOM functions for buttons --------------------------//
49181
49182 /**
49183 *
49184 * @param {Locale} locale
49185 * @private
49186 */
49187
49188 }, {
49189 key: "_createAddNodeButton",
49190 value: function _createAddNodeButton(locale) {
49191 var button = this._createButton('addNode', 'vis-button vis-add', locale['addNode'] || this.options.locales['en']['addNode']);
49192
49193 this.manipulationDiv.appendChild(button);
49194
49195 this._bindHammerToDiv(button, this.addNodeMode.bind(this));
49196 }
49197 /**
49198 *
49199 * @param {Locale} locale
49200 * @private
49201 */
49202
49203 }, {
49204 key: "_createAddEdgeButton",
49205 value: function _createAddEdgeButton(locale) {
49206 var button = this._createButton('addEdge', 'vis-button vis-connect', locale['addEdge'] || this.options.locales['en']['addEdge']);
49207
49208 this.manipulationDiv.appendChild(button);
49209
49210 this._bindHammerToDiv(button, this.addEdgeMode.bind(this));
49211 }
49212 /**
49213 *
49214 * @param {Locale} locale
49215 * @private
49216 */
49217
49218 }, {
49219 key: "_createEditNodeButton",
49220 value: function _createEditNodeButton(locale) {
49221 var button = this._createButton('editNode', 'vis-button vis-edit', locale['editNode'] || this.options.locales['en']['editNode']);
49222
49223 this.manipulationDiv.appendChild(button);
49224
49225 this._bindHammerToDiv(button, this.editNode.bind(this));
49226 }
49227 /**
49228 *
49229 * @param {Locale} locale
49230 * @private
49231 */
49232
49233 }, {
49234 key: "_createEditEdgeButton",
49235 value: function _createEditEdgeButton(locale) {
49236 var button = this._createButton('editEdge', 'vis-button vis-edit', locale['editEdge'] || this.options.locales['en']['editEdge']);
49237
49238 this.manipulationDiv.appendChild(button);
49239
49240 this._bindHammerToDiv(button, this.editEdgeMode.bind(this));
49241 }
49242 /**
49243 *
49244 * @param {Locale} locale
49245 * @private
49246 */
49247
49248 }, {
49249 key: "_createDeleteButton",
49250 value: function _createDeleteButton(locale) {
49251 var deleteBtnClass;
49252
49253 if (this.options.rtl) {
49254 deleteBtnClass = 'vis-button vis-delete-rtl';
49255 } else {
49256 deleteBtnClass = 'vis-button vis-delete';
49257 }
49258
49259 var button = this._createButton('delete', deleteBtnClass, locale['del'] || this.options.locales['en']['del']);
49260
49261 this.manipulationDiv.appendChild(button);
49262
49263 this._bindHammerToDiv(button, this.deleteSelected.bind(this));
49264 }
49265 /**
49266 *
49267 * @param {Locale} locale
49268 * @private
49269 */
49270
49271 }, {
49272 key: "_createBackButton",
49273 value: function _createBackButton(locale) {
49274 var button = this._createButton('back', 'vis-button vis-back', locale['back'] || this.options.locales['en']['back']);
49275
49276 this.manipulationDiv.appendChild(button);
49277
49278 this._bindHammerToDiv(button, this.showManipulatorToolbar.bind(this));
49279 }
49280 /**
49281 *
49282 * @param {number|string} id
49283 * @param {string} className
49284 * @param {label} label
49285 * @param {string} labelClassName
49286 * @returns {HTMLElement}
49287 * @private
49288 */
49289
49290 }, {
49291 key: "_createButton",
49292 value: function _createButton(id, className, label) {
49293 var labelClassName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'vis-label';
49294 this.manipulationDOM[id + 'Div'] = document.createElement('div');
49295 this.manipulationDOM[id + 'Div'].className = className;
49296 this.manipulationDOM[id + 'Label'] = document.createElement('div');
49297 this.manipulationDOM[id + 'Label'].className = labelClassName;
49298 this.manipulationDOM[id + 'Label'].innerHTML = label;
49299 this.manipulationDOM[id + 'Div'].appendChild(this.manipulationDOM[id + 'Label']);
49300 return this.manipulationDOM[id + 'Div'];
49301 }
49302 /**
49303 *
49304 * @param {Label} label
49305 * @private
49306 */
49307
49308 }, {
49309 key: "_createDescription",
49310 value: function _createDescription(label) {
49311 this.manipulationDiv.appendChild(this._createButton('description', 'vis-button vis-none', label));
49312 } // -------------------------- End of DOM functions for buttons ------------------------------//
49313
49314 /**
49315 * this binds an event until cleanup by the clean functions.
49316 * @param {Event} event The event
49317 * @param {function} newFunction
49318 * @private
49319 */
49320
49321 }, {
49322 key: "_temporaryBindEvent",
49323 value: function _temporaryBindEvent(event, newFunction) {
49324 this.temporaryEventFunctions.push({
49325 event: event,
49326 boundFunction: newFunction
49327 });
49328 this.body.emitter.on(event, newFunction);
49329 }
49330 /**
49331 * this overrides an UI function until cleanup by the clean function
49332 * @param {string} UIfunctionName
49333 * @param {function} newFunction
49334 * @private
49335 */
49336
49337 }, {
49338 key: "_temporaryBindUI",
49339 value: function _temporaryBindUI(UIfunctionName, newFunction) {
49340 if (this.body.eventListeners[UIfunctionName] !== undefined) {
49341 this.temporaryUIFunctions[UIfunctionName] = this.body.eventListeners[UIfunctionName];
49342 this.body.eventListeners[UIfunctionName] = newFunction;
49343 } else {
49344 throw new Error('This UI function does not exist. Typo? You tried: ' + UIfunctionName + ' possible are: ' + JSON.stringify(Object.keys(this.body.eventListeners)));
49345 }
49346 }
49347 /**
49348 * Restore the overridden UI functions to their original state.
49349 *
49350 * @private
49351 */
49352
49353 }, {
49354 key: "_unbindTemporaryUIs",
49355 value: function _unbindTemporaryUIs() {
49356 for (var functionName in this.temporaryUIFunctions) {
49357 if (this.temporaryUIFunctions.hasOwnProperty(functionName)) {
49358 this.body.eventListeners[functionName] = this.temporaryUIFunctions[functionName];
49359 delete this.temporaryUIFunctions[functionName];
49360 }
49361 }
49362
49363 this.temporaryUIFunctions = {};
49364 }
49365 /**
49366 * Unbind the events created by _temporaryBindEvent
49367 * @private
49368 */
49369
49370 }, {
49371 key: "_unbindTemporaryEvents",
49372 value: function _unbindTemporaryEvents() {
49373 for (var i = 0; i < this.temporaryEventFunctions.length; i++) {
49374 var eventName = this.temporaryEventFunctions[i].event;
49375 var boundFunction = this.temporaryEventFunctions[i].boundFunction;
49376 this.body.emitter.off(eventName, boundFunction);
49377 }
49378
49379 this.temporaryEventFunctions = [];
49380 }
49381 /**
49382 * Bind an hammer instance to a DOM element.
49383 *
49384 * @param {Element} domElement
49385 * @param {function} boundFunction
49386 */
49387
49388 }, {
49389 key: "_bindHammerToDiv",
49390 value: function _bindHammerToDiv(domElement, boundFunction) {
49391 var hammer$1 = new hammer(domElement, {});
49392 hammerUtil.onTouch(hammer$1, boundFunction);
49393 this.manipulationHammers.push(hammer$1);
49394 }
49395 /**
49396 * Neatly clean up temporary edges and nodes
49397 * @private
49398 */
49399
49400 }, {
49401 key: "_cleanupTemporaryNodesAndEdges",
49402 value: function _cleanupTemporaryNodesAndEdges() {
49403 // _clean temporary edges
49404 for (var i = 0; i < this.temporaryIds.edges.length; i++) {
49405 this.body.edges[this.temporaryIds.edges[i]].disconnect();
49406 delete this.body.edges[this.temporaryIds.edges[i]];
49407 var indexTempEdge = this.body.edgeIndices.indexOf(this.temporaryIds.edges[i]);
49408
49409 if (indexTempEdge !== -1) {
49410 this.body.edgeIndices.splice(indexTempEdge, 1);
49411 }
49412 } // _clean temporary nodes
49413
49414
49415 for (var _i = 0; _i < this.temporaryIds.nodes.length; _i++) {
49416 delete this.body.nodes[this.temporaryIds.nodes[_i]];
49417 var indexTempNode = this.body.nodeIndices.indexOf(this.temporaryIds.nodes[_i]);
49418
49419 if (indexTempNode !== -1) {
49420 this.body.nodeIndices.splice(indexTempNode, 1);
49421 }
49422 }
49423
49424 this.temporaryIds = {
49425 nodes: [],
49426 edges: []
49427 };
49428 } // ------------------------------------------ EDIT EDGE FUNCTIONS -----------------------------------------//
49429
49430 /**
49431 * the touch is used to get the position of the initial click
49432 * @param {Event} event The event
49433 * @private
49434 */
49435
49436 }, {
49437 key: "_controlNodeTouch",
49438 value: function _controlNodeTouch(event) {
49439 this.selectionHandler.unselectAll();
49440 this.lastTouch = this.body.functions.getPointer(event.center);
49441 this.lastTouch.translation = extend({}, this.body.view.translation); // copy the object
49442 }
49443 /**
49444 * the drag start is used to mark one of the control nodes as selected.
49445 * @param {Event} event The event
49446 * @private
49447 */
49448
49449 }, {
49450 key: "_controlNodeDragStart",
49451 value: function _controlNodeDragStart(event) {
49452 // eslint-disable-line no-unused-vars
49453 var pointer = this.lastTouch;
49454
49455 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
49456
49457 var from = this.body.nodes[this.temporaryIds.nodes[0]];
49458 var to = this.body.nodes[this.temporaryIds.nodes[1]];
49459 var edge = this.body.edges[this.edgeBeingEditedId];
49460 this.selectedControlNode = undefined;
49461 var fromSelect = from.isOverlappingWith(pointerObj);
49462 var toSelect = to.isOverlappingWith(pointerObj);
49463
49464 if (fromSelect === true) {
49465 this.selectedControlNode = from;
49466 edge.edgeType.from = from;
49467 } else if (toSelect === true) {
49468 this.selectedControlNode = to;
49469 edge.edgeType.to = to;
49470 } // we use the selection to find the node that is being dragged. We explicitly select it here.
49471
49472
49473 if (this.selectedControlNode !== undefined) {
49474 this.selectionHandler.selectObject(this.selectedControlNode);
49475 }
49476
49477 this.body.emitter.emit('_redraw');
49478 }
49479 /**
49480 * dragging the control nodes or the canvas
49481 * @param {Event} event The event
49482 * @private
49483 */
49484
49485 }, {
49486 key: "_controlNodeDrag",
49487 value: function _controlNodeDrag(event) {
49488 this.body.emitter.emit('disablePhysics');
49489 var pointer = this.body.functions.getPointer(event.center);
49490 var pos = this.canvas.DOMtoCanvas(pointer);
49491
49492 if (this.selectedControlNode !== undefined) {
49493 this.selectedControlNode.x = pos.x;
49494 this.selectedControlNode.y = pos.y;
49495 } else {
49496 this.interactionHandler.onDrag(event);
49497 }
49498
49499 this.body.emitter.emit('_redraw');
49500 }
49501 /**
49502 * connecting or restoring the control nodes.
49503 * @param {Event} event The event
49504 * @private
49505 */
49506
49507 }, {
49508 key: "_controlNodeDragEnd",
49509 value: function _controlNodeDragEnd(event) {
49510 var pointer = this.body.functions.getPointer(event.center);
49511
49512 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
49513
49514 var edge = this.body.edges[this.edgeBeingEditedId]; // if the node that was dragged is not a control node, return
49515
49516 if (this.selectedControlNode === undefined) {
49517 return;
49518 } // we use the selection to find the node that is being dragged. We explicitly DEselect the control node here.
49519
49520
49521 this.selectionHandler.unselectAll();
49522
49523 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
49524
49525 var node = undefined;
49526
49527 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
49528 if (overlappingNodeIds[i] !== this.selectedControlNode.id) {
49529 node = this.body.nodes[overlappingNodeIds[i]];
49530 break;
49531 }
49532 } // perform the connection
49533
49534
49535 if (node !== undefined && this.selectedControlNode !== undefined) {
49536 if (node.isCluster === true) {
49537 alert(this.options.locales[this.options.locale]['createEdgeError'] || this.options.locales['en']['createEdgeError']);
49538 } else {
49539 var from = this.body.nodes[this.temporaryIds.nodes[0]];
49540
49541 if (this.selectedControlNode.id === from.id) {
49542 this._performEditEdge(node.id, edge.to.id);
49543 } else {
49544 this._performEditEdge(edge.from.id, node.id);
49545 }
49546 }
49547 } else {
49548 edge.updateEdgeType();
49549 this.body.emitter.emit('restorePhysics');
49550 }
49551
49552 this.body.emitter.emit('_redraw');
49553 } // ------------------------------------ END OF EDIT EDGE FUNCTIONS -----------------------------------------//
49554 // ------------------------------------------- ADD EDGE FUNCTIONS -----------------------------------------//
49555
49556 /**
49557 * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
49558 * to walk the user through the process.
49559 *
49560 * @param {Event} event
49561 * @private
49562 */
49563
49564 }, {
49565 key: "_handleConnect",
49566 value: function _handleConnect(event) {
49567 // check to avoid double fireing of this function.
49568 if (new Date().valueOf() - this.touchTime > 100) {
49569 this.lastTouch = this.body.functions.getPointer(event.center);
49570 this.lastTouch.translation = extend({}, this.body.view.translation); // copy the object
49571
49572 var pointer = this.lastTouch;
49573 var node = this.selectionHandler.getNodeAt(pointer);
49574
49575 if (node !== undefined) {
49576 if (node.isCluster === true) {
49577 alert(this.options.locales[this.options.locale]['createEdgeError'] || this.options.locales['en']['createEdgeError']);
49578 } else {
49579 // create a node the temporary line can look at
49580 var targetNode = this._getNewTargetNode(node.x, node.y);
49581
49582 this.body.nodes[targetNode.id] = targetNode;
49583 this.body.nodeIndices.push(targetNode.id); // create a temporary edge
49584
49585 var connectionEdge = this.body.functions.createEdge({
49586 id: 'connectionEdge' + uuid4(),
49587 from: node.id,
49588 to: targetNode.id,
49589 physics: false,
49590 smooth: {
49591 enabled: true,
49592 type: 'continuous',
49593 roundness: 0.5
49594 }
49595 });
49596 this.body.edges[connectionEdge.id] = connectionEdge;
49597 this.body.edgeIndices.push(connectionEdge.id);
49598 this.temporaryIds.nodes.push(targetNode.id);
49599 this.temporaryIds.edges.push(connectionEdge.id);
49600 }
49601 }
49602
49603 this.touchTime = new Date().valueOf();
49604 }
49605 }
49606 /**
49607 *
49608 * @param {Event} event
49609 * @private
49610 */
49611
49612 }, {
49613 key: "_dragControlNode",
49614 value: function _dragControlNode(event) {
49615 var pointer = this.body.functions.getPointer(event.center);
49616
49617 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
49618
49619
49620 var connectFromId = undefined;
49621
49622 if (this.temporaryIds.edges[0] !== undefined) {
49623 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
49624 } // get the overlapping node but NOT the temporary node;
49625
49626
49627 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
49628
49629 var node = undefined;
49630
49631 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
49632 // if the node id is NOT a temporary node, accept the node.
49633 if (this.temporaryIds.nodes.indexOf(overlappingNodeIds[i]) === -1) {
49634 node = this.body.nodes[overlappingNodeIds[i]];
49635 break;
49636 }
49637 }
49638
49639 event.controlEdge = {
49640 from: connectFromId,
49641 to: node ? node.id : undefined
49642 };
49643
49644 this.selectionHandler._generateClickEvent('controlNodeDragging', event, pointer);
49645
49646 if (this.temporaryIds.nodes[0] !== undefined) {
49647 var targetNode = this.body.nodes[this.temporaryIds.nodes[0]]; // there is only one temp node in the add edge mode.
49648
49649 targetNode.x = this.canvas._XconvertDOMtoCanvas(pointer.x);
49650 targetNode.y = this.canvas._YconvertDOMtoCanvas(pointer.y);
49651 this.body.emitter.emit('_redraw');
49652 } else {
49653 this.interactionHandler.onDrag(event);
49654 }
49655 }
49656 /**
49657 * Connect the new edge to the target if one exists, otherwise remove temp line
49658 * @param {Event} event The event
49659 * @private
49660 */
49661
49662 }, {
49663 key: "_finishConnect",
49664 value: function _finishConnect(event) {
49665 var pointer = this.body.functions.getPointer(event.center);
49666
49667 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
49668
49669
49670 var connectFromId = undefined;
49671
49672 if (this.temporaryIds.edges[0] !== undefined) {
49673 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
49674 } // get the overlapping node but NOT the temporary node;
49675
49676
49677 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
49678
49679 var node = undefined;
49680
49681 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
49682 // if the node id is NOT a temporary node, accept the node.
49683 if (this.temporaryIds.nodes.indexOf(overlappingNodeIds[i]) === -1) {
49684 node = this.body.nodes[overlappingNodeIds[i]];
49685 break;
49686 }
49687 } // clean temporary nodes and edges.
49688
49689
49690 this._cleanupTemporaryNodesAndEdges(); // perform the connection
49691
49692
49693 if (node !== undefined) {
49694 if (node.isCluster === true) {
49695 alert(this.options.locales[this.options.locale]['createEdgeError'] || this.options.locales['en']['createEdgeError']);
49696 } else {
49697 if (this.body.nodes[connectFromId] !== undefined && this.body.nodes[node.id] !== undefined) {
49698 this._performAddEdge(connectFromId, node.id);
49699 }
49700 }
49701 }
49702
49703 event.controlEdge = {
49704 from: connectFromId,
49705 to: node ? node.id : undefined
49706 };
49707
49708 this.selectionHandler._generateClickEvent('controlNodeDragEnd', event, pointer); // No need to do _generateclickevent('dragEnd') here, the regular dragEnd event fires.
49709
49710
49711 this.body.emitter.emit('_redraw');
49712 }
49713 /**
49714 *
49715 * @param {Event} event
49716 * @private
49717 */
49718
49719 }, {
49720 key: "_dragStartEdge",
49721 value: function _dragStartEdge(event) {
49722 var pointer = this.lastTouch;
49723
49724 this.selectionHandler._generateClickEvent('dragStart', event, pointer, undefined, true);
49725 } // --------------------------------------- END OF ADD EDGE FUNCTIONS -------------------------------------//
49726 // ------------------------------ Performing all the actual data manipulation ------------------------//
49727
49728 /**
49729 * Adds a node on the specified location
49730 *
49731 * @param {Object} clickData
49732 * @private
49733 */
49734
49735 }, {
49736 key: "_performAddNode",
49737 value: function _performAddNode(clickData) {
49738 var _this4 = this;
49739
49740 var defaultData = {
49741 id: uuid4(),
49742 x: clickData.pointer.canvas.x,
49743 y: clickData.pointer.canvas.y,
49744 label: 'new'
49745 };
49746
49747 if (typeof this.options.addNode === 'function') {
49748 if (this.options.addNode.length === 2) {
49749 this.options.addNode(defaultData, function (finalizedData) {
49750 if (finalizedData !== null && finalizedData !== undefined && _this4.inMode === 'addNode') {
49751 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
49752 _this4.body.data.nodes.getDataSet().add(finalizedData);
49753 }
49754
49755 _this4.showManipulatorToolbar();
49756 });
49757 } else {
49758 this.showManipulatorToolbar();
49759 throw new Error('The function for add does not support two arguments (data,callback)');
49760 }
49761 } else {
49762 this.body.data.nodes.getDataSet().add(defaultData);
49763 this.showManipulatorToolbar();
49764 }
49765 }
49766 /**
49767 * connect two nodes with a new edge.
49768 *
49769 * @param {Node.id} sourceNodeId
49770 * @param {Node.id} targetNodeId
49771 * @private
49772 */
49773
49774 }, {
49775 key: "_performAddEdge",
49776 value: function _performAddEdge(sourceNodeId, targetNodeId) {
49777 var _this5 = this;
49778
49779 var defaultData = {
49780 from: sourceNodeId,
49781 to: targetNodeId
49782 };
49783
49784 if (typeof this.options.addEdge === 'function') {
49785 if (this.options.addEdge.length === 2) {
49786 this.options.addEdge(defaultData, function (finalizedData) {
49787 if (finalizedData !== null && finalizedData !== undefined && _this5.inMode === 'addEdge') {
49788 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
49789 _this5.body.data.edges.getDataSet().add(finalizedData);
49790
49791 _this5.selectionHandler.unselectAll();
49792
49793 _this5.showManipulatorToolbar();
49794 }
49795 });
49796 } else {
49797 throw new Error('The function for connect does not support two arguments (data,callback)');
49798 }
49799 } else {
49800 this.body.data.edges.getDataSet().add(defaultData);
49801 this.selectionHandler.unselectAll();
49802 this.showManipulatorToolbar();
49803 }
49804 }
49805 /**
49806 * connect two nodes with a new edge.
49807 *
49808 * @param {Node.id} sourceNodeId
49809 * @param {Node.id} targetNodeId
49810 * @private
49811 */
49812
49813 }, {
49814 key: "_performEditEdge",
49815 value: function _performEditEdge(sourceNodeId, targetNodeId) {
49816 var _this6 = this;
49817
49818 var defaultData = {
49819 id: this.edgeBeingEditedId,
49820 from: sourceNodeId,
49821 to: targetNodeId,
49822 label: this.body.data.edges._data[this.edgeBeingEditedId].label
49823 };
49824 var eeFunct = this.options.editEdge;
49825
49826 if (_typeof$1(eeFunct) === 'object') {
49827 eeFunct = eeFunct.editWithoutDrag;
49828 }
49829
49830 if (typeof eeFunct === 'function') {
49831 if (eeFunct.length === 2) {
49832 eeFunct(defaultData, function (finalizedData) {
49833 if (finalizedData === null || finalizedData === undefined || _this6.inMode !== 'editEdge') {
49834 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
49835 _this6.body.edges[defaultData.id].updateEdgeType();
49836
49837 _this6.body.emitter.emit('_redraw');
49838
49839 _this6.showManipulatorToolbar();
49840 } else {
49841 _this6.body.data.edges.getDataSet().update(finalizedData);
49842
49843 _this6.selectionHandler.unselectAll();
49844
49845 _this6.showManipulatorToolbar();
49846 }
49847 });
49848 } else {
49849 throw new Error('The function for edit does not support two arguments (data, callback)');
49850 }
49851 } else {
49852 this.body.data.edges.getDataSet().update(defaultData);
49853 this.selectionHandler.unselectAll();
49854 this.showManipulatorToolbar();
49855 }
49856 }
49857 }]);
49858
49859 return ManipulationSystem;
49860 }();
49861
49862 var htmlColors = {
49863 black: '#000000',
49864 navy: '#000080',
49865 darkblue: '#00008B',
49866 mediumblue: '#0000CD',
49867 blue: '#0000FF',
49868 darkgreen: '#006400',
49869 green: '#008000',
49870 teal: '#008080',
49871 darkcyan: '#008B8B',
49872 deepskyblue: '#00BFFF',
49873 darkturquoise: '#00CED1',
49874 mediumspringgreen: '#00FA9A',
49875 lime: '#00FF00',
49876 springgreen: '#00FF7F',
49877 aqua: '#00FFFF',
49878 cyan: '#00FFFF',
49879 midnightblue: '#191970',
49880 dodgerblue: '#1E90FF',
49881 lightseagreen: '#20B2AA',
49882 forestgreen: '#228B22',
49883 seagreen: '#2E8B57',
49884 darkslategray: '#2F4F4F',
49885 limegreen: '#32CD32',
49886 mediumseagreen: '#3CB371',
49887 turquoise: '#40E0D0',
49888 royalblue: '#4169E1',
49889 steelblue: '#4682B4',
49890 darkslateblue: '#483D8B',
49891 mediumturquoise: '#48D1CC',
49892 indigo: '#4B0082',
49893 darkolivegreen: '#556B2F',
49894 cadetblue: '#5F9EA0',
49895 cornflowerblue: '#6495ED',
49896 mediumaquamarine: '#66CDAA',
49897 dimgray: '#696969',
49898 slateblue: '#6A5ACD',
49899 olivedrab: '#6B8E23',
49900 slategray: '#708090',
49901 lightslategray: '#778899',
49902 mediumslateblue: '#7B68EE',
49903 lawngreen: '#7CFC00',
49904 chartreuse: '#7FFF00',
49905 aquamarine: '#7FFFD4',
49906 maroon: '#800000',
49907 purple: '#800080',
49908 olive: '#808000',
49909 gray: '#808080',
49910 skyblue: '#87CEEB',
49911 lightskyblue: '#87CEFA',
49912 blueviolet: '#8A2BE2',
49913 darkred: '#8B0000',
49914 darkmagenta: '#8B008B',
49915 saddlebrown: '#8B4513',
49916 darkseagreen: '#8FBC8F',
49917 lightgreen: '#90EE90',
49918 mediumpurple: '#9370D8',
49919 darkviolet: '#9400D3',
49920 palegreen: '#98FB98',
49921 darkorchid: '#9932CC',
49922 yellowgreen: '#9ACD32',
49923 sienna: '#A0522D',
49924 brown: '#A52A2A',
49925 darkgray: '#A9A9A9',
49926 lightblue: '#ADD8E6',
49927 greenyellow: '#ADFF2F',
49928 paleturquoise: '#AFEEEE',
49929 lightsteelblue: '#B0C4DE',
49930 powderblue: '#B0E0E6',
49931 firebrick: '#B22222',
49932 darkgoldenrod: '#B8860B',
49933 mediumorchid: '#BA55D3',
49934 rosybrown: '#BC8F8F',
49935 darkkhaki: '#BDB76B',
49936 silver: '#C0C0C0',
49937 mediumvioletred: '#C71585',
49938 indianred: '#CD5C5C',
49939 peru: '#CD853F',
49940 chocolate: '#D2691E',
49941 tan: '#D2B48C',
49942 lightgrey: '#D3D3D3',
49943 palevioletred: '#D87093',
49944 thistle: '#D8BFD8',
49945 orchid: '#DA70D6',
49946 goldenrod: '#DAA520',
49947 crimson: '#DC143C',
49948 gainsboro: '#DCDCDC',
49949 plum: '#DDA0DD',
49950 burlywood: '#DEB887',
49951 lightcyan: '#E0FFFF',
49952 lavender: '#E6E6FA',
49953 darksalmon: '#E9967A',
49954 violet: '#EE82EE',
49955 palegoldenrod: '#EEE8AA',
49956 lightcoral: '#F08080',
49957 khaki: '#F0E68C',
49958 aliceblue: '#F0F8FF',
49959 honeydew: '#F0FFF0',
49960 azure: '#F0FFFF',
49961 sandybrown: '#F4A460',
49962 wheat: '#F5DEB3',
49963 beige: '#F5F5DC',
49964 whitesmoke: '#F5F5F5',
49965 mintcream: '#F5FFFA',
49966 ghostwhite: '#F8F8FF',
49967 salmon: '#FA8072',
49968 antiquewhite: '#FAEBD7',
49969 linen: '#FAF0E6',
49970 lightgoldenrodyellow: '#FAFAD2',
49971 oldlace: '#FDF5E6',
49972 red: '#FF0000',
49973 fuchsia: '#FF00FF',
49974 magenta: '#FF00FF',
49975 deeppink: '#FF1493',
49976 orangered: '#FF4500',
49977 tomato: '#FF6347',
49978 hotpink: '#FF69B4',
49979 coral: '#FF7F50',
49980 darkorange: '#FF8C00',
49981 lightsalmon: '#FFA07A',
49982 orange: '#FFA500',
49983 lightpink: '#FFB6C1',
49984 pink: '#FFC0CB',
49985 gold: '#FFD700',
49986 peachpuff: '#FFDAB9',
49987 navajowhite: '#FFDEAD',
49988 moccasin: '#FFE4B5',
49989 bisque: '#FFE4C4',
49990 mistyrose: '#FFE4E1',
49991 blanchedalmond: '#FFEBCD',
49992 papayawhip: '#FFEFD5',
49993 lavenderblush: '#FFF0F5',
49994 seashell: '#FFF5EE',
49995 cornsilk: '#FFF8DC',
49996 lemonchiffon: '#FFFACD',
49997 floralwhite: '#FFFAF0',
49998 snow: '#FFFAFA',
49999 yellow: '#FFFF00',
50000 lightyellow: '#FFFFE0',
50001 ivory: '#FFFFF0',
50002 white: '#FFFFFF'
50003 };
50004 /**
50005 * @param {number} [pixelRatio=1]
50006 */
50007
50008 var ColorPicker =
50009 /*#__PURE__*/
50010 function () {
50011 /**
50012 * @param {number} [pixelRatio=1]
50013 */
50014 function ColorPicker() {
50015 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
50016
50017 _classCallCheck(this, ColorPicker);
50018
50019 this.pixelRatio = pixelRatio;
50020 this.generated = false;
50021 this.centerCoordinates = {
50022 x: 289 / 2,
50023 y: 289 / 2
50024 };
50025 this.r = 289 * 0.49;
50026 this.color = {
50027 r: 255,
50028 g: 255,
50029 b: 255,
50030 a: 1.0
50031 };
50032 this.hueCircle = undefined;
50033 this.initialColor = {
50034 r: 255,
50035 g: 255,
50036 b: 255,
50037 a: 1.0
50038 };
50039 this.previousColor = undefined;
50040 this.applied = false; // bound by
50041
50042 this.updateCallback = function () {};
50043
50044 this.closeCallback = function () {}; // create all DOM elements
50045
50046
50047 this._create();
50048 }
50049 /**
50050 * this inserts the colorPicker into a div from the DOM
50051 * @param {Element} container
50052 */
50053
50054
50055 _createClass(ColorPicker, [{
50056 key: "insertTo",
50057 value: function insertTo(container) {
50058 if (this.hammer !== undefined) {
50059 this.hammer.destroy();
50060 this.hammer = undefined;
50061 }
50062
50063 this.container = container;
50064 this.container.appendChild(this.frame);
50065
50066 this._bindHammer();
50067
50068 this._setSize();
50069 }
50070 /**
50071 * the callback is executed on apply and save. Bind it to the application
50072 * @param {function} callback
50073 */
50074
50075 }, {
50076 key: "setUpdateCallback",
50077 value: function setUpdateCallback(callback) {
50078 if (typeof callback === 'function') {
50079 this.updateCallback = callback;
50080 } else {
50081 throw new Error("Function attempted to set as colorPicker update callback is not a function.");
50082 }
50083 }
50084 /**
50085 * the callback is executed on apply and save. Bind it to the application
50086 * @param {function} callback
50087 */
50088
50089 }, {
50090 key: "setCloseCallback",
50091 value: function setCloseCallback(callback) {
50092 if (typeof callback === 'function') {
50093 this.closeCallback = callback;
50094 } else {
50095 throw new Error("Function attempted to set as colorPicker closing callback is not a function.");
50096 }
50097 }
50098 /**
50099 *
50100 * @param {string} color
50101 * @returns {String}
50102 * @private
50103 */
50104
50105 }, {
50106 key: "_isColorString",
50107 value: function _isColorString(color) {
50108 if (typeof color === 'string') {
50109 return htmlColors[color];
50110 }
50111 }
50112 /**
50113 * Set the color of the colorPicker
50114 * Supported formats:
50115 * 'red' --> HTML color string
50116 * '#ffffff' --> hex string
50117 * 'rgb(255,255,255)' --> rgb string
50118 * 'rgba(255,255,255,1.0)' --> rgba string
50119 * {r:255,g:255,b:255} --> rgb object
50120 * {r:255,g:255,b:255,a:1.0} --> rgba object
50121 * @param {string|Object} color
50122 * @param {boolean} [setInitial=true]
50123 */
50124
50125 }, {
50126 key: "setColor",
50127 value: function setColor(color) {
50128 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
50129
50130 if (color === 'none') {
50131 return;
50132 }
50133
50134 var rgba; // if a html color shorthand is used, convert to hex
50135
50136 var htmlColor = this._isColorString(color);
50137
50138 if (htmlColor !== undefined) {
50139 color = htmlColor;
50140 } // check format
50141
50142
50143 if (isString(color) === true) {
50144 if (isValidRGB(color) === true) {
50145 var rgbaArray = color.substr(4).substr(0, color.length - 5).split(',');
50146 rgba = {
50147 r: rgbaArray[0],
50148 g: rgbaArray[1],
50149 b: rgbaArray[2],
50150 a: 1.0
50151 };
50152 } else if (isValidRGBA(color) === true) {
50153 var _rgbaArray = color.substr(5).substr(0, color.length - 6).split(',');
50154
50155 rgba = {
50156 r: _rgbaArray[0],
50157 g: _rgbaArray[1],
50158 b: _rgbaArray[2],
50159 a: _rgbaArray[3]
50160 };
50161 } else if (isValidHex(color) === true) {
50162 var rgbObj = hexToRGB(color);
50163 rgba = {
50164 r: rgbObj.r,
50165 g: rgbObj.g,
50166 b: rgbObj.b,
50167 a: 1.0
50168 };
50169 }
50170 } else {
50171 if (color instanceof Object) {
50172 if (color.r !== undefined && color.g !== undefined && color.b !== undefined) {
50173 var alpha = color.a !== undefined ? color.a : '1.0';
50174 rgba = {
50175 r: color.r,
50176 g: color.g,
50177 b: color.b,
50178 a: alpha
50179 };
50180 }
50181 }
50182 } // set color
50183
50184
50185 if (rgba === undefined) {
50186 throw new Error("Unknown color passed to the colorPicker. Supported are strings: rgb, hex, rgba. Object: rgb ({r:r,g:g,b:b,[a:a]}). Supplied: " + JSON.stringify(color));
50187 } else {
50188 this._setColor(rgba, setInitial);
50189 }
50190 }
50191 /**
50192 * this shows the color picker.
50193 * The hue circle is constructed once and stored.
50194 */
50195
50196 }, {
50197 key: "show",
50198 value: function show() {
50199 if (this.closeCallback !== undefined) {
50200 this.closeCallback();
50201 this.closeCallback = undefined;
50202 }
50203
50204 this.applied = false;
50205 this.frame.style.display = 'block';
50206
50207 this._generateHueCircle();
50208 } // ------------------------------------------ PRIVATE ----------------------------- //
50209
50210 /**
50211 * Hide the picker. Is called by the cancel button.
50212 * Optional boolean to store the previous color for easy access later on.
50213 * @param {boolean} [storePrevious=true]
50214 * @private
50215 */
50216
50217 }, {
50218 key: "_hide",
50219 value: function _hide() {
50220 var _this = this;
50221
50222 var storePrevious = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
50223
50224 // store the previous color for next time;
50225 if (storePrevious === true) {
50226 this.previousColor = extend({}, this.color);
50227 }
50228
50229 if (this.applied === true) {
50230 this.updateCallback(this.initialColor);
50231 }
50232
50233 this.frame.style.display = 'none'; // call the closing callback, restoring the onclick method.
50234 // this is in a setTimeout because it will trigger the show again before the click is done.
50235
50236 setTimeout(function () {
50237 if (_this.closeCallback !== undefined) {
50238 _this.closeCallback();
50239
50240 _this.closeCallback = undefined;
50241 }
50242 }, 0);
50243 }
50244 /**
50245 * bound to the save button. Saves and hides.
50246 * @private
50247 */
50248
50249 }, {
50250 key: "_save",
50251 value: function _save() {
50252 this.updateCallback(this.color);
50253 this.applied = false;
50254
50255 this._hide();
50256 }
50257 /**
50258 * Bound to apply button. Saves but does not close. Is undone by the cancel button.
50259 * @private
50260 */
50261
50262 }, {
50263 key: "_apply",
50264 value: function _apply() {
50265 this.applied = true;
50266 this.updateCallback(this.color);
50267
50268 this._updatePicker(this.color);
50269 }
50270 /**
50271 * load the color from the previous session.
50272 * @private
50273 */
50274
50275 }, {
50276 key: "_loadLast",
50277 value: function _loadLast() {
50278 if (this.previousColor !== undefined) {
50279 this.setColor(this.previousColor, false);
50280 } else {
50281 alert("There is no last color to load...");
50282 }
50283 }
50284 /**
50285 * set the color, place the picker
50286 * @param {Object} rgba
50287 * @param {boolean} [setInitial=true]
50288 * @private
50289 */
50290
50291 }, {
50292 key: "_setColor",
50293 value: function _setColor(rgba) {
50294 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
50295
50296 // store the initial color
50297 if (setInitial === true) {
50298 this.initialColor = extend({}, rgba);
50299 }
50300
50301 this.color = rgba;
50302 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
50303 var angleConvert = 2 * Math.PI;
50304 var radius = this.r * hsv.s;
50305 var x = this.centerCoordinates.x + radius * Math.sin(angleConvert * hsv.h);
50306 var y = this.centerCoordinates.y + radius * Math.cos(angleConvert * hsv.h);
50307 this.colorPickerSelector.style.left = x - 0.5 * this.colorPickerSelector.clientWidth + 'px';
50308 this.colorPickerSelector.style.top = y - 0.5 * this.colorPickerSelector.clientHeight + 'px';
50309
50310 this._updatePicker(rgba);
50311 }
50312 /**
50313 * bound to opacity control
50314 * @param {number} value
50315 * @private
50316 */
50317
50318 }, {
50319 key: "_setOpacity",
50320 value: function _setOpacity(value) {
50321 this.color.a = value / 100;
50322
50323 this._updatePicker(this.color);
50324 }
50325 /**
50326 * bound to brightness control
50327 * @param {number} value
50328 * @private
50329 */
50330
50331 }, {
50332 key: "_setBrightness",
50333 value: function _setBrightness(value) {
50334 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
50335 hsv.v = value / 100;
50336 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
50337 rgba['a'] = this.color.a;
50338 this.color = rgba;
50339
50340 this._updatePicker();
50341 }
50342 /**
50343 * update the color picker. A black circle overlays the hue circle to mimic the brightness decreasing.
50344 * @param {Object} rgba
50345 * @private
50346 */
50347
50348 }, {
50349 key: "_updatePicker",
50350 value: function _updatePicker() {
50351 var rgba = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.color;
50352 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
50353 var ctx = this.colorPickerCanvas.getContext('2d');
50354
50355 if (this.pixelRation === undefined) {
50356 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
50357 }
50358
50359 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
50360
50361 var w = this.colorPickerCanvas.clientWidth;
50362 var h = this.colorPickerCanvas.clientHeight;
50363 ctx.clearRect(0, 0, w, h);
50364 ctx.putImageData(this.hueCircle, 0, 0);
50365 ctx.fillStyle = 'rgba(0,0,0,' + (1 - hsv.v) + ')';
50366 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
50367 ctx.fill();
50368 this.brightnessRange.value = 100 * hsv.v;
50369 this.opacityRange.value = 100 * rgba.a;
50370 this.initialColorDiv.style.backgroundColor = 'rgba(' + this.initialColor.r + ',' + this.initialColor.g + ',' + this.initialColor.b + ',' + this.initialColor.a + ')';
50371 this.newColorDiv.style.backgroundColor = 'rgba(' + this.color.r + ',' + this.color.g + ',' + this.color.b + ',' + this.color.a + ')';
50372 }
50373 /**
50374 * used by create to set the size of the canvas.
50375 * @private
50376 */
50377
50378 }, {
50379 key: "_setSize",
50380 value: function _setSize() {
50381 this.colorPickerCanvas.style.width = '100%';
50382 this.colorPickerCanvas.style.height = '100%';
50383 this.colorPickerCanvas.width = 289 * this.pixelRatio;
50384 this.colorPickerCanvas.height = 289 * this.pixelRatio;
50385 }
50386 /**
50387 * create all dom elements
50388 * TODO: cleanup, lots of similar dom elements
50389 * @private
50390 */
50391
50392 }, {
50393 key: "_create",
50394 value: function _create() {
50395 this.frame = document.createElement('div');
50396 this.frame.className = 'vis-color-picker';
50397 this.colorPickerDiv = document.createElement('div');
50398 this.colorPickerSelector = document.createElement('div');
50399 this.colorPickerSelector.className = 'vis-selector';
50400 this.colorPickerDiv.appendChild(this.colorPickerSelector);
50401 this.colorPickerCanvas = document.createElement('canvas');
50402 this.colorPickerDiv.appendChild(this.colorPickerCanvas);
50403
50404 if (!this.colorPickerCanvas.getContext) {
50405 var noCanvas = document.createElement('DIV');
50406 noCanvas.style.color = 'red';
50407 noCanvas.style.fontWeight = 'bold';
50408 noCanvas.style.padding = '10px';
50409 noCanvas.innerHTML = 'Error: your browser does not support HTML canvas';
50410 this.colorPickerCanvas.appendChild(noCanvas);
50411 } else {
50412 var ctx = this.colorPickerCanvas.getContext("2d");
50413 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
50414 this.colorPickerCanvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
50415 }
50416
50417 this.colorPickerDiv.className = 'vis-color';
50418 this.opacityDiv = document.createElement('div');
50419 this.opacityDiv.className = 'vis-opacity';
50420 this.brightnessDiv = document.createElement('div');
50421 this.brightnessDiv.className = 'vis-brightness';
50422 this.arrowDiv = document.createElement('div');
50423 this.arrowDiv.className = 'vis-arrow';
50424 this.opacityRange = document.createElement('input');
50425
50426 try {
50427 this.opacityRange.type = 'range'; // Not supported on IE9
50428
50429 this.opacityRange.min = '0';
50430 this.opacityRange.max = '100';
50431 } // TODO: Add some error handling and remove this lint exception
50432 catch (err) {} // eslint-disable-line no-empty
50433
50434
50435 this.opacityRange.value = '100';
50436 this.opacityRange.className = 'vis-range';
50437 this.brightnessRange = document.createElement('input');
50438
50439 try {
50440 this.brightnessRange.type = 'range'; // Not supported on IE9
50441
50442 this.brightnessRange.min = '0';
50443 this.brightnessRange.max = '100';
50444 } // TODO: Add some error handling and remove this lint exception
50445 catch (err) {} // eslint-disable-line no-empty
50446
50447
50448 this.brightnessRange.value = '100';
50449 this.brightnessRange.className = 'vis-range';
50450 this.opacityDiv.appendChild(this.opacityRange);
50451 this.brightnessDiv.appendChild(this.brightnessRange);
50452 var me = this;
50453
50454 this.opacityRange.onchange = function () {
50455 me._setOpacity(this.value);
50456 };
50457
50458 this.opacityRange.oninput = function () {
50459 me._setOpacity(this.value);
50460 };
50461
50462 this.brightnessRange.onchange = function () {
50463 me._setBrightness(this.value);
50464 };
50465
50466 this.brightnessRange.oninput = function () {
50467 me._setBrightness(this.value);
50468 };
50469
50470 this.brightnessLabel = document.createElement("div");
50471 this.brightnessLabel.className = "vis-label vis-brightness";
50472 this.brightnessLabel.innerHTML = 'brightness:';
50473 this.opacityLabel = document.createElement("div");
50474 this.opacityLabel.className = "vis-label vis-opacity";
50475 this.opacityLabel.innerHTML = 'opacity:';
50476 this.newColorDiv = document.createElement("div");
50477 this.newColorDiv.className = "vis-new-color";
50478 this.newColorDiv.innerHTML = 'new';
50479 this.initialColorDiv = document.createElement("div");
50480 this.initialColorDiv.className = "vis-initial-color";
50481 this.initialColorDiv.innerHTML = 'initial';
50482 this.cancelButton = document.createElement("div");
50483 this.cancelButton.className = "vis-button vis-cancel";
50484 this.cancelButton.innerHTML = 'cancel';
50485 this.cancelButton.onclick = this._hide.bind(this, false);
50486 this.applyButton = document.createElement("div");
50487 this.applyButton.className = "vis-button vis-apply";
50488 this.applyButton.innerHTML = 'apply';
50489 this.applyButton.onclick = this._apply.bind(this);
50490 this.saveButton = document.createElement("div");
50491 this.saveButton.className = "vis-button vis-save";
50492 this.saveButton.innerHTML = 'save';
50493 this.saveButton.onclick = this._save.bind(this);
50494 this.loadButton = document.createElement("div");
50495 this.loadButton.className = "vis-button vis-load";
50496 this.loadButton.innerHTML = 'load last';
50497 this.loadButton.onclick = this._loadLast.bind(this);
50498 this.frame.appendChild(this.colorPickerDiv);
50499 this.frame.appendChild(this.arrowDiv);
50500 this.frame.appendChild(this.brightnessLabel);
50501 this.frame.appendChild(this.brightnessDiv);
50502 this.frame.appendChild(this.opacityLabel);
50503 this.frame.appendChild(this.opacityDiv);
50504 this.frame.appendChild(this.newColorDiv);
50505 this.frame.appendChild(this.initialColorDiv);
50506 this.frame.appendChild(this.cancelButton);
50507 this.frame.appendChild(this.applyButton);
50508 this.frame.appendChild(this.saveButton);
50509 this.frame.appendChild(this.loadButton);
50510 }
50511 /**
50512 * bind hammer to the color picker
50513 * @private
50514 */
50515
50516 }, {
50517 key: "_bindHammer",
50518 value: function _bindHammer() {
50519 var _this2 = this;
50520
50521 this.drag = {};
50522 this.pinch = {};
50523 this.hammer = new hammer(this.colorPickerCanvas);
50524 this.hammer.get('pinch').set({
50525 enable: true
50526 });
50527 hammerUtil.onTouch(this.hammer, function (event) {
50528 _this2._moveSelector(event);
50529 });
50530 this.hammer.on('tap', function (event) {
50531 _this2._moveSelector(event);
50532 });
50533 this.hammer.on('panstart', function (event) {
50534 _this2._moveSelector(event);
50535 });
50536 this.hammer.on('panmove', function (event) {
50537 _this2._moveSelector(event);
50538 });
50539 this.hammer.on('panend', function (event) {
50540 _this2._moveSelector(event);
50541 });
50542 }
50543 /**
50544 * generate the hue circle. This is relatively heavy (200ms) and is done only once on the first time it is shown.
50545 * @private
50546 */
50547
50548 }, {
50549 key: "_generateHueCircle",
50550 value: function _generateHueCircle() {
50551 if (this.generated === false) {
50552 var ctx = this.colorPickerCanvas.getContext('2d');
50553
50554 if (this.pixelRation === undefined) {
50555 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
50556 }
50557
50558 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
50559
50560 var w = this.colorPickerCanvas.clientWidth;
50561 var h = this.colorPickerCanvas.clientHeight;
50562 ctx.clearRect(0, 0, w, h); // draw hue circle
50563
50564 var x, y, hue, sat;
50565 this.centerCoordinates = {
50566 x: w * 0.5,
50567 y: h * 0.5
50568 };
50569 this.r = 0.49 * w;
50570 var angleConvert = 2 * Math.PI / 360;
50571 var hfac = 1 / 360;
50572 var sfac = 1 / this.r;
50573 var rgb;
50574
50575 for (hue = 0; hue < 360; hue++) {
50576 for (sat = 0; sat < this.r; sat++) {
50577 x = this.centerCoordinates.x + sat * Math.sin(angleConvert * hue);
50578 y = this.centerCoordinates.y + sat * Math.cos(angleConvert * hue);
50579 rgb = HSVToRGB(hue * hfac, sat * sfac, 1);
50580 ctx.fillStyle = 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
50581 ctx.fillRect(x - 0.5, y - 0.5, 2, 2);
50582 }
50583 }
50584
50585 ctx.strokeStyle = 'rgba(0,0,0,1)';
50586 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
50587 ctx.stroke();
50588 this.hueCircle = ctx.getImageData(0, 0, w, h);
50589 }
50590
50591 this.generated = true;
50592 }
50593 /**
50594 * move the selector. This is called by hammer functions.
50595 *
50596 * @param {Event} event The event
50597 * @private
50598 */
50599
50600 }, {
50601 key: "_moveSelector",
50602 value: function _moveSelector(event) {
50603 var rect = this.colorPickerDiv.getBoundingClientRect();
50604 var left = event.center.x - rect.left;
50605 var top = event.center.y - rect.top;
50606 var centerY = 0.5 * this.colorPickerDiv.clientHeight;
50607 var centerX = 0.5 * this.colorPickerDiv.clientWidth;
50608 var x = left - centerX;
50609 var y = top - centerY;
50610 var angle = Math.atan2(x, y);
50611 var radius = 0.98 * Math.min(Math.sqrt(x * x + y * y), centerX);
50612 var newTop = Math.cos(angle) * radius + centerY;
50613 var newLeft = Math.sin(angle) * radius + centerX;
50614 this.colorPickerSelector.style.top = newTop - 0.5 * this.colorPickerSelector.clientHeight + 'px';
50615 this.colorPickerSelector.style.left = newLeft - 0.5 * this.colorPickerSelector.clientWidth + 'px'; // set color
50616
50617 var h = angle / (2 * Math.PI);
50618 h = h < 0 ? h + 1 : h;
50619 var s = radius / this.r;
50620 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
50621 hsv.h = h;
50622 hsv.s = s;
50623 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
50624 rgba['a'] = this.color.a;
50625 this.color = rgba; // update previews
50626
50627 this.initialColorDiv.style.backgroundColor = 'rgba(' + this.initialColor.r + ',' + this.initialColor.g + ',' + this.initialColor.b + ',' + this.initialColor.a + ')';
50628 this.newColorDiv.style.backgroundColor = 'rgba(' + this.color.r + ',' + this.color.g + ',' + this.color.b + ',' + this.color.a + ')';
50629 }
50630 }]);
50631
50632 return ColorPicker;
50633 }();
50634
50635 /**
50636 * The way this works is for all properties of this.possible options, you can supply the property name in any form to list the options.
50637 * Boolean options are recognised as Boolean
50638 * Number options should be written as array: [default value, min value, max value, stepsize]
50639 * Colors should be written as array: ['color', '#ffffff']
50640 * Strings with should be written as array: [option1, option2, option3, ..]
50641 *
50642 * The options are matched with their counterparts in each of the modules and the values used in the configuration are
50643 */
50644
50645 var Configurator =
50646 /*#__PURE__*/
50647 function () {
50648 /**
50649 * @param {Object} parentModule | the location where parentModule.setOptions() can be called
50650 * @param {Object} defaultContainer | the default container of the module
50651 * @param {Object} configureOptions | the fully configured and predefined options set found in allOptions.js
50652 * @param {number} pixelRatio | canvas pixel ratio
50653 */
50654 function Configurator(parentModule, defaultContainer, configureOptions) {
50655 var pixelRatio = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
50656
50657 _classCallCheck(this, Configurator);
50658
50659 this.parent = parentModule;
50660 this.changedOptions = [];
50661 this.container = defaultContainer;
50662 this.allowCreation = false;
50663 this.options = {};
50664 this.initialized = false;
50665 this.popupCounter = 0;
50666 this.defaultOptions = {
50667 enabled: false,
50668 filter: true,
50669 container: undefined,
50670 showButton: true
50671 };
50672 extend(this.options, this.defaultOptions);
50673 this.configureOptions = configureOptions;
50674 this.moduleOptions = {};
50675 this.domElements = [];
50676 this.popupDiv = {};
50677 this.popupLimit = 5;
50678 this.popupHistory = {};
50679 this.colorPicker = new ColorPicker(pixelRatio);
50680 this.wrapper = undefined;
50681 }
50682 /**
50683 * refresh all options.
50684 * Because all modules parse their options by themselves, we just use their options. We copy them here.
50685 *
50686 * @param {Object} options
50687 */
50688
50689
50690 _createClass(Configurator, [{
50691 key: "setOptions",
50692 value: function setOptions(options) {
50693 if (options !== undefined) {
50694 // reset the popup history because the indices may have been changed.
50695 this.popupHistory = {};
50696
50697 this._removePopup();
50698
50699 var enabled = true;
50700
50701 if (typeof options === 'string') {
50702 this.options.filter = options;
50703 } else if (options instanceof Array) {
50704 this.options.filter = options.join();
50705 } else if (_typeof$1(options) === 'object') {
50706 if (options == null) {
50707 throw new TypeError('options cannot be null');
50708 }
50709
50710 if (options.container !== undefined) {
50711 this.options.container = options.container;
50712 }
50713
50714 if (options.filter !== undefined) {
50715 this.options.filter = options.filter;
50716 }
50717
50718 if (options.showButton !== undefined) {
50719 this.options.showButton = options.showButton;
50720 }
50721
50722 if (options.enabled !== undefined) {
50723 enabled = options.enabled;
50724 }
50725 } else if (typeof options === 'boolean') {
50726 this.options.filter = true;
50727 enabled = options;
50728 } else if (typeof options === 'function') {
50729 this.options.filter = options;
50730 enabled = true;
50731 }
50732
50733 if (this.options.filter === false) {
50734 enabled = false;
50735 }
50736
50737 this.options.enabled = enabled;
50738 }
50739
50740 this._clean();
50741 }
50742 /**
50743 *
50744 * @param {Object} moduleOptions
50745 */
50746
50747 }, {
50748 key: "setModuleOptions",
50749 value: function setModuleOptions(moduleOptions) {
50750 this.moduleOptions = moduleOptions;
50751
50752 if (this.options.enabled === true) {
50753 this._clean();
50754
50755 if (this.options.container !== undefined) {
50756 this.container = this.options.container;
50757 }
50758
50759 this._create();
50760 }
50761 }
50762 /**
50763 * Create all DOM elements
50764 * @private
50765 */
50766
50767 }, {
50768 key: "_create",
50769 value: function _create() {
50770 this._clean();
50771
50772 this.changedOptions = [];
50773 var filter = this.options.filter;
50774 var counter = 0;
50775 var show = false;
50776
50777 for (var option in this.configureOptions) {
50778 if (this.configureOptions.hasOwnProperty(option)) {
50779 this.allowCreation = false;
50780 show = false;
50781
50782 if (typeof filter === 'function') {
50783 show = filter(option, []);
50784 show = show || this._handleObject(this.configureOptions[option], [option], true);
50785 } else if (filter === true || filter.indexOf(option) !== -1) {
50786 show = true;
50787 }
50788
50789 if (show !== false) {
50790 this.allowCreation = true; // linebreak between categories
50791
50792 if (counter > 0) {
50793 this._makeItem([]);
50794 } // a header for the category
50795
50796
50797 this._makeHeader(option); // get the sub options
50798
50799
50800 this._handleObject(this.configureOptions[option], [option]);
50801 }
50802
50803 counter++;
50804 }
50805 }
50806
50807 this._makeButton();
50808
50809 this._push(); //~ this.colorPicker.insertTo(this.container);
50810
50811 }
50812 /**
50813 * draw all DOM elements on the screen
50814 * @private
50815 */
50816
50817 }, {
50818 key: "_push",
50819 value: function _push() {
50820 this.wrapper = document.createElement('div');
50821 this.wrapper.className = 'vis-configuration-wrapper';
50822 this.container.appendChild(this.wrapper);
50823
50824 for (var i = 0; i < this.domElements.length; i++) {
50825 this.wrapper.appendChild(this.domElements[i]);
50826 }
50827
50828 this._showPopupIfNeeded();
50829 }
50830 /**
50831 * delete all DOM elements
50832 * @private
50833 */
50834
50835 }, {
50836 key: "_clean",
50837 value: function _clean() {
50838 for (var i = 0; i < this.domElements.length; i++) {
50839 this.wrapper.removeChild(this.domElements[i]);
50840 }
50841
50842 if (this.wrapper !== undefined) {
50843 this.container.removeChild(this.wrapper);
50844 this.wrapper = undefined;
50845 }
50846
50847 this.domElements = [];
50848
50849 this._removePopup();
50850 }
50851 /**
50852 * get the value from the actualOptions if it exists
50853 * @param {array} path | where to look for the actual option
50854 * @returns {*}
50855 * @private
50856 */
50857
50858 }, {
50859 key: "_getValue",
50860 value: function _getValue(path) {
50861 var base = this.moduleOptions;
50862
50863 for (var i = 0; i < path.length; i++) {
50864 if (base[path[i]] !== undefined) {
50865 base = base[path[i]];
50866 } else {
50867 base = undefined;
50868 break;
50869 }
50870 }
50871
50872 return base;
50873 }
50874 /**
50875 * all option elements are wrapped in an item
50876 * @param {Array} path | where to look for the actual option
50877 * @param {Array.<Element>} domElements
50878 * @returns {number}
50879 * @private
50880 */
50881
50882 }, {
50883 key: "_makeItem",
50884 value: function _makeItem(path) {
50885 if (this.allowCreation === true) {
50886 var item = document.createElement('div');
50887 item.className = 'vis-configuration vis-config-item vis-config-s' + path.length;
50888
50889 for (var _len = arguments.length, domElements = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
50890 domElements[_key - 1] = arguments[_key];
50891 }
50892
50893 domElements.forEach(function (element) {
50894 item.appendChild(element);
50895 });
50896 this.domElements.push(item);
50897 return this.domElements.length;
50898 }
50899
50900 return 0;
50901 }
50902 /**
50903 * header for major subjects
50904 * @param {string} name
50905 * @private
50906 */
50907
50908 }, {
50909 key: "_makeHeader",
50910 value: function _makeHeader(name) {
50911 var div = document.createElement('div');
50912 div.className = 'vis-configuration vis-config-header';
50913 div.innerHTML = name;
50914
50915 this._makeItem([], div);
50916 }
50917 /**
50918 * make a label, if it is an object label, it gets different styling.
50919 * @param {string} name
50920 * @param {array} path | where to look for the actual option
50921 * @param {string} objectLabel
50922 * @returns {HTMLElement}
50923 * @private
50924 */
50925
50926 }, {
50927 key: "_makeLabel",
50928 value: function _makeLabel(name, path) {
50929 var objectLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
50930 var div = document.createElement('div');
50931 div.className = 'vis-configuration vis-config-label vis-config-s' + path.length;
50932
50933 if (objectLabel === true) {
50934 div.innerHTML = '<i><b>' + name + ':</b></i>';
50935 } else {
50936 div.innerHTML = name + ':';
50937 }
50938
50939 return div;
50940 }
50941 /**
50942 * make a dropdown list for multiple possible string optoins
50943 * @param {Array.<number>} arr
50944 * @param {number} value
50945 * @param {array} path | where to look for the actual option
50946 * @private
50947 */
50948
50949 }, {
50950 key: "_makeDropdown",
50951 value: function _makeDropdown(arr, value, path) {
50952 var select = document.createElement('select');
50953 select.className = 'vis-configuration vis-config-select';
50954 var selectedValue = 0;
50955
50956 if (value !== undefined) {
50957 if (arr.indexOf(value) !== -1) {
50958 selectedValue = arr.indexOf(value);
50959 }
50960 }
50961
50962 for (var i = 0; i < arr.length; i++) {
50963 var option = document.createElement('option');
50964 option.value = arr[i];
50965
50966 if (i === selectedValue) {
50967 option.selected = 'selected';
50968 }
50969
50970 option.innerHTML = arr[i];
50971 select.appendChild(option);
50972 }
50973
50974 var me = this;
50975
50976 select.onchange = function () {
50977 me._update(this.value, path);
50978 };
50979
50980 var label = this._makeLabel(path[path.length - 1], path);
50981
50982 this._makeItem(path, label, select);
50983 }
50984 /**
50985 * make a range object for numeric options
50986 * @param {Array.<number>} arr
50987 * @param {number} value
50988 * @param {array} path | where to look for the actual option
50989 * @private
50990 */
50991
50992 }, {
50993 key: "_makeRange",
50994 value: function _makeRange(arr, value, path) {
50995 var defaultValue = arr[0];
50996 var min = arr[1];
50997 var max = arr[2];
50998 var step = arr[3];
50999 var range = document.createElement('input');
51000 range.className = 'vis-configuration vis-config-range';
51001
51002 try {
51003 range.type = 'range'; // not supported on IE9
51004
51005 range.min = min;
51006 range.max = max;
51007 } // TODO: Add some error handling and remove this lint exception
51008 catch (err) {} // eslint-disable-line no-empty
51009
51010
51011 range.step = step; // set up the popup settings in case they are needed.
51012
51013 var popupString = '';
51014 var popupValue = 0;
51015
51016 if (value !== undefined) {
51017 var factor = 1.20;
51018
51019 if (value < 0 && value * factor < min) {
51020 range.min = Math.ceil(value * factor);
51021 popupValue = range.min;
51022 popupString = 'range increased';
51023 } else if (value / factor < min) {
51024 range.min = Math.ceil(value / factor);
51025 popupValue = range.min;
51026 popupString = 'range increased';
51027 }
51028
51029 if (value * factor > max && max !== 1) {
51030 range.max = Math.ceil(value * factor);
51031 popupValue = range.max;
51032 popupString = 'range increased';
51033 }
51034
51035 range.value = value;
51036 } else {
51037 range.value = defaultValue;
51038 }
51039
51040 var input = document.createElement('input');
51041 input.className = 'vis-configuration vis-config-rangeinput';
51042 input.value = range.value;
51043 var me = this;
51044
51045 range.onchange = function () {
51046 input.value = this.value;
51047
51048 me._update(Number(this.value), path);
51049 };
51050
51051 range.oninput = function () {
51052 input.value = this.value;
51053 };
51054
51055 var label = this._makeLabel(path[path.length - 1], path);
51056
51057 var itemIndex = this._makeItem(path, label, range, input); // if a popup is needed AND it has not been shown for this value, show it.
51058
51059
51060 if (popupString !== '' && this.popupHistory[itemIndex] !== popupValue) {
51061 this.popupHistory[itemIndex] = popupValue;
51062
51063 this._setupPopup(popupString, itemIndex);
51064 }
51065 }
51066 /**
51067 * make a button object
51068 * @private
51069 */
51070
51071 }, {
51072 key: "_makeButton",
51073 value: function _makeButton() {
51074 var _this = this;
51075
51076 if (this.options.showButton === true) {
51077 var generateButton = document.createElement('div');
51078 generateButton.className = 'vis-configuration vis-config-button';
51079 generateButton.innerHTML = 'generate options';
51080
51081 generateButton.onclick = function () {
51082 _this._printOptions();
51083 };
51084
51085 generateButton.onmouseover = function () {
51086 generateButton.className = 'vis-configuration vis-config-button hover';
51087 };
51088
51089 generateButton.onmouseout = function () {
51090 generateButton.className = 'vis-configuration vis-config-button';
51091 };
51092
51093 this.optionsContainer = document.createElement('div');
51094 this.optionsContainer.className = 'vis-configuration vis-config-option-container';
51095 this.domElements.push(this.optionsContainer);
51096 this.domElements.push(generateButton);
51097 }
51098 }
51099 /**
51100 * prepare the popup
51101 * @param {string} string
51102 * @param {number} index
51103 * @private
51104 */
51105
51106 }, {
51107 key: "_setupPopup",
51108 value: function _setupPopup(string, index) {
51109 var _this2 = this;
51110
51111 if (this.initialized === true && this.allowCreation === true && this.popupCounter < this.popupLimit) {
51112 var div = document.createElement("div");
51113 div.id = "vis-configuration-popup";
51114 div.className = "vis-configuration-popup";
51115 div.innerHTML = string;
51116
51117 div.onclick = function () {
51118 _this2._removePopup();
51119 };
51120
51121 this.popupCounter += 1;
51122 this.popupDiv = {
51123 html: div,
51124 index: index
51125 };
51126 }
51127 }
51128 /**
51129 * remove the popup from the dom
51130 * @private
51131 */
51132
51133 }, {
51134 key: "_removePopup",
51135 value: function _removePopup() {
51136 if (this.popupDiv.html !== undefined) {
51137 this.popupDiv.html.parentNode.removeChild(this.popupDiv.html);
51138 clearTimeout(this.popupDiv.hideTimeout);
51139 clearTimeout(this.popupDiv.deleteTimeout);
51140 this.popupDiv = {};
51141 }
51142 }
51143 /**
51144 * Show the popup if it is needed.
51145 * @private
51146 */
51147
51148 }, {
51149 key: "_showPopupIfNeeded",
51150 value: function _showPopupIfNeeded() {
51151 var _this3 = this;
51152
51153 if (this.popupDiv.html !== undefined) {
51154 var correspondingElement = this.domElements[this.popupDiv.index];
51155 var rect = correspondingElement.getBoundingClientRect();
51156 this.popupDiv.html.style.left = rect.left + "px";
51157 this.popupDiv.html.style.top = rect.top - 30 + "px"; // 30 is the height;
51158
51159 document.body.appendChild(this.popupDiv.html);
51160 this.popupDiv.hideTimeout = setTimeout(function () {
51161 _this3.popupDiv.html.style.opacity = 0;
51162 }, 1500);
51163 this.popupDiv.deleteTimeout = setTimeout(function () {
51164 _this3._removePopup();
51165 }, 1800);
51166 }
51167 }
51168 /**
51169 * make a checkbox for boolean options.
51170 * @param {number} defaultValue
51171 * @param {number} value
51172 * @param {array} path | where to look for the actual option
51173 * @private
51174 */
51175
51176 }, {
51177 key: "_makeCheckbox",
51178 value: function _makeCheckbox(defaultValue, value, path) {
51179 var checkbox = document.createElement('input');
51180 checkbox.type = 'checkbox';
51181 checkbox.className = 'vis-configuration vis-config-checkbox';
51182 checkbox.checked = defaultValue;
51183
51184 if (value !== undefined) {
51185 checkbox.checked = value;
51186
51187 if (value !== defaultValue) {
51188 if (_typeof$1(defaultValue) === 'object') {
51189 if (value !== defaultValue.enabled) {
51190 this.changedOptions.push({
51191 path: path,
51192 value: value
51193 });
51194 }
51195 } else {
51196 this.changedOptions.push({
51197 path: path,
51198 value: value
51199 });
51200 }
51201 }
51202 }
51203
51204 var me = this;
51205
51206 checkbox.onchange = function () {
51207 me._update(this.checked, path);
51208 };
51209
51210 var label = this._makeLabel(path[path.length - 1], path);
51211
51212 this._makeItem(path, label, checkbox);
51213 }
51214 /**
51215 * make a text input field for string options.
51216 * @param {number} defaultValue
51217 * @param {number} value
51218 * @param {array} path | where to look for the actual option
51219 * @private
51220 */
51221
51222 }, {
51223 key: "_makeTextInput",
51224 value: function _makeTextInput(defaultValue, value, path) {
51225 var checkbox = document.createElement('input');
51226 checkbox.type = 'text';
51227 checkbox.className = 'vis-configuration vis-config-text';
51228 checkbox.value = value;
51229
51230 if (value !== defaultValue) {
51231 this.changedOptions.push({
51232 path: path,
51233 value: value
51234 });
51235 }
51236
51237 var me = this;
51238
51239 checkbox.onchange = function () {
51240 me._update(this.value, path);
51241 };
51242
51243 var label = this._makeLabel(path[path.length - 1], path);
51244
51245 this._makeItem(path, label, checkbox);
51246 }
51247 /**
51248 * make a color field with a color picker for color fields
51249 * @param {Array.<number>} arr
51250 * @param {number} value
51251 * @param {array} path | where to look for the actual option
51252 * @private
51253 */
51254
51255 }, {
51256 key: "_makeColorField",
51257 value: function _makeColorField(arr, value, path) {
51258 var _this4 = this;
51259
51260 var defaultColor = arr[1];
51261 var div = document.createElement('div');
51262 value = value === undefined ? defaultColor : value;
51263
51264 if (value !== 'none') {
51265 div.className = 'vis-configuration vis-config-colorBlock';
51266 div.style.backgroundColor = value;
51267 } else {
51268 div.className = 'vis-configuration vis-config-colorBlock none';
51269 }
51270
51271 value = value === undefined ? defaultColor : value;
51272
51273 div.onclick = function () {
51274 _this4._showColorPicker(value, div, path);
51275 };
51276
51277 var label = this._makeLabel(path[path.length - 1], path);
51278
51279 this._makeItem(path, label, div);
51280 }
51281 /**
51282 * used by the color buttons to call the color picker.
51283 * @param {number} value
51284 * @param {HTMLElement} div
51285 * @param {array} path | where to look for the actual option
51286 * @private
51287 */
51288
51289 }, {
51290 key: "_showColorPicker",
51291 value: function _showColorPicker(value, div, path) {
51292 var _this5 = this;
51293
51294 // clear the callback from this div
51295 div.onclick = function () {};
51296
51297 this.colorPicker.insertTo(div);
51298 this.colorPicker.show();
51299 this.colorPicker.setColor(value);
51300 this.colorPicker.setUpdateCallback(function (color) {
51301 var colorString = 'rgba(' + color.r + ',' + color.g + ',' + color.b + ',' + color.a + ')';
51302 div.style.backgroundColor = colorString;
51303
51304 _this5._update(colorString, path);
51305 }); // on close of the colorpicker, restore the callback.
51306
51307 this.colorPicker.setCloseCallback(function () {
51308 div.onclick = function () {
51309 _this5._showColorPicker(value, div, path);
51310 };
51311 });
51312 }
51313 /**
51314 * parse an object and draw the correct items
51315 * @param {Object} obj
51316 * @param {array} [path=[]] | where to look for the actual option
51317 * @param {boolean} [checkOnly=false]
51318 * @returns {boolean}
51319 * @private
51320 */
51321
51322 }, {
51323 key: "_handleObject",
51324 value: function _handleObject(obj) {
51325 var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
51326 var checkOnly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
51327 var show = false;
51328 var filter = this.options.filter;
51329 var visibleInSet = false;
51330
51331 for (var subObj in obj) {
51332 if (obj.hasOwnProperty(subObj)) {
51333 show = true;
51334 var item = obj[subObj];
51335 var newPath = copyAndExtendArray(path, subObj);
51336
51337 if (typeof filter === 'function') {
51338 show = filter(subObj, path); // if needed we must go deeper into the object.
51339
51340 if (show === false) {
51341 if (!(item instanceof Array) && typeof item !== 'string' && typeof item !== 'boolean' && item instanceof Object) {
51342 this.allowCreation = false;
51343 show = this._handleObject(item, newPath, true);
51344 this.allowCreation = checkOnly === false;
51345 }
51346 }
51347 }
51348
51349 if (show !== false) {
51350 visibleInSet = true;
51351
51352 var value = this._getValue(newPath);
51353
51354 if (item instanceof Array) {
51355 this._handleArray(item, value, newPath);
51356 } else if (typeof item === 'string') {
51357 this._makeTextInput(item, value, newPath);
51358 } else if (typeof item === 'boolean') {
51359 this._makeCheckbox(item, value, newPath);
51360 } else if (item instanceof Object) {
51361 // collapse the physics options that are not enabled
51362 var draw = true;
51363
51364 if (path.indexOf('physics') !== -1) {
51365 if (this.moduleOptions.physics.solver !== subObj) {
51366 draw = false;
51367 }
51368 }
51369
51370 if (draw === true) {
51371 // initially collapse options with an disabled enabled option.
51372 if (item.enabled !== undefined) {
51373 var enabledPath = copyAndExtendArray(newPath, 'enabled');
51374
51375 var enabledValue = this._getValue(enabledPath);
51376
51377 if (enabledValue === true) {
51378 var label = this._makeLabel(subObj, newPath, true);
51379
51380 this._makeItem(newPath, label);
51381
51382 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
51383 } else {
51384 this._makeCheckbox(item, enabledValue, newPath);
51385 }
51386 } else {
51387 var _label = this._makeLabel(subObj, newPath, true);
51388
51389 this._makeItem(newPath, _label);
51390
51391 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
51392 }
51393 }
51394 } else {
51395 console.error('dont know how to handle', item, subObj, newPath);
51396 }
51397 }
51398 }
51399 }
51400
51401 return visibleInSet;
51402 }
51403 /**
51404 * handle the array type of option
51405 * @param {Array.<number>} arr
51406 * @param {number} value
51407 * @param {array} path | where to look for the actual option
51408 * @private
51409 */
51410
51411 }, {
51412 key: "_handleArray",
51413 value: function _handleArray(arr, value, path) {
51414 if (typeof arr[0] === 'string' && arr[0] === 'color') {
51415 this._makeColorField(arr, value, path);
51416
51417 if (arr[1] !== value) {
51418 this.changedOptions.push({
51419 path: path,
51420 value: value
51421 });
51422 }
51423 } else if (typeof arr[0] === 'string') {
51424 this._makeDropdown(arr, value, path);
51425
51426 if (arr[0] !== value) {
51427 this.changedOptions.push({
51428 path: path,
51429 value: value
51430 });
51431 }
51432 } else if (typeof arr[0] === 'number') {
51433 this._makeRange(arr, value, path);
51434
51435 if (arr[0] !== value) {
51436 this.changedOptions.push({
51437 path: path,
51438 value: Number(value)
51439 });
51440 }
51441 }
51442 }
51443 /**
51444 * called to update the network with the new settings.
51445 * @param {number} value
51446 * @param {array} path | where to look for the actual option
51447 * @private
51448 */
51449
51450 }, {
51451 key: "_update",
51452 value: function _update(value, path) {
51453 var options = this._constructOptions(value, path);
51454
51455 if (this.parent.body && this.parent.body.emitter && this.parent.body.emitter.emit) {
51456 this.parent.body.emitter.emit("configChange", options);
51457 }
51458
51459 this.initialized = true;
51460 this.parent.setOptions(options);
51461 }
51462 /**
51463 *
51464 * @param {string|Boolean} value
51465 * @param {Array.<string>} path
51466 * @param {{}} optionsObj
51467 * @returns {{}}
51468 * @private
51469 */
51470
51471 }, {
51472 key: "_constructOptions",
51473 value: function _constructOptions(value, path) {
51474 var optionsObj = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
51475 var pointer = optionsObj; // when dropdown boxes can be string or boolean, we typecast it into correct types
51476
51477 value = value === 'true' ? true : value;
51478 value = value === 'false' ? false : value;
51479
51480 for (var i = 0; i < path.length; i++) {
51481 if (path[i] !== 'global') {
51482 if (pointer[path[i]] === undefined) {
51483 pointer[path[i]] = {};
51484 }
51485
51486 if (i !== path.length - 1) {
51487 pointer = pointer[path[i]];
51488 } else {
51489 pointer[path[i]] = value;
51490 }
51491 }
51492 }
51493
51494 return optionsObj;
51495 }
51496 /**
51497 * @private
51498 */
51499
51500 }, {
51501 key: "_printOptions",
51502 value: function _printOptions() {
51503 var options = this.getOptions();
51504 this.optionsContainer.innerHTML = '<pre>var options = ' + JSON.stringify(options, null, 2) + '</pre>';
51505 }
51506 /**
51507 *
51508 * @returns {{}} options
51509 */
51510
51511 }, {
51512 key: "getOptions",
51513 value: function getOptions() {
51514 var options = {};
51515
51516 for (var i = 0; i < this.changedOptions.length; i++) {
51517 this._constructOptions(this.changedOptions[i].value, this.changedOptions[i].path, options);
51518 }
51519
51520 return options;
51521 }
51522 }]);
51523
51524 return Configurator;
51525 }();
51526
51527 /**
51528 * This object contains all possible options. It will check if the types are correct, if required if the option is one
51529 * of the allowed values.
51530 *
51531 * __any__ means that the name of the property does not matter.
51532 * __type__ is a required field for all objects and contains the allowed types of all objects
51533 */
51534 var string = 'string';
51535 var bool = 'boolean';
51536 var number = 'number';
51537 var array = 'array';
51538 var object = 'object'; // should only be in a __type__ property
51539
51540 var dom = 'dom';
51541 var any = 'any'; // List of endpoints
51542
51543 var endPoints = ["arrow", "bar", "box", "circle", "crow", "curve", "diamond", "image", "inv_curve", "inv_triangle", "triangle", "vee"];
51544 var allOptions$1 = {
51545 configure: {
51546 enabled: {
51547 boolean: bool
51548 },
51549 filter: {
51550 boolean: bool,
51551 string: string,
51552 array: array,
51553 'function': 'function'
51554 },
51555 container: {
51556 dom: dom
51557 },
51558 showButton: {
51559 boolean: bool
51560 },
51561 __type__: {
51562 object: object,
51563 boolean: bool,
51564 string: string,
51565 array: array,
51566 'function': 'function'
51567 }
51568 },
51569 edges: {
51570 arrows: {
51571 to: {
51572 enabled: {
51573 boolean: bool
51574 },
51575 scaleFactor: {
51576 number: number
51577 },
51578 type: {
51579 string: endPoints
51580 },
51581 imageHeight: {
51582 number: number
51583 },
51584 imageWidth: {
51585 number: number
51586 },
51587 src: {
51588 string: string
51589 },
51590 __type__: {
51591 object: object,
51592 boolean: bool
51593 }
51594 },
51595 middle: {
51596 enabled: {
51597 boolean: bool
51598 },
51599 scaleFactor: {
51600 number: number
51601 },
51602 type: {
51603 string: endPoints
51604 },
51605 imageWidth: {
51606 number: number
51607 },
51608 imageHeight: {
51609 number: number
51610 },
51611 src: {
51612 string: string
51613 },
51614 __type__: {
51615 object: object,
51616 boolean: bool
51617 }
51618 },
51619 from: {
51620 enabled: {
51621 boolean: bool
51622 },
51623 scaleFactor: {
51624 number: number
51625 },
51626 type: {
51627 string: endPoints
51628 },
51629 imageWidth: {
51630 number: number
51631 },
51632 imageHeight: {
51633 number: number
51634 },
51635 src: {
51636 string: string
51637 },
51638 __type__: {
51639 object: object,
51640 boolean: bool
51641 }
51642 },
51643 __type__: {
51644 string: ["from", "to", "middle"],
51645 object: object
51646 }
51647 },
51648 arrowStrikethrough: {
51649 boolean: bool
51650 },
51651 background: {
51652 enabled: {
51653 boolean: bool
51654 },
51655 color: {
51656 string: string
51657 },
51658 size: {
51659 number: number
51660 },
51661 dashes: {
51662 boolean: bool,
51663 array: array
51664 },
51665 __type__: {
51666 object: object,
51667 boolean: bool
51668 }
51669 },
51670 chosen: {
51671 label: {
51672 boolean: bool,
51673 'function': 'function'
51674 },
51675 edge: {
51676 boolean: bool,
51677 'function': 'function'
51678 },
51679 __type__: {
51680 object: object,
51681 boolean: bool
51682 }
51683 },
51684 color: {
51685 color: {
51686 string: string
51687 },
51688 highlight: {
51689 string: string
51690 },
51691 hover: {
51692 string: string
51693 },
51694 inherit: {
51695 string: ['from', 'to', 'both'],
51696 boolean: bool
51697 },
51698 opacity: {
51699 number: number
51700 },
51701 __type__: {
51702 object: object,
51703 string: string
51704 }
51705 },
51706 dashes: {
51707 boolean: bool,
51708 array: array
51709 },
51710 font: {
51711 color: {
51712 string: string
51713 },
51714 size: {
51715 number: number
51716 },
51717 // px
51718 face: {
51719 string: string
51720 },
51721 background: {
51722 string: string
51723 },
51724 strokeWidth: {
51725 number: number
51726 },
51727 // px
51728 strokeColor: {
51729 string: string
51730 },
51731 align: {
51732 string: ['horizontal', 'top', 'middle', 'bottom']
51733 },
51734 vadjust: {
51735 number: number
51736 },
51737 multi: {
51738 boolean: bool,
51739 string: string
51740 },
51741 bold: {
51742 color: {
51743 string: string
51744 },
51745 size: {
51746 number: number
51747 },
51748 // px
51749 face: {
51750 string: string
51751 },
51752 mod: {
51753 string: string
51754 },
51755 vadjust: {
51756 number: number
51757 },
51758 __type__: {
51759 object: object,
51760 string: string
51761 }
51762 },
51763 boldital: {
51764 color: {
51765 string: string
51766 },
51767 size: {
51768 number: number
51769 },
51770 // px
51771 face: {
51772 string: string
51773 },
51774 mod: {
51775 string: string
51776 },
51777 vadjust: {
51778 number: number
51779 },
51780 __type__: {
51781 object: object,
51782 string: string
51783 }
51784 },
51785 ital: {
51786 color: {
51787 string: string
51788 },
51789 size: {
51790 number: number
51791 },
51792 // px
51793 face: {
51794 string: string
51795 },
51796 mod: {
51797 string: string
51798 },
51799 vadjust: {
51800 number: number
51801 },
51802 __type__: {
51803 object: object,
51804 string: string
51805 }
51806 },
51807 mono: {
51808 color: {
51809 string: string
51810 },
51811 size: {
51812 number: number
51813 },
51814 // px
51815 face: {
51816 string: string
51817 },
51818 mod: {
51819 string: string
51820 },
51821 vadjust: {
51822 number: number
51823 },
51824 __type__: {
51825 object: object,
51826 string: string
51827 }
51828 },
51829 __type__: {
51830 object: object,
51831 string: string
51832 }
51833 },
51834 hidden: {
51835 boolean: bool
51836 },
51837 hoverWidth: {
51838 'function': 'function',
51839 number: number
51840 },
51841 label: {
51842 string: string,
51843 'undefined': 'undefined'
51844 },
51845 labelHighlightBold: {
51846 boolean: bool
51847 },
51848 length: {
51849 number: number,
51850 'undefined': 'undefined'
51851 },
51852 physics: {
51853 boolean: bool
51854 },
51855 scaling: {
51856 min: {
51857 number: number
51858 },
51859 max: {
51860 number: number
51861 },
51862 label: {
51863 enabled: {
51864 boolean: bool
51865 },
51866 min: {
51867 number: number
51868 },
51869 max: {
51870 number: number
51871 },
51872 maxVisible: {
51873 number: number
51874 },
51875 drawThreshold: {
51876 number: number
51877 },
51878 __type__: {
51879 object: object,
51880 boolean: bool
51881 }
51882 },
51883 customScalingFunction: {
51884 'function': 'function'
51885 },
51886 __type__: {
51887 object: object
51888 }
51889 },
51890 selectionWidth: {
51891 'function': 'function',
51892 number: number
51893 },
51894 selfReferenceSize: {
51895 number: number
51896 },
51897 shadow: {
51898 enabled: {
51899 boolean: bool
51900 },
51901 color: {
51902 string: string
51903 },
51904 size: {
51905 number: number
51906 },
51907 x: {
51908 number: number
51909 },
51910 y: {
51911 number: number
51912 },
51913 __type__: {
51914 object: object,
51915 boolean: bool
51916 }
51917 },
51918 smooth: {
51919 enabled: {
51920 boolean: bool
51921 },
51922 type: {
51923 string: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW', 'cubicBezier']
51924 },
51925 roundness: {
51926 number: number
51927 },
51928 forceDirection: {
51929 string: ['horizontal', 'vertical', 'none'],
51930 boolean: bool
51931 },
51932 __type__: {
51933 object: object,
51934 boolean: bool
51935 }
51936 },
51937 title: {
51938 string: string,
51939 'undefined': 'undefined'
51940 },
51941 width: {
51942 number: number
51943 },
51944 widthConstraint: {
51945 maximum: {
51946 number: number
51947 },
51948 __type__: {
51949 object: object,
51950 boolean: bool,
51951 number: number
51952 }
51953 },
51954 value: {
51955 number: number,
51956 'undefined': 'undefined'
51957 },
51958 __type__: {
51959 object: object
51960 }
51961 },
51962 groups: {
51963 useDefaultGroups: {
51964 boolean: bool
51965 },
51966 __any__: 'get from nodes, will be overwritten below',
51967 __type__: {
51968 object: object
51969 }
51970 },
51971 interaction: {
51972 dragNodes: {
51973 boolean: bool
51974 },
51975 dragView: {
51976 boolean: bool
51977 },
51978 hideEdgesOnDrag: {
51979 boolean: bool
51980 },
51981 hideEdgesOnZoom: {
51982 boolean: bool
51983 },
51984 hideNodesOnDrag: {
51985 boolean: bool
51986 },
51987 hover: {
51988 boolean: bool
51989 },
51990 keyboard: {
51991 enabled: {
51992 boolean: bool
51993 },
51994 speed: {
51995 x: {
51996 number: number
51997 },
51998 y: {
51999 number: number
52000 },
52001 zoom: {
52002 number: number
52003 },
52004 __type__: {
52005 object: object
52006 }
52007 },
52008 bindToWindow: {
52009 boolean: bool
52010 },
52011 __type__: {
52012 object: object,
52013 boolean: bool
52014 }
52015 },
52016 multiselect: {
52017 boolean: bool
52018 },
52019 navigationButtons: {
52020 boolean: bool
52021 },
52022 selectable: {
52023 boolean: bool
52024 },
52025 selectConnectedEdges: {
52026 boolean: bool
52027 },
52028 hoverConnectedEdges: {
52029 boolean: bool
52030 },
52031 tooltipDelay: {
52032 number: number
52033 },
52034 zoomView: {
52035 boolean: bool
52036 },
52037 zoomSpeed: {
52038 number: number
52039 },
52040 __type__: {
52041 object: object
52042 }
52043 },
52044 layout: {
52045 randomSeed: {
52046 'undefined': 'undefined',
52047 number: number
52048 },
52049 improvedLayout: {
52050 boolean: bool
52051 },
52052 clusterThreshold: {
52053 number: number
52054 },
52055 hierarchical: {
52056 enabled: {
52057 boolean: bool
52058 },
52059 levelSeparation: {
52060 number: number
52061 },
52062 nodeSpacing: {
52063 number: number
52064 },
52065 treeSpacing: {
52066 number: number
52067 },
52068 blockShifting: {
52069 boolean: bool
52070 },
52071 edgeMinimization: {
52072 boolean: bool
52073 },
52074 parentCentralization: {
52075 boolean: bool
52076 },
52077 direction: {
52078 string: ['UD', 'DU', 'LR', 'RL']
52079 },
52080 // UD, DU, LR, RL
52081 sortMethod: {
52082 string: ['hubsize', 'directed']
52083 },
52084 // hubsize, directed
52085 shakeTowards: {
52086 string: ['leaves', 'roots']
52087 },
52088 // leaves, roots
52089 __type__: {
52090 object: object,
52091 boolean: bool
52092 }
52093 },
52094 __type__: {
52095 object: object
52096 }
52097 },
52098 manipulation: {
52099 enabled: {
52100 boolean: bool
52101 },
52102 initiallyActive: {
52103 boolean: bool
52104 },
52105 addNode: {
52106 boolean: bool,
52107 'function': 'function'
52108 },
52109 addEdge: {
52110 boolean: bool,
52111 'function': 'function'
52112 },
52113 editNode: {
52114 'function': 'function'
52115 },
52116 editEdge: {
52117 editWithoutDrag: {
52118 'function': 'function'
52119 },
52120 __type__: {
52121 object: object,
52122 boolean: bool,
52123 'function': 'function'
52124 }
52125 },
52126 deleteNode: {
52127 boolean: bool,
52128 'function': 'function'
52129 },
52130 deleteEdge: {
52131 boolean: bool,
52132 'function': 'function'
52133 },
52134 controlNodeStyle: 'get from nodes, will be overwritten below',
52135 __type__: {
52136 object: object,
52137 boolean: bool
52138 }
52139 },
52140 nodes: {
52141 borderWidth: {
52142 number: number
52143 },
52144 borderWidthSelected: {
52145 number: number,
52146 'undefined': 'undefined'
52147 },
52148 brokenImage: {
52149 string: string,
52150 'undefined': 'undefined'
52151 },
52152 chosen: {
52153 label: {
52154 boolean: bool,
52155 'function': 'function'
52156 },
52157 node: {
52158 boolean: bool,
52159 'function': 'function'
52160 },
52161 __type__: {
52162 object: object,
52163 boolean: bool
52164 }
52165 },
52166 color: {
52167 border: {
52168 string: string
52169 },
52170 background: {
52171 string: string
52172 },
52173 highlight: {
52174 border: {
52175 string: string
52176 },
52177 background: {
52178 string: string
52179 },
52180 __type__: {
52181 object: object,
52182 string: string
52183 }
52184 },
52185 hover: {
52186 border: {
52187 string: string
52188 },
52189 background: {
52190 string: string
52191 },
52192 __type__: {
52193 object: object,
52194 string: string
52195 }
52196 },
52197 __type__: {
52198 object: object,
52199 string: string
52200 }
52201 },
52202 fixed: {
52203 x: {
52204 boolean: bool
52205 },
52206 y: {
52207 boolean: bool
52208 },
52209 __type__: {
52210 object: object,
52211 boolean: bool
52212 }
52213 },
52214 font: {
52215 align: {
52216 string: string
52217 },
52218 color: {
52219 string: string
52220 },
52221 size: {
52222 number: number
52223 },
52224 // px
52225 face: {
52226 string: string
52227 },
52228 background: {
52229 string: string
52230 },
52231 strokeWidth: {
52232 number: number
52233 },
52234 // px
52235 strokeColor: {
52236 string: string
52237 },
52238 vadjust: {
52239 number: number
52240 },
52241 multi: {
52242 boolean: bool,
52243 string: string
52244 },
52245 bold: {
52246 color: {
52247 string: string
52248 },
52249 size: {
52250 number: number
52251 },
52252 // px
52253 face: {
52254 string: string
52255 },
52256 mod: {
52257 string: string
52258 },
52259 vadjust: {
52260 number: number
52261 },
52262 __type__: {
52263 object: object,
52264 string: string
52265 }
52266 },
52267 boldital: {
52268 color: {
52269 string: string
52270 },
52271 size: {
52272 number: number
52273 },
52274 // px
52275 face: {
52276 string: string
52277 },
52278 mod: {
52279 string: string
52280 },
52281 vadjust: {
52282 number: number
52283 },
52284 __type__: {
52285 object: object,
52286 string: string
52287 }
52288 },
52289 ital: {
52290 color: {
52291 string: string
52292 },
52293 size: {
52294 number: number
52295 },
52296 // px
52297 face: {
52298 string: string
52299 },
52300 mod: {
52301 string: string
52302 },
52303 vadjust: {
52304 number: number
52305 },
52306 __type__: {
52307 object: object,
52308 string: string
52309 }
52310 },
52311 mono: {
52312 color: {
52313 string: string
52314 },
52315 size: {
52316 number: number
52317 },
52318 // px
52319 face: {
52320 string: string
52321 },
52322 mod: {
52323 string: string
52324 },
52325 vadjust: {
52326 number: number
52327 },
52328 __type__: {
52329 object: object,
52330 string: string
52331 }
52332 },
52333 __type__: {
52334 object: object,
52335 string: string
52336 }
52337 },
52338 group: {
52339 string: string,
52340 number: number,
52341 'undefined': 'undefined'
52342 },
52343 heightConstraint: {
52344 minimum: {
52345 number: number
52346 },
52347 valign: {
52348 string: string
52349 },
52350 __type__: {
52351 object: object,
52352 boolean: bool,
52353 number: number
52354 }
52355 },
52356 hidden: {
52357 boolean: bool
52358 },
52359 icon: {
52360 face: {
52361 string: string
52362 },
52363 code: {
52364 string: string
52365 },
52366 //'\uf007',
52367 size: {
52368 number: number
52369 },
52370 //50,
52371 color: {
52372 string: string
52373 },
52374 weight: {
52375 string: string,
52376 number: number
52377 },
52378 __type__: {
52379 object: object
52380 }
52381 },
52382 id: {
52383 string: string,
52384 number: number
52385 },
52386 image: {
52387 selected: {
52388 string: string,
52389 'undefined': 'undefined'
52390 },
52391 // --> URL
52392 unselected: {
52393 string: string,
52394 'undefined': 'undefined'
52395 },
52396 // --> URL
52397 __type__: {
52398 object: object,
52399 string: string
52400 }
52401 },
52402 imagePadding: {
52403 top: {
52404 number: number
52405 },
52406 right: {
52407 number: number
52408 },
52409 bottom: {
52410 number: number
52411 },
52412 left: {
52413 number: number
52414 },
52415 __type__: {
52416 object: object,
52417 number: number
52418 }
52419 },
52420 label: {
52421 string: string,
52422 'undefined': 'undefined'
52423 },
52424 labelHighlightBold: {
52425 boolean: bool
52426 },
52427 level: {
52428 number: number,
52429 'undefined': 'undefined'
52430 },
52431 margin: {
52432 top: {
52433 number: number
52434 },
52435 right: {
52436 number: number
52437 },
52438 bottom: {
52439 number: number
52440 },
52441 left: {
52442 number: number
52443 },
52444 __type__: {
52445 object: object,
52446 number: number
52447 }
52448 },
52449 mass: {
52450 number: number
52451 },
52452 physics: {
52453 boolean: bool
52454 },
52455 scaling: {
52456 min: {
52457 number: number
52458 },
52459 max: {
52460 number: number
52461 },
52462 label: {
52463 enabled: {
52464 boolean: bool
52465 },
52466 min: {
52467 number: number
52468 },
52469 max: {
52470 number: number
52471 },
52472 maxVisible: {
52473 number: number
52474 },
52475 drawThreshold: {
52476 number: number
52477 },
52478 __type__: {
52479 object: object,
52480 boolean: bool
52481 }
52482 },
52483 customScalingFunction: {
52484 'function': 'function'
52485 },
52486 __type__: {
52487 object: object
52488 }
52489 },
52490 shadow: {
52491 enabled: {
52492 boolean: bool
52493 },
52494 color: {
52495 string: string
52496 },
52497 size: {
52498 number: number
52499 },
52500 x: {
52501 number: number
52502 },
52503 y: {
52504 number: number
52505 },
52506 __type__: {
52507 object: object,
52508 boolean: bool
52509 }
52510 },
52511 shape: {
52512 string: ['ellipse', 'circle', 'database', 'box', 'text', 'image', 'circularImage', 'diamond', 'dot', 'star', 'triangle', 'triangleDown', 'square', 'icon', 'hexagon']
52513 },
52514 shapeProperties: {
52515 borderDashes: {
52516 boolean: bool,
52517 array: array
52518 },
52519 borderRadius: {
52520 number: number
52521 },
52522 interpolation: {
52523 boolean: bool
52524 },
52525 useImageSize: {
52526 boolean: bool
52527 },
52528 useBorderWithImage: {
52529 boolean: bool
52530 },
52531 __type__: {
52532 object: object
52533 }
52534 },
52535 size: {
52536 number: number
52537 },
52538 title: {
52539 string: string,
52540 dom: dom,
52541 'undefined': 'undefined'
52542 },
52543 value: {
52544 number: number,
52545 'undefined': 'undefined'
52546 },
52547 widthConstraint: {
52548 minimum: {
52549 number: number
52550 },
52551 maximum: {
52552 number: number
52553 },
52554 __type__: {
52555 object: object,
52556 boolean: bool,
52557 number: number
52558 }
52559 },
52560 x: {
52561 number: number
52562 },
52563 y: {
52564 number: number
52565 },
52566 __type__: {
52567 object: object
52568 }
52569 },
52570 physics: {
52571 enabled: {
52572 boolean: bool
52573 },
52574 barnesHut: {
52575 gravitationalConstant: {
52576 number: number
52577 },
52578 centralGravity: {
52579 number: number
52580 },
52581 springLength: {
52582 number: number
52583 },
52584 springConstant: {
52585 number: number
52586 },
52587 damping: {
52588 number: number
52589 },
52590 avoidOverlap: {
52591 number: number
52592 },
52593 __type__: {
52594 object: object
52595 }
52596 },
52597 forceAtlas2Based: {
52598 gravitationalConstant: {
52599 number: number
52600 },
52601 centralGravity: {
52602 number: number
52603 },
52604 springLength: {
52605 number: number
52606 },
52607 springConstant: {
52608 number: number
52609 },
52610 damping: {
52611 number: number
52612 },
52613 avoidOverlap: {
52614 number: number
52615 },
52616 __type__: {
52617 object: object
52618 }
52619 },
52620 repulsion: {
52621 centralGravity: {
52622 number: number
52623 },
52624 springLength: {
52625 number: number
52626 },
52627 springConstant: {
52628 number: number
52629 },
52630 nodeDistance: {
52631 number: number
52632 },
52633 damping: {
52634 number: number
52635 },
52636 __type__: {
52637 object: object
52638 }
52639 },
52640 hierarchicalRepulsion: {
52641 centralGravity: {
52642 number: number
52643 },
52644 springLength: {
52645 number: number
52646 },
52647 springConstant: {
52648 number: number
52649 },
52650 nodeDistance: {
52651 number: number
52652 },
52653 damping: {
52654 number: number
52655 },
52656 avoidOverlap: {
52657 number: number
52658 },
52659 __type__: {
52660 object: object
52661 }
52662 },
52663 maxVelocity: {
52664 number: number
52665 },
52666 minVelocity: {
52667 number: number
52668 },
52669 // px/s
52670 solver: {
52671 string: ['barnesHut', 'repulsion', 'hierarchicalRepulsion', 'forceAtlas2Based']
52672 },
52673 stabilization: {
52674 enabled: {
52675 boolean: bool
52676 },
52677 iterations: {
52678 number: number
52679 },
52680 // maximum number of iteration to stabilize
52681 updateInterval: {
52682 number: number
52683 },
52684 onlyDynamicEdges: {
52685 boolean: bool
52686 },
52687 fit: {
52688 boolean: bool
52689 },
52690 __type__: {
52691 object: object,
52692 boolean: bool
52693 }
52694 },
52695 timestep: {
52696 number: number
52697 },
52698 adaptiveTimestep: {
52699 boolean: bool
52700 },
52701 __type__: {
52702 object: object,
52703 boolean: bool
52704 }
52705 },
52706 //globals :
52707 autoResize: {
52708 boolean: bool
52709 },
52710 clickToUse: {
52711 boolean: bool
52712 },
52713 locale: {
52714 string: string
52715 },
52716 locales: {
52717 __any__: {
52718 any: any
52719 },
52720 __type__: {
52721 object: object
52722 }
52723 },
52724 height: {
52725 string: string
52726 },
52727 width: {
52728 string: string
52729 },
52730 __type__: {
52731 object: object
52732 }
52733 };
52734 allOptions$1.groups.__any__ = allOptions$1.nodes;
52735 allOptions$1.manipulation.controlNodeStyle = allOptions$1.nodes;
52736 var configureOptions = {
52737 nodes: {
52738 borderWidth: [1, 0, 10, 1],
52739 borderWidthSelected: [2, 0, 10, 1],
52740 color: {
52741 border: ['color', '#2B7CE9'],
52742 background: ['color', '#97C2FC'],
52743 highlight: {
52744 border: ['color', '#2B7CE9'],
52745 background: ['color', '#D2E5FF']
52746 },
52747 hover: {
52748 border: ['color', '#2B7CE9'],
52749 background: ['color', '#D2E5FF']
52750 }
52751 },
52752 fixed: {
52753 x: false,
52754 y: false
52755 },
52756 font: {
52757 color: ['color', '#343434'],
52758 size: [14, 0, 100, 1],
52759 // px
52760 face: ['arial', 'verdana', 'tahoma'],
52761 background: ['color', 'none'],
52762 strokeWidth: [0, 0, 50, 1],
52763 // px
52764 strokeColor: ['color', '#ffffff']
52765 },
52766 //group: 'string',
52767 hidden: false,
52768 labelHighlightBold: true,
52769 //icon: {
52770 // face: 'string', //'FontAwesome',
52771 // code: 'string', //'\uf007',
52772 // size: [50, 0, 200, 1], //50,
52773 // color: ['color','#2B7CE9'] //'#aa00ff'
52774 //},
52775 //image: 'string', // --> URL
52776 physics: true,
52777 scaling: {
52778 min: [10, 0, 200, 1],
52779 max: [30, 0, 200, 1],
52780 label: {
52781 enabled: false,
52782 min: [14, 0, 200, 1],
52783 max: [30, 0, 200, 1],
52784 maxVisible: [30, 0, 200, 1],
52785 drawThreshold: [5, 0, 20, 1]
52786 }
52787 },
52788 shadow: {
52789 enabled: false,
52790 color: 'rgba(0,0,0,0.5)',
52791 size: [10, 0, 20, 1],
52792 x: [5, -30, 30, 1],
52793 y: [5, -30, 30, 1]
52794 },
52795 shape: ['ellipse', 'box', 'circle', 'database', 'diamond', 'dot', 'square', 'star', 'text', 'triangle', 'triangleDown', 'hexagon'],
52796 shapeProperties: {
52797 borderDashes: false,
52798 borderRadius: [6, 0, 20, 1],
52799 interpolation: true,
52800 useImageSize: false
52801 },
52802 size: [25, 0, 200, 1]
52803 },
52804 edges: {
52805 arrows: {
52806 to: {
52807 enabled: false,
52808 scaleFactor: [1, 0, 3, 0.05],
52809 type: 'arrow'
52810 },
52811 middle: {
52812 enabled: false,
52813 scaleFactor: [1, 0, 3, 0.05],
52814 type: 'arrow'
52815 },
52816 from: {
52817 enabled: false,
52818 scaleFactor: [1, 0, 3, 0.05],
52819 type: 'arrow'
52820 }
52821 },
52822 arrowStrikethrough: true,
52823 color: {
52824 color: ['color', '#848484'],
52825 highlight: ['color', '#848484'],
52826 hover: ['color', '#848484'],
52827 inherit: ['from', 'to', 'both', true, false],
52828 opacity: [1, 0, 1, 0.05]
52829 },
52830 dashes: false,
52831 font: {
52832 color: ['color', '#343434'],
52833 size: [14, 0, 100, 1],
52834 // px
52835 face: ['arial', 'verdana', 'tahoma'],
52836 background: ['color', 'none'],
52837 strokeWidth: [2, 0, 50, 1],
52838 // px
52839 strokeColor: ['color', '#ffffff'],
52840 align: ['horizontal', 'top', 'middle', 'bottom']
52841 },
52842 hidden: false,
52843 hoverWidth: [1.5, 0, 5, 0.1],
52844 labelHighlightBold: true,
52845 physics: true,
52846 scaling: {
52847 min: [1, 0, 100, 1],
52848 max: [15, 0, 100, 1],
52849 label: {
52850 enabled: true,
52851 min: [14, 0, 200, 1],
52852 max: [30, 0, 200, 1],
52853 maxVisible: [30, 0, 200, 1],
52854 drawThreshold: [5, 0, 20, 1]
52855 }
52856 },
52857 selectionWidth: [1.5, 0, 5, 0.1],
52858 selfReferenceSize: [20, 0, 200, 1],
52859 shadow: {
52860 enabled: false,
52861 color: 'rgba(0,0,0,0.5)',
52862 size: [10, 0, 20, 1],
52863 x: [5, -30, 30, 1],
52864 y: [5, -30, 30, 1]
52865 },
52866 smooth: {
52867 enabled: true,
52868 type: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW', 'cubicBezier'],
52869 forceDirection: ['horizontal', 'vertical', 'none'],
52870 roundness: [0.5, 0, 1, 0.05]
52871 },
52872 width: [1, 0, 30, 1]
52873 },
52874 layout: {
52875 //randomSeed: [0, 0, 500, 1],
52876 //improvedLayout: true,
52877 hierarchical: {
52878 enabled: false,
52879 levelSeparation: [150, 20, 500, 5],
52880 nodeSpacing: [100, 20, 500, 5],
52881 treeSpacing: [200, 20, 500, 5],
52882 blockShifting: true,
52883 edgeMinimization: true,
52884 parentCentralization: true,
52885 direction: ['UD', 'DU', 'LR', 'RL'],
52886 // UD, DU, LR, RL
52887 sortMethod: ['hubsize', 'directed'],
52888 // hubsize, directed
52889 shakeTowards: ['leaves', 'roots'] // leaves, roots
52890
52891 }
52892 },
52893 interaction: {
52894 dragNodes: true,
52895 dragView: true,
52896 hideEdgesOnDrag: false,
52897 hideEdgesOnZoom: false,
52898 hideNodesOnDrag: false,
52899 hover: false,
52900 keyboard: {
52901 enabled: false,
52902 speed: {
52903 x: [10, 0, 40, 1],
52904 y: [10, 0, 40, 1],
52905 zoom: [0.02, 0, 0.1, 0.005]
52906 },
52907 bindToWindow: true
52908 },
52909 multiselect: false,
52910 navigationButtons: false,
52911 selectable: true,
52912 selectConnectedEdges: true,
52913 hoverConnectedEdges: true,
52914 tooltipDelay: [300, 0, 1000, 25],
52915 zoomView: true,
52916 zoomSpeed: [1, 1, 1, 1]
52917 },
52918 manipulation: {
52919 enabled: false,
52920 initiallyActive: false
52921 },
52922 physics: {
52923 enabled: true,
52924 barnesHut: {
52925 //theta: [0.5, 0.1, 1, 0.05],
52926 gravitationalConstant: [-2000, -30000, 0, 50],
52927 centralGravity: [0.3, 0, 10, 0.05],
52928 springLength: [95, 0, 500, 5],
52929 springConstant: [0.04, 0, 1.2, 0.005],
52930 damping: [0.09, 0, 1, 0.01],
52931 avoidOverlap: [0, 0, 1, 0.01]
52932 },
52933 forceAtlas2Based: {
52934 //theta: [0.5, 0.1, 1, 0.05],
52935 gravitationalConstant: [-50, -500, 0, 1],
52936 centralGravity: [0.01, 0, 1, 0.005],
52937 springLength: [95, 0, 500, 5],
52938 springConstant: [0.08, 0, 1.2, 0.005],
52939 damping: [0.4, 0, 1, 0.01],
52940 avoidOverlap: [0, 0, 1, 0.01]
52941 },
52942 repulsion: {
52943 centralGravity: [0.2, 0, 10, 0.05],
52944 springLength: [200, 0, 500, 5],
52945 springConstant: [0.05, 0, 1.2, 0.005],
52946 nodeDistance: [100, 0, 500, 5],
52947 damping: [0.09, 0, 1, 0.01]
52948 },
52949 hierarchicalRepulsion: {
52950 centralGravity: [0.2, 0, 10, 0.05],
52951 springLength: [100, 0, 500, 5],
52952 springConstant: [0.01, 0, 1.2, 0.005],
52953 nodeDistance: [120, 0, 500, 5],
52954 damping: [0.09, 0, 1, 0.01],
52955 avoidOverlap: [0, 0, 1, 0.01]
52956 },
52957 maxVelocity: [50, 0, 150, 1],
52958 minVelocity: [0.1, 0.01, 0.5, 0.01],
52959 solver: ['barnesHut', 'forceAtlas2Based', 'repulsion', 'hierarchicalRepulsion'],
52960 timestep: [0.5, 0.01, 1, 0.01] //adaptiveTimestep: true
52961
52962 }
52963 };
52964
52965 var allOptions$2 = /*#__PURE__*/Object.freeze({
52966 __proto__: null,
52967 allOptions: allOptions$1,
52968 configureOptions: configureOptions
52969 });
52970
52971 /**
52972 * The Floyd–Warshall algorithm is an algorithm for finding shortest paths in
52973 * a weighted graph with positive or negative edge weights (but with no negative
52974 * cycles). - https://en.wikipedia.org/wiki/Floyd–Warshall_algorithm
52975 */
52976 var FloydWarshall =
52977 /*#__PURE__*/
52978 function () {
52979 /**
52980 * @ignore
52981 */
52982 function FloydWarshall() {
52983 _classCallCheck(this, FloydWarshall);
52984 }
52985 /**
52986 *
52987 * @param {Object} body
52988 * @param {Array.<Node>} nodesArray
52989 * @param {Array.<Edge>} edgesArray
52990 * @returns {{}}
52991 */
52992
52993
52994 _createClass(FloydWarshall, [{
52995 key: "getDistances",
52996 value: function getDistances(body, nodesArray, edgesArray) {
52997 var D_matrix = {};
52998 var edges = body.edges; // prepare matrix with large numbers
52999
53000 for (var i = 0; i < nodesArray.length; i++) {
53001 var node = nodesArray[i];
53002 var cell = {};
53003 D_matrix[node] = cell;
53004
53005 for (var j = 0; j < nodesArray.length; j++) {
53006 cell[nodesArray[j]] = i == j ? 0 : 1e9;
53007 }
53008 } // put the weights for the edges in. This assumes unidirectionality.
53009
53010
53011 for (var _i = 0; _i < edgesArray.length; _i++) {
53012 var edge = edges[edgesArray[_i]]; // edge has to be connected if it counts to the distances. If it is connected to inner clusters it will crash so we also check if it is in the D_matrix
53013
53014 if (edge.connected === true && D_matrix[edge.fromId] !== undefined && D_matrix[edge.toId] !== undefined) {
53015 D_matrix[edge.fromId][edge.toId] = 1;
53016 D_matrix[edge.toId][edge.fromId] = 1;
53017 }
53018 }
53019
53020 var nodeCount = nodesArray.length; // Adapted FloydWarshall based on unidirectionality to greatly reduce complexity.
53021
53022 for (var k = 0; k < nodeCount; k++) {
53023 var knode = nodesArray[k];
53024 var kcolm = D_matrix[knode];
53025
53026 for (var _i2 = 0; _i2 < nodeCount - 1; _i2++) {
53027 var inode = nodesArray[_i2];
53028 var icolm = D_matrix[inode];
53029
53030 for (var _j = _i2 + 1; _j < nodeCount; _j++) {
53031 var jnode = nodesArray[_j];
53032 var jcolm = D_matrix[jnode];
53033 var val = Math.min(icolm[jnode], icolm[knode] + kcolm[jnode]);
53034 icolm[jnode] = val;
53035 jcolm[inode] = val;
53036 }
53037 }
53038 }
53039
53040 return D_matrix;
53041 }
53042 }]);
53043
53044 return FloydWarshall;
53045 }();
53046
53047 /**
53048 * KamadaKawai positions the nodes initially based on
53049 *
53050 * "AN ALGORITHM FOR DRAWING GENERAL UNDIRECTED GRAPHS"
53051 * -- Tomihisa KAMADA and Satoru KAWAI in 1989
53052 *
53053 * Possible optimizations in the distance calculation can be implemented.
53054 */
53055
53056 var KamadaKawai =
53057 /*#__PURE__*/
53058 function () {
53059 /**
53060 * @param {Object} body
53061 * @param {number} edgeLength
53062 * @param {number} edgeStrength
53063 */
53064 function KamadaKawai(body, edgeLength, edgeStrength) {
53065 _classCallCheck(this, KamadaKawai);
53066
53067 this.body = body;
53068 this.springLength = edgeLength;
53069 this.springConstant = edgeStrength;
53070 this.distanceSolver = new FloydWarshall();
53071 }
53072 /**
53073 * Not sure if needed but can be used to update the spring length and spring constant
53074 * @param {Object} options
53075 */
53076
53077
53078 _createClass(KamadaKawai, [{
53079 key: "setOptions",
53080 value: function setOptions(options) {
53081 if (options) {
53082 if (options.springLength) {
53083 this.springLength = options.springLength;
53084 }
53085
53086 if (options.springConstant) {
53087 this.springConstant = options.springConstant;
53088 }
53089 }
53090 }
53091 /**
53092 * Position the system
53093 * @param {Array.<Node>} nodesArray
53094 * @param {Array.<vis.Edge>} edgesArray
53095 * @param {boolean} [ignoreClusters=false]
53096 */
53097
53098 }, {
53099 key: "solve",
53100 value: function solve(nodesArray, edgesArray) {
53101 var ignoreClusters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
53102 // get distance matrix
53103 var D_matrix = this.distanceSolver.getDistances(this.body, nodesArray, edgesArray); // distance matrix
53104 // get the L Matrix
53105
53106 this._createL_matrix(D_matrix); // get the K Matrix
53107
53108
53109 this._createK_matrix(D_matrix); // initial E Matrix
53110
53111
53112 this._createE_matrix(); // calculate positions
53113
53114
53115 var threshold = 0.01;
53116 var innerThreshold = 1;
53117 var iterations = 0;
53118 var maxIterations = Math.max(1000, Math.min(10 * this.body.nodeIndices.length, 6000));
53119 var maxInnerIterations = 5;
53120 var maxEnergy = 1e9;
53121 var highE_nodeId = 0,
53122 dE_dx = 0,
53123 dE_dy = 0,
53124 delta_m = 0,
53125 subIterations = 0;
53126
53127 while (maxEnergy > threshold && iterations < maxIterations) {
53128 iterations += 1;
53129
53130 var _this$_getHighestEner = this._getHighestEnergyNode(ignoreClusters);
53131
53132 var _this$_getHighestEner2 = _slicedToArray(_this$_getHighestEner, 4);
53133
53134 highE_nodeId = _this$_getHighestEner2[0];
53135 maxEnergy = _this$_getHighestEner2[1];
53136 dE_dx = _this$_getHighestEner2[2];
53137 dE_dy = _this$_getHighestEner2[3];
53138 delta_m = maxEnergy;
53139 subIterations = 0;
53140
53141 while (delta_m > innerThreshold && subIterations < maxInnerIterations) {
53142 subIterations += 1;
53143
53144 this._moveNode(highE_nodeId, dE_dx, dE_dy);
53145
53146 var _this$_getEnergy = this._getEnergy(highE_nodeId);
53147
53148 var _this$_getEnergy2 = _slicedToArray(_this$_getEnergy, 3);
53149
53150 delta_m = _this$_getEnergy2[0];
53151 dE_dx = _this$_getEnergy2[1];
53152 dE_dy = _this$_getEnergy2[2];
53153 }
53154 }
53155 }
53156 /**
53157 * get the node with the highest energy
53158 * @param {boolean} ignoreClusters
53159 * @returns {number[]}
53160 * @private
53161 */
53162
53163 }, {
53164 key: "_getHighestEnergyNode",
53165 value: function _getHighestEnergyNode(ignoreClusters) {
53166 var nodesArray = this.body.nodeIndices;
53167 var nodes = this.body.nodes;
53168 var maxEnergy = 0;
53169 var maxEnergyNodeId = nodesArray[0];
53170 var dE_dx_max = 0,
53171 dE_dy_max = 0;
53172
53173 for (var nodeIdx = 0; nodeIdx < nodesArray.length; nodeIdx++) {
53174 var m = nodesArray[nodeIdx]; // by not evaluating nodes with predefined positions we should only move nodes that have no positions.
53175
53176 if (nodes[m].predefinedPosition === false || nodes[m].isCluster === true && ignoreClusters === true || nodes[m].options.fixed.x === true || nodes[m].options.fixed.y === true) {
53177 var _this$_getEnergy3 = this._getEnergy(m),
53178 _this$_getEnergy4 = _slicedToArray(_this$_getEnergy3, 3),
53179 delta_m = _this$_getEnergy4[0],
53180 dE_dx = _this$_getEnergy4[1],
53181 dE_dy = _this$_getEnergy4[2];
53182
53183 if (maxEnergy < delta_m) {
53184 maxEnergy = delta_m;
53185 maxEnergyNodeId = m;
53186 dE_dx_max = dE_dx;
53187 dE_dy_max = dE_dy;
53188 }
53189 }
53190 }
53191
53192 return [maxEnergyNodeId, maxEnergy, dE_dx_max, dE_dy_max];
53193 }
53194 /**
53195 * calculate the energy of a single node
53196 * @param {Node.id} m
53197 * @returns {number[]}
53198 * @private
53199 */
53200
53201 }, {
53202 key: "_getEnergy",
53203 value: function _getEnergy(m) {
53204 var _this$E_sums$m = _slicedToArray(this.E_sums[m], 2),
53205 dE_dx = _this$E_sums$m[0],
53206 dE_dy = _this$E_sums$m[1];
53207
53208 var delta_m = Math.sqrt(Math.pow(dE_dx, 2) + Math.pow(dE_dy, 2));
53209 return [delta_m, dE_dx, dE_dy];
53210 }
53211 /**
53212 * move the node based on it's energy
53213 * the dx and dy are calculated from the linear system proposed by Kamada and Kawai
53214 * @param {number} m
53215 * @param {number} dE_dx
53216 * @param {number} dE_dy
53217 * @private
53218 */
53219
53220 }, {
53221 key: "_moveNode",
53222 value: function _moveNode(m, dE_dx, dE_dy) {
53223 var nodesArray = this.body.nodeIndices;
53224 var nodes = this.body.nodes;
53225 var d2E_dx2 = 0;
53226 var d2E_dxdy = 0;
53227 var d2E_dy2 = 0;
53228 var x_m = nodes[m].x;
53229 var y_m = nodes[m].y;
53230 var km = this.K_matrix[m];
53231 var lm = this.L_matrix[m];
53232
53233 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
53234 var i = nodesArray[iIdx];
53235
53236 if (i !== m) {
53237 var x_i = nodes[i].x;
53238 var y_i = nodes[i].y;
53239 var kmat = km[i];
53240 var lmat = lm[i];
53241 var denominator = 1.0 / Math.pow(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2), 1.5);
53242 d2E_dx2 += kmat * (1 - lmat * Math.pow(y_m - y_i, 2) * denominator);
53243 d2E_dxdy += kmat * (lmat * (x_m - x_i) * (y_m - y_i) * denominator);
53244 d2E_dy2 += kmat * (1 - lmat * Math.pow(x_m - x_i, 2) * denominator);
53245 }
53246 } // make the variable names easier to make the solving of the linear system easier to read
53247
53248
53249 var A = d2E_dx2,
53250 B = d2E_dxdy,
53251 C = dE_dx,
53252 D = d2E_dy2,
53253 E = dE_dy; // solve the linear system for dx and dy
53254
53255 var dy = (C / A + E / B) / (B / A - D / B);
53256 var dx = -(B * dy + C) / A; // move the node
53257
53258 nodes[m].x += dx;
53259 nodes[m].y += dy; // Recalculate E_matrix (should be incremental)
53260
53261 this._updateE_matrix(m);
53262 }
53263 /**
53264 * Create the L matrix: edge length times shortest path
53265 * @param {Object} D_matrix
53266 * @private
53267 */
53268
53269 }, {
53270 key: "_createL_matrix",
53271 value: function _createL_matrix(D_matrix) {
53272 var nodesArray = this.body.nodeIndices;
53273 var edgeLength = this.springLength;
53274 this.L_matrix = [];
53275
53276 for (var i = 0; i < nodesArray.length; i++) {
53277 this.L_matrix[nodesArray[i]] = {};
53278
53279 for (var j = 0; j < nodesArray.length; j++) {
53280 this.L_matrix[nodesArray[i]][nodesArray[j]] = edgeLength * D_matrix[nodesArray[i]][nodesArray[j]];
53281 }
53282 }
53283 }
53284 /**
53285 * Create the K matrix: spring constants times shortest path
53286 * @param {Object} D_matrix
53287 * @private
53288 */
53289
53290 }, {
53291 key: "_createK_matrix",
53292 value: function _createK_matrix(D_matrix) {
53293 var nodesArray = this.body.nodeIndices;
53294 var edgeStrength = this.springConstant;
53295 this.K_matrix = [];
53296
53297 for (var i = 0; i < nodesArray.length; i++) {
53298 this.K_matrix[nodesArray[i]] = {};
53299
53300 for (var j = 0; j < nodesArray.length; j++) {
53301 this.K_matrix[nodesArray[i]][nodesArray[j]] = edgeStrength * Math.pow(D_matrix[nodesArray[i]][nodesArray[j]], -2);
53302 }
53303 }
53304 }
53305 /**
53306 * Create matrix with all energies between nodes
53307 * @private
53308 */
53309
53310 }, {
53311 key: "_createE_matrix",
53312 value: function _createE_matrix() {
53313 var nodesArray = this.body.nodeIndices;
53314 var nodes = this.body.nodes;
53315 this.E_matrix = {};
53316 this.E_sums = {};
53317
53318 for (var mIdx = 0; mIdx < nodesArray.length; mIdx++) {
53319 this.E_matrix[nodesArray[mIdx]] = [];
53320 }
53321
53322 for (var _mIdx = 0; _mIdx < nodesArray.length; _mIdx++) {
53323 var m = nodesArray[_mIdx];
53324 var x_m = nodes[m].x;
53325 var y_m = nodes[m].y;
53326 var dE_dx = 0;
53327 var dE_dy = 0;
53328
53329 for (var iIdx = _mIdx; iIdx < nodesArray.length; iIdx++) {
53330 var i = nodesArray[iIdx];
53331
53332 if (i !== m) {
53333 var x_i = nodes[i].x;
53334 var y_i = nodes[i].y;
53335 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
53336 this.E_matrix[m][iIdx] = [this.K_matrix[m][i] * (x_m - x_i - this.L_matrix[m][i] * (x_m - x_i) * denominator), this.K_matrix[m][i] * (y_m - y_i - this.L_matrix[m][i] * (y_m - y_i) * denominator)];
53337 this.E_matrix[i][_mIdx] = this.E_matrix[m][iIdx];
53338 dE_dx += this.E_matrix[m][iIdx][0];
53339 dE_dy += this.E_matrix[m][iIdx][1];
53340 }
53341 } //Store sum
53342
53343
53344 this.E_sums[m] = [dE_dx, dE_dy];
53345 }
53346 }
53347 /**
53348 * Update method, just doing single column (rows are auto-updated) (update all sums)
53349 *
53350 * @param {number} m
53351 * @private
53352 */
53353
53354 }, {
53355 key: "_updateE_matrix",
53356 value: function _updateE_matrix(m) {
53357 var nodesArray = this.body.nodeIndices;
53358 var nodes = this.body.nodes;
53359 var colm = this.E_matrix[m];
53360 var kcolm = this.K_matrix[m];
53361 var lcolm = this.L_matrix[m];
53362 var x_m = nodes[m].x;
53363 var y_m = nodes[m].y;
53364 var dE_dx = 0;
53365 var dE_dy = 0;
53366
53367 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
53368 var i = nodesArray[iIdx];
53369
53370 if (i !== m) {
53371 //Keep old energy value for sum modification below
53372 var cell = colm[iIdx];
53373 var oldDx = cell[0];
53374 var oldDy = cell[1]; //Calc new energy:
53375
53376 var x_i = nodes[i].x;
53377 var y_i = nodes[i].y;
53378 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
53379 var dx = kcolm[i] * (x_m - x_i - lcolm[i] * (x_m - x_i) * denominator);
53380 var dy = kcolm[i] * (y_m - y_i - lcolm[i] * (y_m - y_i) * denominator);
53381 colm[iIdx] = [dx, dy];
53382 dE_dx += dx;
53383 dE_dy += dy; //add new energy to sum of each column
53384
53385 var sum = this.E_sums[i];
53386 sum[0] += dx - oldDx;
53387 sum[1] += dy - oldDy;
53388 }
53389 } //Store sum at -1 index
53390
53391
53392 this.E_sums[m] = [dE_dx, dE_dy];
53393 }
53394 }]);
53395
53396 return KamadaKawai;
53397 }();
53398
53399 // Load custom shapes into CanvasRenderingContext2D
53400 /**
53401 * Create a network visualization, displaying nodes and edges.
53402 *
53403 * @param {Element} container The DOM element in which the Network will
53404 * be created. Normally a div element.
53405 * @param {Object} data An object containing parameters
53406 * {Array} nodes
53407 * {Array} edges
53408 * @param {Object} options Options
53409 * @constructor Network
53410 */
53411
53412 function Network(container, data, options) {
53413 var _this = this;
53414
53415 if (!(this instanceof Network)) {
53416 throw new SyntaxError('Constructor must be called with the new operator');
53417 } // set constant values
53418
53419
53420 this.options = {};
53421 this.defaultOptions = {
53422 locale: 'en',
53423 locales: locales,
53424 clickToUse: false
53425 };
53426 extend(this.options, this.defaultOptions);
53427 /**
53428 * Containers for nodes and edges.
53429 *
53430 * 'edges' and 'nodes' contain the full definitions of all the network elements.
53431 * 'nodeIndices' and 'edgeIndices' contain the id's of the active elements.
53432 *
53433 * The distinction is important, because a defined node need not be active, i.e.
53434 * visible on the canvas. This happens in particular when clusters are defined, in
53435 * that case there will be nodes and edges not displayed.
53436 * The bottom line is that all code with actions related to visibility, *must* use
53437 * 'nodeIndices' and 'edgeIndices', not 'nodes' and 'edges' directly.
53438 */
53439
53440 this.body = {
53441 container: container,
53442 // See comment above for following fields
53443 nodes: {},
53444 nodeIndices: [],
53445 edges: {},
53446 edgeIndices: [],
53447 emitter: {
53448 on: this.on.bind(this),
53449 off: this.off.bind(this),
53450 emit: this.emit.bind(this),
53451 once: this.once.bind(this)
53452 },
53453 eventListeners: {
53454 onTap: function onTap() {},
53455 onTouch: function onTouch() {},
53456 onDoubleTap: function onDoubleTap() {},
53457 onHold: function onHold() {},
53458 onDragStart: function onDragStart() {},
53459 onDrag: function onDrag() {},
53460 onDragEnd: function onDragEnd() {},
53461 onMouseWheel: function onMouseWheel() {},
53462 onPinch: function onPinch() {},
53463 onMouseMove: function onMouseMove() {},
53464 onRelease: function onRelease() {},
53465 onContext: function onContext() {}
53466 },
53467 data: {
53468 nodes: null,
53469 // A DataSet or DataView
53470 edges: null // A DataSet or DataView
53471
53472 },
53473 functions: {
53474 createNode: function createNode() {},
53475 createEdge: function createEdge() {},
53476 getPointer: function getPointer() {}
53477 },
53478 modules: {},
53479 view: {
53480 scale: 1,
53481 translation: {
53482 x: 0,
53483 y: 0
53484 }
53485 }
53486 }; // bind the event listeners
53487
53488 this.bindEventListeners(); // setting up all modules
53489
53490 this.images = new Images(function () {
53491 return _this.body.emitter.emit("_requestRedraw");
53492 }); // object with images
53493
53494 this.groups = new Groups(); // object with groups
53495
53496 this.canvas = new Canvas(this.body); // DOM handler
53497
53498 this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler
53499
53500 this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key
53501
53502 this.view = new View(this.body, this.canvas); // camera handler, does animations and zooms
53503
53504 this.renderer = new CanvasRenderer(this.body, this.canvas); // renderer, starts renderloop, has events that modules can hook into
53505
53506 this.physics = new PhysicsEngine(this.body); // physics engine, does all the simulations
53507
53508 this.layoutEngine = new LayoutEngine(this.body); // layout engine for inital layout and hierarchical layout
53509
53510 this.clustering = new ClusterEngine(this.body); // clustering api
53511
53512 this.manipulation = new ManipulationSystem(this.body, this.canvas, this.selectionHandler, this.interactionHandler); // data manipulation system
53513
53514 this.nodesHandler = new NodesHandler(this.body, this.images, this.groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
53515
53516 this.edgesHandler = new EdgesHandler(this.body, this.images, this.groups); // Handle adding, deleting and updating of edges as well as global options
53517
53518 this.body.modules["kamadaKawai"] = new KamadaKawai(this.body, 150, 0.05); // Layouting algorithm.
53519
53520 this.body.modules["clustering"] = this.clustering; // create the DOM elements
53521
53522 this.canvas._create(); // apply options
53523
53524
53525 this.setOptions(options); // load data (the disable start variable will be the same as the enabled clustering)
53526
53527 this.setData(data);
53528 } // Extend Network with an Emitter mixin
53529
53530 componentEmitter(Network.prototype);
53531 /**
53532 * Set options
53533 * @param {Object} options
53534 */
53535
53536 Network.prototype.setOptions = function (options) {
53537 var _this2 = this;
53538
53539 if (options === null) {
53540 options = undefined; // This ensures that options handling doesn't crash in the handling
53541 }
53542
53543 if (options !== undefined) {
53544 var errorFound = Validator.validate(options, allOptions$1);
53545
53546 if (errorFound === true) {
53547 console.log('%cErrors have been found in the supplied options object.', printStyle);
53548 } // copy the global fields over
53549
53550
53551 var fields = ['locale', 'locales', 'clickToUse'];
53552 selectiveDeepExtend(fields, this.options, options); // the hierarchical system can adapt the edges and the physics to it's own options because not all combinations work with the hierarichical system.
53553
53554 options = this.layoutEngine.setOptions(options.layout, options);
53555 this.canvas.setOptions(options); // options for canvas are in globals
53556 // pass the options to the modules
53557
53558 this.groups.setOptions(options.groups);
53559 this.nodesHandler.setOptions(options.nodes);
53560 this.edgesHandler.setOptions(options.edges);
53561 this.physics.setOptions(options.physics);
53562 this.manipulation.setOptions(options.manipulation, options, this.options); // manipulation uses the locales in the globals
53563
53564 this.interactionHandler.setOptions(options.interaction);
53565 this.renderer.setOptions(options.interaction); // options for rendering are in interaction
53566
53567 this.selectionHandler.setOptions(options.interaction); // options for selection are in interaction
53568 // reload the settings of the nodes to apply changes in groups that are not referenced by pointer.
53569
53570 if (options.groups !== undefined) {
53571 this.body.emitter.emit("refreshNodes");
53572 } // these two do not have options at the moment, here for completeness
53573 //this.view.setOptions(options.view);
53574 //this.clustering.setOptions(options.clustering);
53575
53576
53577 if ('configure' in options) {
53578 if (!this.configurator) {
53579 this.configurator = new Configurator(this, this.body.container, configureOptions, this.canvas.pixelRatio);
53580 }
53581
53582 this.configurator.setOptions(options.configure);
53583 } // if the configuration system is enabled, copy all options and put them into the config system
53584
53585
53586 if (this.configurator && this.configurator.options.enabled === true) {
53587 var networkOptions = {
53588 nodes: {},
53589 edges: {},
53590 layout: {},
53591 interaction: {},
53592 manipulation: {},
53593 physics: {},
53594 global: {}
53595 };
53596 deepExtend(networkOptions.nodes, this.nodesHandler.options);
53597 deepExtend(networkOptions.edges, this.edgesHandler.options);
53598 deepExtend(networkOptions.layout, this.layoutEngine.options); // load the selectionHandler and render default options in to the interaction group
53599
53600 deepExtend(networkOptions.interaction, this.selectionHandler.options);
53601 deepExtend(networkOptions.interaction, this.renderer.options);
53602 deepExtend(networkOptions.interaction, this.interactionHandler.options);
53603 deepExtend(networkOptions.manipulation, this.manipulation.options);
53604 deepExtend(networkOptions.physics, this.physics.options); // load globals into the global object
53605
53606 deepExtend(networkOptions.global, this.canvas.options);
53607 deepExtend(networkOptions.global, this.options);
53608 this.configurator.setModuleOptions(networkOptions);
53609 } // handle network global options
53610
53611
53612 if (options.clickToUse !== undefined) {
53613 if (options.clickToUse === true) {
53614 if (this.activator === undefined) {
53615 this.activator = new Activator_1(this.canvas.frame);
53616 this.activator.on('change', function () {
53617 _this2.body.emitter.emit("activate");
53618 });
53619 }
53620 } else {
53621 if (this.activator !== undefined) {
53622 this.activator.destroy();
53623 delete this.activator;
53624 }
53625
53626 this.body.emitter.emit("activate");
53627 }
53628 } else {
53629 this.body.emitter.emit("activate");
53630 }
53631
53632 this.canvas.setSize(); // start the physics simulation. Can be safely called multiple times.
53633
53634 this.body.emitter.emit("startSimulation");
53635 }
53636 };
53637 /**
53638 * Update the visible nodes and edges list with the most recent node state.
53639 *
53640 * Visible nodes are stored in this.body.nodeIndices.
53641 * Visible edges are stored in this.body.edgeIndices.
53642 * A node or edges is visible if it is not hidden or clustered.
53643 *
53644 * @private
53645 */
53646
53647
53648 Network.prototype._updateVisibleIndices = function () {
53649 var nodes = this.body.nodes;
53650 var edges = this.body.edges;
53651 this.body.nodeIndices = [];
53652 this.body.edgeIndices = [];
53653
53654 for (var nodeId in nodes) {
53655 if (nodes.hasOwnProperty(nodeId)) {
53656 if (!this.clustering._isClusteredNode(nodeId) && nodes[nodeId].options.hidden === false) {
53657 this.body.nodeIndices.push(nodes[nodeId].id);
53658 }
53659 }
53660 }
53661
53662 for (var edgeId in edges) {
53663 if (edges.hasOwnProperty(edgeId)) {
53664 var edge = edges[edgeId]; // It can happen that this is executed *after* a node edge has been removed,
53665 // but *before* the edge itself has been removed. Taking this into account.
53666
53667 var fromNode = nodes[edge.fromId];
53668 var toNode = nodes[edge.toId];
53669 var edgeNodesPresent = fromNode !== undefined && toNode !== undefined;
53670 var isVisible = !this.clustering._isClusteredEdge(edgeId) && edge.options.hidden === false && edgeNodesPresent && fromNode.options.hidden === false // Also hidden if any of its connecting nodes are hidden
53671 && toNode.options.hidden === false; // idem
53672
53673 if (isVisible) {
53674 this.body.edgeIndices.push(edge.id);
53675 }
53676 }
53677 }
53678 };
53679 /**
53680 * Bind all events
53681 */
53682
53683
53684 Network.prototype.bindEventListeners = function () {
53685 var _this3 = this;
53686
53687 // This event will trigger a rebuilding of the cache everything.
53688 // Used when nodes or edges have been added or removed.
53689 this.body.emitter.on("_dataChanged", function () {
53690 _this3.edgesHandler._updateState();
53691
53692 _this3.body.emitter.emit("_dataUpdated");
53693 }); // this is called when options of EXISTING nodes or edges have changed.
53694
53695 this.body.emitter.on("_dataUpdated", function () {
53696 // Order important in following block
53697 _this3.clustering._updateState();
53698
53699 _this3._updateVisibleIndices();
53700
53701 _this3._updateValueRange(_this3.body.nodes);
53702
53703 _this3._updateValueRange(_this3.body.edges); // start simulation (can be called safely, even if already running)
53704
53705
53706 _this3.body.emitter.emit("startSimulation");
53707
53708 _this3.body.emitter.emit("_requestRedraw");
53709 });
53710 };
53711 /**
53712 * Set nodes and edges, and optionally options as well.
53713 *
53714 * @param {Object} data Object containing parameters:
53715 * {Array | DataSet | DataView} [nodes] Array with nodes
53716 * {Array | DataSet | DataView} [edges] Array with edges
53717 * {String} [dot] String containing data in DOT format
53718 * {String} [gephi] String containing data in gephi JSON format
53719 * {Options} [options] Object with options
53720 */
53721
53722
53723 Network.prototype.setData = function (data) {
53724 // reset the physics engine.
53725 this.body.emitter.emit("resetPhysics");
53726 this.body.emitter.emit("_resetData"); // unselect all to ensure no selections from old data are carried over.
53727
53728 this.selectionHandler.unselectAll();
53729
53730 if (data && data.dot && (data.nodes || data.edges)) {
53731 throw new SyntaxError('Data must contain either parameter "dot" or ' + ' parameter pair "nodes" and "edges", but not both.');
53732 } // set options
53733
53734
53735 this.setOptions(data && data.options); // set all data
53736
53737 if (data && data.dot) {
53738 console.log('The dot property has been deprecated. Please use the static convertDot method to convert DOT into vis.network format and use the normal data format with nodes and edges. This converter is used like this: var data = vis.network.convertDot(dotString);'); // parse DOT file
53739
53740 var dotData = dotparser.DOTToGraph(data.dot);
53741 this.setData(dotData);
53742 return;
53743 } else if (data && data.gephi) {
53744 // parse DOT file
53745 console.log('The gephi property has been deprecated. Please use the static convertGephi method to convert gephi into vis.network format and use the normal data format with nodes and edges. This converter is used like this: var data = vis.network.convertGephi(gephiJson);');
53746 var gephiData = parseGephi(data.gephi);
53747 this.setData(gephiData);
53748 return;
53749 } else {
53750 this.nodesHandler.setData(data && data.nodes, true);
53751 this.edgesHandler.setData(data && data.edges, true);
53752 } // emit change in data
53753
53754
53755 this.body.emitter.emit("_dataChanged"); // emit data loaded
53756
53757 this.body.emitter.emit("_dataLoaded"); // find a stable position or start animating to a stable position
53758
53759 this.body.emitter.emit("initPhysics");
53760 };
53761 /**
53762 * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function.
53763 * var network = new vis.Network(..);
53764 * network.destroy();
53765 * network = null;
53766 */
53767
53768
53769 Network.prototype.destroy = function () {
53770 this.body.emitter.emit("destroy"); // clear events
53771
53772 this.body.emitter.off();
53773 this.off(); // delete modules
53774
53775 delete this.groups;
53776 delete this.canvas;
53777 delete this.selectionHandler;
53778 delete this.interactionHandler;
53779 delete this.view;
53780 delete this.renderer;
53781 delete this.physics;
53782 delete this.layoutEngine;
53783 delete this.clustering;
53784 delete this.manipulation;
53785 delete this.nodesHandler;
53786 delete this.edgesHandler;
53787 delete this.configurator;
53788 delete this.images;
53789
53790 for (var nodeId in this.body.nodes) {
53791 if (!this.body.nodes.hasOwnProperty(nodeId)) continue;
53792 delete this.body.nodes[nodeId];
53793 }
53794
53795 for (var edgeId in this.body.edges) {
53796 if (!this.body.edges.hasOwnProperty(edgeId)) continue;
53797 delete this.body.edges[edgeId];
53798 } // remove the container and everything inside it recursively
53799
53800
53801 recursiveDOMDelete(this.body.container);
53802 };
53803 /**
53804 * Update the values of all object in the given array according to the current
53805 * value range of the objects in the array.
53806 * @param {Object} obj An object containing a set of Edges or Nodes
53807 * The objects must have a method getValue() and
53808 * setValueRange(min, max).
53809 * @private
53810 */
53811
53812
53813 Network.prototype._updateValueRange = function (obj) {
53814 var id; // determine the range of the objects
53815
53816 var valueMin = undefined;
53817 var valueMax = undefined;
53818 var valueTotal = 0;
53819
53820 for (id in obj) {
53821 if (obj.hasOwnProperty(id)) {
53822 var value = obj[id].getValue();
53823
53824 if (value !== undefined) {
53825 valueMin = valueMin === undefined ? value : Math.min(value, valueMin);
53826 valueMax = valueMax === undefined ? value : Math.max(value, valueMax);
53827 valueTotal += value;
53828 }
53829 }
53830 } // adjust the range of all objects
53831
53832
53833 if (valueMin !== undefined && valueMax !== undefined) {
53834 for (id in obj) {
53835 if (obj.hasOwnProperty(id)) {
53836 obj[id].setValueRange(valueMin, valueMax, valueTotal);
53837 }
53838 }
53839 }
53840 };
53841 /**
53842 * Returns true when the Network is active.
53843 * @returns {boolean}
53844 */
53845
53846
53847 Network.prototype.isActive = function () {
53848 return !this.activator || this.activator.active;
53849 };
53850
53851 Network.prototype.setSize = function () {
53852 return this.canvas.setSize.apply(this.canvas, arguments);
53853 };
53854
53855 Network.prototype.canvasToDOM = function () {
53856 return this.canvas.canvasToDOM.apply(this.canvas, arguments);
53857 };
53858
53859 Network.prototype.DOMtoCanvas = function () {
53860 return this.canvas.DOMtoCanvas.apply(this.canvas, arguments);
53861 };
53862 /**
53863 * Nodes can be in clusters. Clusters can also be in clusters. This function returns and array of
53864 * nodeIds showing where the node is.
53865 *
53866 * If any nodeId in the chain, especially the first passed in as a parameter, is not present in
53867 * the current nodes list, an empty array is returned.
53868 *
53869 * Example:
53870 * cluster 'A' contains cluster 'B',
53871 * cluster 'B' contains cluster 'C',
53872 * cluster 'C' contains node 'fred'.
53873 * `jsnetwork.clustering.findNode('fred')` will return `['A','B','C','fred']`.
53874 *
53875 * @param {string|number} nodeId
53876 * @returns {Array}
53877 */
53878
53879
53880 Network.prototype.findNode = function () {
53881 return this.clustering.findNode.apply(this.clustering, arguments);
53882 };
53883
53884 Network.prototype.isCluster = function () {
53885 return this.clustering.isCluster.apply(this.clustering, arguments);
53886 };
53887
53888 Network.prototype.openCluster = function () {
53889 return this.clustering.openCluster.apply(this.clustering, arguments);
53890 };
53891
53892 Network.prototype.cluster = function () {
53893 return this.clustering.cluster.apply(this.clustering, arguments);
53894 };
53895
53896 Network.prototype.getNodesInCluster = function () {
53897 return this.clustering.getNodesInCluster.apply(this.clustering, arguments);
53898 };
53899
53900 Network.prototype.clusterByConnection = function () {
53901 return this.clustering.clusterByConnection.apply(this.clustering, arguments);
53902 };
53903
53904 Network.prototype.clusterByHubsize = function () {
53905 return this.clustering.clusterByHubsize.apply(this.clustering, arguments);
53906 };
53907 /**
53908 * This method will cluster all nodes with 1 edge with their respective connected node.
53909 * The options object is explained in full <a data-scroll="" data-options="{ &quot;easing&quot;: &quot;easeInCubic&quot; }" href="#optionsObject">below</a>.
53910 *
53911 * @param {object} [options]
53912 * @returns {undefined}
53913 */
53914
53915
53916 Network.prototype.clusterOutliers = function () {
53917 return this.clustering.clusterOutliers.apply(this.clustering, arguments);
53918 };
53919
53920 Network.prototype.getSeed = function () {
53921 return this.layoutEngine.getSeed.apply(this.layoutEngine, arguments);
53922 };
53923
53924 Network.prototype.enableEditMode = function () {
53925 return this.manipulation.enableEditMode.apply(this.manipulation, arguments);
53926 };
53927
53928 Network.prototype.disableEditMode = function () {
53929 return this.manipulation.disableEditMode.apply(this.manipulation, arguments);
53930 };
53931
53932 Network.prototype.addNodeMode = function () {
53933 return this.manipulation.addNodeMode.apply(this.manipulation, arguments);
53934 };
53935
53936 Network.prototype.editNode = function () {
53937 return this.manipulation.editNode.apply(this.manipulation, arguments);
53938 };
53939
53940 Network.prototype.editNodeMode = function () {
53941 console.log("Deprecated: Please use editNode instead of editNodeMode.");
53942 return this.manipulation.editNode.apply(this.manipulation, arguments);
53943 };
53944
53945 Network.prototype.addEdgeMode = function () {
53946 return this.manipulation.addEdgeMode.apply(this.manipulation, arguments);
53947 };
53948
53949 Network.prototype.editEdgeMode = function () {
53950 return this.manipulation.editEdgeMode.apply(this.manipulation, arguments);
53951 };
53952
53953 Network.prototype.deleteSelected = function () {
53954 return this.manipulation.deleteSelected.apply(this.manipulation, arguments);
53955 };
53956
53957 Network.prototype.getPositions = function () {
53958 return this.nodesHandler.getPositions.apply(this.nodesHandler, arguments);
53959 };
53960
53961 Network.prototype.storePositions = function () {
53962 return this.nodesHandler.storePositions.apply(this.nodesHandler, arguments);
53963 };
53964
53965 Network.prototype.moveNode = function () {
53966 return this.nodesHandler.moveNode.apply(this.nodesHandler, arguments);
53967 };
53968
53969 Network.prototype.getBoundingBox = function () {
53970 return this.nodesHandler.getBoundingBox.apply(this.nodesHandler, arguments);
53971 };
53972
53973 Network.prototype.getConnectedNodes = function (objectId) {
53974 if (this.body.nodes[objectId] !== undefined) {
53975 return this.nodesHandler.getConnectedNodes.apply(this.nodesHandler, arguments);
53976 } else {
53977 return this.edgesHandler.getConnectedNodes.apply(this.edgesHandler, arguments);
53978 }
53979 };
53980
53981 Network.prototype.getConnectedEdges = function () {
53982 return this.nodesHandler.getConnectedEdges.apply(this.nodesHandler, arguments);
53983 };
53984
53985 Network.prototype.startSimulation = function () {
53986 return this.physics.startSimulation.apply(this.physics, arguments);
53987 };
53988
53989 Network.prototype.stopSimulation = function () {
53990 return this.physics.stopSimulation.apply(this.physics, arguments);
53991 };
53992
53993 Network.prototype.stabilize = function () {
53994 return this.physics.stabilize.apply(this.physics, arguments);
53995 };
53996
53997 Network.prototype.getSelection = function () {
53998 return this.selectionHandler.getSelection.apply(this.selectionHandler, arguments);
53999 };
54000
54001 Network.prototype.setSelection = function () {
54002 return this.selectionHandler.setSelection.apply(this.selectionHandler, arguments);
54003 };
54004
54005 Network.prototype.getSelectedNodes = function () {
54006 return this.selectionHandler.getSelectedNodes.apply(this.selectionHandler, arguments);
54007 };
54008
54009 Network.prototype.getSelectedEdges = function () {
54010 return this.selectionHandler.getSelectedEdges.apply(this.selectionHandler, arguments);
54011 };
54012
54013 Network.prototype.getNodeAt = function () {
54014 var node = this.selectionHandler.getNodeAt.apply(this.selectionHandler, arguments);
54015
54016 if (node !== undefined && node.id !== undefined) {
54017 return node.id;
54018 }
54019
54020 return node;
54021 };
54022
54023 Network.prototype.getEdgeAt = function () {
54024 var edge = this.selectionHandler.getEdgeAt.apply(this.selectionHandler, arguments);
54025
54026 if (edge !== undefined && edge.id !== undefined) {
54027 return edge.id;
54028 }
54029
54030 return edge;
54031 };
54032
54033 Network.prototype.selectNodes = function () {
54034 return this.selectionHandler.selectNodes.apply(this.selectionHandler, arguments);
54035 };
54036
54037 Network.prototype.selectEdges = function () {
54038 return this.selectionHandler.selectEdges.apply(this.selectionHandler, arguments);
54039 };
54040
54041 Network.prototype.unselectAll = function () {
54042 this.selectionHandler.unselectAll.apply(this.selectionHandler, arguments);
54043 this.redraw();
54044 };
54045
54046 Network.prototype.redraw = function () {
54047 return this.renderer.redraw.apply(this.renderer, arguments);
54048 };
54049
54050 Network.prototype.getScale = function () {
54051 return this.view.getScale.apply(this.view, arguments);
54052 };
54053
54054 Network.prototype.getViewPosition = function () {
54055 return this.view.getViewPosition.apply(this.view, arguments);
54056 };
54057
54058 Network.prototype.fit = function () {
54059 return this.view.fit.apply(this.view, arguments);
54060 };
54061
54062 Network.prototype.moveTo = function () {
54063 return this.view.moveTo.apply(this.view, arguments);
54064 };
54065
54066 Network.prototype.focus = function () {
54067 return this.view.focus.apply(this.view, arguments);
54068 };
54069
54070 Network.prototype.releaseNode = function () {
54071 return this.view.releaseNode.apply(this.view, arguments);
54072 };
54073
54074 Network.prototype.getOptionsFromConfigurator = function () {
54075 var options = {};
54076
54077 if (this.configurator) {
54078 options = this.configurator.getOptions.apply(this.configurator);
54079 }
54080
54081 return options;
54082 };
54083
54084 var DOMutil = createCommonjsModule(function (module, exports) {
54085 // DOM utility methods
54086
54087 /**
54088 * this prepares the JSON container for allocating SVG elements
54089 * @param {Object} JSONcontainer
54090 * @private
54091 */
54092 exports.prepareElements = function (JSONcontainer) {
54093 // cleanup the redundant svgElements;
54094 for (var elementType in JSONcontainer) {
54095 if (JSONcontainer.hasOwnProperty(elementType)) {
54096 JSONcontainer[elementType].redundant = JSONcontainer[elementType].used;
54097 JSONcontainer[elementType].used = [];
54098 }
54099 }
54100 };
54101 /**
54102 * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from
54103 * which to remove the redundant elements.
54104 *
54105 * @param {Object} JSONcontainer
54106 * @private
54107 */
54108
54109
54110 exports.cleanupElements = function (JSONcontainer) {
54111 // cleanup the redundant svgElements;
54112 for (var elementType in JSONcontainer) {
54113 if (JSONcontainer.hasOwnProperty(elementType)) {
54114 if (JSONcontainer[elementType].redundant) {
54115 for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) {
54116 JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]);
54117 }
54118
54119 JSONcontainer[elementType].redundant = [];
54120 }
54121 }
54122 }
54123 };
54124 /**
54125 * Ensures that all elements are removed first up so they can be recreated cleanly
54126 * @param {Object} JSONcontainer
54127 */
54128
54129
54130 exports.resetElements = function (JSONcontainer) {
54131 exports.prepareElements(JSONcontainer);
54132 exports.cleanupElements(JSONcontainer);
54133 exports.prepareElements(JSONcontainer);
54134 };
54135 /**
54136 * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
54137 * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
54138 *
54139 * @param {string} elementType
54140 * @param {Object} JSONcontainer
54141 * @param {Object} svgContainer
54142 * @returns {Element}
54143 * @private
54144 */
54145
54146
54147 exports.getSVGElement = function (elementType, JSONcontainer, svgContainer) {
54148 var element; // allocate SVG element, if it doesnt yet exist, create one.
54149
54150 if (JSONcontainer.hasOwnProperty(elementType)) {
54151 // this element has been created before
54152 // check if there is an redundant element
54153 if (JSONcontainer[elementType].redundant.length > 0) {
54154 element = JSONcontainer[elementType].redundant[0];
54155 JSONcontainer[elementType].redundant.shift();
54156 } else {
54157 // create a new element and add it to the SVG
54158 element = document.createElementNS('http://www.w3.org/2000/svg', elementType);
54159 svgContainer.appendChild(element);
54160 }
54161 } else {
54162 // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
54163 element = document.createElementNS('http://www.w3.org/2000/svg', elementType);
54164 JSONcontainer[elementType] = {
54165 used: [],
54166 redundant: []
54167 };
54168 svgContainer.appendChild(element);
54169 }
54170
54171 JSONcontainer[elementType].used.push(element);
54172 return element;
54173 };
54174 /**
54175 * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
54176 * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
54177 *
54178 * @param {string} elementType
54179 * @param {Object} JSONcontainer
54180 * @param {Element} DOMContainer
54181 * @param {Element} insertBefore
54182 * @returns {*}
54183 */
54184
54185
54186 exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer, insertBefore) {
54187 var element; // allocate DOM element, if it doesnt yet exist, create one.
54188
54189 if (JSONcontainer.hasOwnProperty(elementType)) {
54190 // this element has been created before
54191 // check if there is an redundant element
54192 if (JSONcontainer[elementType].redundant.length > 0) {
54193 element = JSONcontainer[elementType].redundant[0];
54194 JSONcontainer[elementType].redundant.shift();
54195 } else {
54196 // create a new element and add it to the SVG
54197 element = document.createElement(elementType);
54198
54199 if (insertBefore !== undefined) {
54200 DOMContainer.insertBefore(element, insertBefore);
54201 } else {
54202 DOMContainer.appendChild(element);
54203 }
54204 }
54205 } else {
54206 // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
54207 element = document.createElement(elementType);
54208 JSONcontainer[elementType] = {
54209 used: [],
54210 redundant: []
54211 };
54212
54213 if (insertBefore !== undefined) {
54214 DOMContainer.insertBefore(element, insertBefore);
54215 } else {
54216 DOMContainer.appendChild(element);
54217 }
54218 }
54219
54220 JSONcontainer[elementType].used.push(element);
54221 return element;
54222 };
54223 /**
54224 * Draw a point object. This is a separate function because it can also be called by the legend.
54225 * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions
54226 * as well.
54227 *
54228 * @param {number} x
54229 * @param {number} y
54230 * @param {Object} groupTemplate: A template containing the necessary information to draw the datapoint e.g., {style: 'circle', size: 5, className: 'className' }
54231 * @param {Object} JSONcontainer
54232 * @param {Object} svgContainer
54233 * @param {Object} labelObj
54234 * @returns {vis.PointItem}
54235 */
54236
54237
54238 exports.drawPoint = function (x, y, groupTemplate, JSONcontainer, svgContainer, labelObj) {
54239 var point;
54240
54241 if (groupTemplate.style == 'circle') {
54242 point = exports.getSVGElement('circle', JSONcontainer, svgContainer);
54243 point.setAttributeNS(null, "cx", x);
54244 point.setAttributeNS(null, "cy", y);
54245 point.setAttributeNS(null, "r", 0.5 * groupTemplate.size);
54246 } else {
54247 point = exports.getSVGElement('rect', JSONcontainer, svgContainer);
54248 point.setAttributeNS(null, "x", x - 0.5 * groupTemplate.size);
54249 point.setAttributeNS(null, "y", y - 0.5 * groupTemplate.size);
54250 point.setAttributeNS(null, "width", groupTemplate.size);
54251 point.setAttributeNS(null, "height", groupTemplate.size);
54252 }
54253
54254 if (groupTemplate.styles !== undefined) {
54255 point.setAttributeNS(null, "style", groupTemplate.styles);
54256 }
54257
54258 point.setAttributeNS(null, "class", groupTemplate.className + " vis-point"); //handle label
54259
54260 if (labelObj) {
54261 var label = exports.getSVGElement('text', JSONcontainer, svgContainer);
54262
54263 if (labelObj.xOffset) {
54264 x = x + labelObj.xOffset;
54265 }
54266
54267 if (labelObj.yOffset) {
54268 y = y + labelObj.yOffset;
54269 }
54270
54271 if (labelObj.content) {
54272 label.textContent = labelObj.content;
54273 }
54274
54275 if (labelObj.className) {
54276 label.setAttributeNS(null, "class", labelObj.className + " vis-label");
54277 }
54278
54279 label.setAttributeNS(null, "x", x);
54280 label.setAttributeNS(null, "y", y);
54281 }
54282
54283 return point;
54284 };
54285 /**
54286 * draw a bar SVG element centered on the X coordinate
54287 *
54288 * @param {number} x
54289 * @param {number} y
54290 * @param {number} width
54291 * @param {number} height
54292 * @param {string} className
54293 * @param {Object} JSONcontainer
54294 * @param {Object} svgContainer
54295 * @param {string} style
54296 */
54297
54298
54299 exports.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer, style) {
54300 if (height != 0) {
54301 if (height < 0) {
54302 height *= -1;
54303 y -= height;
54304 }
54305
54306 var rect = exports.getSVGElement('rect', JSONcontainer, svgContainer);
54307 rect.setAttributeNS(null, "x", x - 0.5 * width);
54308 rect.setAttributeNS(null, "y", y);
54309 rect.setAttributeNS(null, "width", width);
54310 rect.setAttributeNS(null, "height", height);
54311 rect.setAttributeNS(null, "class", className);
54312
54313 if (style) {
54314 rect.setAttributeNS(null, "style", style);
54315 }
54316 }
54317 };
54318 });
54319 var DOMutil_1 = DOMutil.prepareElements;
54320 var DOMutil_2 = DOMutil.cleanupElements;
54321 var DOMutil_3 = DOMutil.resetElements;
54322 var DOMutil_4 = DOMutil.getSVGElement;
54323 var DOMutil_5 = DOMutil.getDOMElement;
54324 var DOMutil_6 = DOMutil.drawPoint;
54325 var DOMutil_7 = DOMutil.drawBar;
54326
54327 var DOMutil$1 = /*#__PURE__*/Object.freeze({
54328 __proto__: null,
54329 'default': DOMutil,
54330 __moduleExports: DOMutil,
54331 prepareElements: DOMutil_1,
54332 cleanupElements: DOMutil_2,
54333 resetElements: DOMutil_3,
54334 getSVGElement: DOMutil_4,
54335 getDOMElement: DOMutil_5,
54336 drawPoint: DOMutil_6,
54337 drawBar: DOMutil_7
54338 });
54339
54340 var moment$2 = createCommonjsModule(function (module, exports) {
54341
54342 (function (global, factory) {
54343 module.exports = factory() ;
54344 })(commonjsGlobal, function () {
54345
54346 var hookCallback;
54347
54348 function hooks() {
54349 return hookCallback.apply(null, arguments);
54350 } // This is done to register the method called with moment()
54351 // without creating circular dependencies.
54352
54353
54354 function setHookCallback(callback) {
54355 hookCallback = callback;
54356 }
54357
54358 function isArray(input) {
54359 return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
54360 }
54361
54362 function isObject(input) {
54363 // IE8 will treat undefined and null as object if it wasn't for
54364 // input != null
54365 return input != null && Object.prototype.toString.call(input) === '[object Object]';
54366 }
54367
54368 function isObjectEmpty(obj) {
54369 if (Object.getOwnPropertyNames) {
54370 return Object.getOwnPropertyNames(obj).length === 0;
54371 } else {
54372 var k;
54373
54374 for (k in obj) {
54375 if (obj.hasOwnProperty(k)) {
54376 return false;
54377 }
54378 }
54379
54380 return true;
54381 }
54382 }
54383
54384 function isUndefined(input) {
54385 return input === void 0;
54386 }
54387
54388 function isNumber(input) {
54389 return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
54390 }
54391
54392 function isDate(input) {
54393 return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
54394 }
54395
54396 function map(arr, fn) {
54397 var res = [],
54398 i;
54399
54400 for (i = 0; i < arr.length; ++i) {
54401 res.push(fn(arr[i], i));
54402 }
54403
54404 return res;
54405 }
54406
54407 function hasOwnProp(a, b) {
54408 return Object.prototype.hasOwnProperty.call(a, b);
54409 }
54410
54411 function extend(a, b) {
54412 for (var i in b) {
54413 if (hasOwnProp(b, i)) {
54414 a[i] = b[i];
54415 }
54416 }
54417
54418 if (hasOwnProp(b, 'toString')) {
54419 a.toString = b.toString;
54420 }
54421
54422 if (hasOwnProp(b, 'valueOf')) {
54423 a.valueOf = b.valueOf;
54424 }
54425
54426 return a;
54427 }
54428
54429 function createUTC(input, format, locale, strict) {
54430 return createLocalOrUTC(input, format, locale, strict, true).utc();
54431 }
54432
54433 function defaultParsingFlags() {
54434 // We need to deep clone this object.
54435 return {
54436 empty: false,
54437 unusedTokens: [],
54438 unusedInput: [],
54439 overflow: -2,
54440 charsLeftOver: 0,
54441 nullInput: false,
54442 invalidMonth: null,
54443 invalidFormat: false,
54444 userInvalidated: false,
54445 iso: false,
54446 parsedDateParts: [],
54447 meridiem: null,
54448 rfc2822: false,
54449 weekdayMismatch: false
54450 };
54451 }
54452
54453 function getParsingFlags(m) {
54454 if (m._pf == null) {
54455 m._pf = defaultParsingFlags();
54456 }
54457
54458 return m._pf;
54459 }
54460
54461 var some;
54462
54463 if (Array.prototype.some) {
54464 some = Array.prototype.some;
54465 } else {
54466 some = function (fun) {
54467 var t = Object(this);
54468 var len = t.length >>> 0;
54469
54470 for (var i = 0; i < len; i++) {
54471 if (i in t && fun.call(this, t[i], i, t)) {
54472 return true;
54473 }
54474 }
54475
54476 return false;
54477 };
54478 }
54479
54480 function isValid(m) {
54481 if (m._isValid == null) {
54482 var flags = getParsingFlags(m);
54483 var parsedParts = some.call(flags.parsedDateParts, function (i) {
54484 return i != null;
54485 });
54486 var isNowValid = !isNaN(m._d.getTime()) && flags.overflow < 0 && !flags.empty && !flags.invalidMonth && !flags.invalidWeekday && !flags.weekdayMismatch && !flags.nullInput && !flags.invalidFormat && !flags.userInvalidated && (!flags.meridiem || flags.meridiem && parsedParts);
54487
54488 if (m._strict) {
54489 isNowValid = isNowValid && flags.charsLeftOver === 0 && flags.unusedTokens.length === 0 && flags.bigHour === undefined;
54490 }
54491
54492 if (Object.isFrozen == null || !Object.isFrozen(m)) {
54493 m._isValid = isNowValid;
54494 } else {
54495 return isNowValid;
54496 }
54497 }
54498
54499 return m._isValid;
54500 }
54501
54502 function createInvalid(flags) {
54503 var m = createUTC(NaN);
54504
54505 if (flags != null) {
54506 extend(getParsingFlags(m), flags);
54507 } else {
54508 getParsingFlags(m).userInvalidated = true;
54509 }
54510
54511 return m;
54512 } // Plugins that add properties should also add the key here (null value),
54513 // so we can properly clone ourselves.
54514
54515
54516 var momentProperties = hooks.momentProperties = [];
54517
54518 function copyConfig(to, from) {
54519 var i, prop, val;
54520
54521 if (!isUndefined(from._isAMomentObject)) {
54522 to._isAMomentObject = from._isAMomentObject;
54523 }
54524
54525 if (!isUndefined(from._i)) {
54526 to._i = from._i;
54527 }
54528
54529 if (!isUndefined(from._f)) {
54530 to._f = from._f;
54531 }
54532
54533 if (!isUndefined(from._l)) {
54534 to._l = from._l;
54535 }
54536
54537 if (!isUndefined(from._strict)) {
54538 to._strict = from._strict;
54539 }
54540
54541 if (!isUndefined(from._tzm)) {
54542 to._tzm = from._tzm;
54543 }
54544
54545 if (!isUndefined(from._isUTC)) {
54546 to._isUTC = from._isUTC;
54547 }
54548
54549 if (!isUndefined(from._offset)) {
54550 to._offset = from._offset;
54551 }
54552
54553 if (!isUndefined(from._pf)) {
54554 to._pf = getParsingFlags(from);
54555 }
54556
54557 if (!isUndefined(from._locale)) {
54558 to._locale = from._locale;
54559 }
54560
54561 if (momentProperties.length > 0) {
54562 for (i = 0; i < momentProperties.length; i++) {
54563 prop = momentProperties[i];
54564 val = from[prop];
54565
54566 if (!isUndefined(val)) {
54567 to[prop] = val;
54568 }
54569 }
54570 }
54571
54572 return to;
54573 }
54574
54575 var updateInProgress = false; // Moment prototype object
54576
54577 function Moment(config) {
54578 copyConfig(this, config);
54579 this._d = new Date(config._d != null ? config._d.getTime() : NaN);
54580
54581 if (!this.isValid()) {
54582 this._d = new Date(NaN);
54583 } // Prevent infinite loop in case updateOffset creates new moment
54584 // objects.
54585
54586
54587 if (updateInProgress === false) {
54588 updateInProgress = true;
54589 hooks.updateOffset(this);
54590 updateInProgress = false;
54591 }
54592 }
54593
54594 function isMoment(obj) {
54595 return obj instanceof Moment || obj != null && obj._isAMomentObject != null;
54596 }
54597
54598 function absFloor(number) {
54599 if (number < 0) {
54600 // -0 -> 0
54601 return Math.ceil(number) || 0;
54602 } else {
54603 return Math.floor(number);
54604 }
54605 }
54606
54607 function toInt(argumentForCoercion) {
54608 var coercedNumber = +argumentForCoercion,
54609 value = 0;
54610
54611 if (coercedNumber !== 0 && isFinite(coercedNumber)) {
54612 value = absFloor(coercedNumber);
54613 }
54614
54615 return value;
54616 } // compare two arrays, return the number of differences
54617
54618
54619 function compareArrays(array1, array2, dontConvert) {
54620 var len = Math.min(array1.length, array2.length),
54621 lengthDiff = Math.abs(array1.length - array2.length),
54622 diffs = 0,
54623 i;
54624
54625 for (i = 0; i < len; i++) {
54626 if (dontConvert && array1[i] !== array2[i] || !dontConvert && toInt(array1[i]) !== toInt(array2[i])) {
54627 diffs++;
54628 }
54629 }
54630
54631 return diffs + lengthDiff;
54632 }
54633
54634 function warn(msg) {
54635 if (hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) {
54636 console.warn('Deprecation warning: ' + msg);
54637 }
54638 }
54639
54640 function deprecate(msg, fn) {
54641 var firstTime = true;
54642 return extend(function () {
54643 if (hooks.deprecationHandler != null) {
54644 hooks.deprecationHandler(null, msg);
54645 }
54646
54647 if (firstTime) {
54648 var args = [];
54649 var arg;
54650
54651 for (var i = 0; i < arguments.length; i++) {
54652 arg = '';
54653
54654 if (typeof arguments[i] === 'object') {
54655 arg += '\n[' + i + '] ';
54656
54657 for (var key in arguments[0]) {
54658 arg += key + ': ' + arguments[0][key] + ', ';
54659 }
54660
54661 arg = arg.slice(0, -2); // Remove trailing comma and space
54662 } else {
54663 arg = arguments[i];
54664 }
54665
54666 args.push(arg);
54667 }
54668
54669 warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + new Error().stack);
54670 firstTime = false;
54671 }
54672
54673 return fn.apply(this, arguments);
54674 }, fn);
54675 }
54676
54677 var deprecations = {};
54678
54679 function deprecateSimple(name, msg) {
54680 if (hooks.deprecationHandler != null) {
54681 hooks.deprecationHandler(name, msg);
54682 }
54683
54684 if (!deprecations[name]) {
54685 warn(msg);
54686 deprecations[name] = true;
54687 }
54688 }
54689
54690 hooks.suppressDeprecationWarnings = false;
54691 hooks.deprecationHandler = null;
54692
54693 function isFunction(input) {
54694 return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
54695 }
54696
54697 function set(config) {
54698 var prop, i;
54699
54700 for (i in config) {
54701 prop = config[i];
54702
54703 if (isFunction(prop)) {
54704 this[i] = prop;
54705 } else {
54706 this['_' + i] = prop;
54707 }
54708 }
54709
54710 this._config = config; // Lenient ordinal parsing accepts just a number in addition to
54711 // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
54712 // TODO: Remove "ordinalParse" fallback in next major release.
54713
54714 this._dayOfMonthOrdinalParseLenient = new RegExp((this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + '|' + /\d{1,2}/.source);
54715 }
54716
54717 function mergeConfigs(parentConfig, childConfig) {
54718 var res = extend({}, parentConfig),
54719 prop;
54720
54721 for (prop in childConfig) {
54722 if (hasOwnProp(childConfig, prop)) {
54723 if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
54724 res[prop] = {};
54725 extend(res[prop], parentConfig[prop]);
54726 extend(res[prop], childConfig[prop]);
54727 } else if (childConfig[prop] != null) {
54728 res[prop] = childConfig[prop];
54729 } else {
54730 delete res[prop];
54731 }
54732 }
54733 }
54734
54735 for (prop in parentConfig) {
54736 if (hasOwnProp(parentConfig, prop) && !hasOwnProp(childConfig, prop) && isObject(parentConfig[prop])) {
54737 // make sure changes to properties don't modify parent config
54738 res[prop] = extend({}, res[prop]);
54739 }
54740 }
54741
54742 return res;
54743 }
54744
54745 function Locale(config) {
54746 if (config != null) {
54747 this.set(config);
54748 }
54749 }
54750
54751 var keys;
54752
54753 if (Object.keys) {
54754 keys = Object.keys;
54755 } else {
54756 keys = function (obj) {
54757 var i,
54758 res = [];
54759
54760 for (i in obj) {
54761 if (hasOwnProp(obj, i)) {
54762 res.push(i);
54763 }
54764 }
54765
54766 return res;
54767 };
54768 }
54769
54770 var defaultCalendar = {
54771 sameDay: '[Today at] LT',
54772 nextDay: '[Tomorrow at] LT',
54773 nextWeek: 'dddd [at] LT',
54774 lastDay: '[Yesterday at] LT',
54775 lastWeek: '[Last] dddd [at] LT',
54776 sameElse: 'L'
54777 };
54778
54779 function calendar(key, mom, now) {
54780 var output = this._calendar[key] || this._calendar['sameElse'];
54781 return isFunction(output) ? output.call(mom, now) : output;
54782 }
54783
54784 var defaultLongDateFormat = {
54785 LTS: 'h:mm:ss A',
54786 LT: 'h:mm A',
54787 L: 'MM/DD/YYYY',
54788 LL: 'MMMM D, YYYY',
54789 LLL: 'MMMM D, YYYY h:mm A',
54790 LLLL: 'dddd, MMMM D, YYYY h:mm A'
54791 };
54792
54793 function longDateFormat(key) {
54794 var format = this._longDateFormat[key],
54795 formatUpper = this._longDateFormat[key.toUpperCase()];
54796
54797 if (format || !formatUpper) {
54798 return format;
54799 }
54800
54801 this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
54802 return val.slice(1);
54803 });
54804 return this._longDateFormat[key];
54805 }
54806
54807 var defaultInvalidDate = 'Invalid date';
54808
54809 function invalidDate() {
54810 return this._invalidDate;
54811 }
54812
54813 var defaultOrdinal = '%d';
54814 var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
54815
54816 function ordinal(number) {
54817 return this._ordinal.replace('%d', number);
54818 }
54819
54820 var defaultRelativeTime = {
54821 future: 'in %s',
54822 past: '%s ago',
54823 s: 'a few seconds',
54824 ss: '%d seconds',
54825 m: 'a minute',
54826 mm: '%d minutes',
54827 h: 'an hour',
54828 hh: '%d hours',
54829 d: 'a day',
54830 dd: '%d days',
54831 M: 'a month',
54832 MM: '%d months',
54833 y: 'a year',
54834 yy: '%d years'
54835 };
54836
54837 function relativeTime(number, withoutSuffix, string, isFuture) {
54838 var output = this._relativeTime[string];
54839 return isFunction(output) ? output(number, withoutSuffix, string, isFuture) : output.replace(/%d/i, number);
54840 }
54841
54842 function pastFuture(diff, output) {
54843 var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
54844 return isFunction(format) ? format(output) : format.replace(/%s/i, output);
54845 }
54846
54847 var aliases = {};
54848
54849 function addUnitAlias(unit, shorthand) {
54850 var lowerCase = unit.toLowerCase();
54851 aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
54852 }
54853
54854 function normalizeUnits(units) {
54855 return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
54856 }
54857
54858 function normalizeObjectUnits(inputObject) {
54859 var normalizedInput = {},
54860 normalizedProp,
54861 prop;
54862
54863 for (prop in inputObject) {
54864 if (hasOwnProp(inputObject, prop)) {
54865 normalizedProp = normalizeUnits(prop);
54866
54867 if (normalizedProp) {
54868 normalizedInput[normalizedProp] = inputObject[prop];
54869 }
54870 }
54871 }
54872
54873 return normalizedInput;
54874 }
54875
54876 var priorities = {};
54877
54878 function addUnitPriority(unit, priority) {
54879 priorities[unit] = priority;
54880 }
54881
54882 function getPrioritizedUnits(unitsObj) {
54883 var units = [];
54884
54885 for (var u in unitsObj) {
54886 units.push({
54887 unit: u,
54888 priority: priorities[u]
54889 });
54890 }
54891
54892 units.sort(function (a, b) {
54893 return a.priority - b.priority;
54894 });
54895 return units;
54896 }
54897
54898 function zeroFill(number, targetLength, forceSign) {
54899 var absNumber = '' + Math.abs(number),
54900 zerosToFill = targetLength - absNumber.length,
54901 sign = number >= 0;
54902 return (sign ? forceSign ? '+' : '' : '-') + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
54903 }
54904
54905 var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
54906 var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
54907 var formatFunctions = {};
54908 var formatTokenFunctions = {}; // token: 'M'
54909 // padded: ['MM', 2]
54910 // ordinal: 'Mo'
54911 // callback: function () { this.month() + 1 }
54912
54913 function addFormatToken(token, padded, ordinal, callback) {
54914 var func = callback;
54915
54916 if (typeof callback === 'string') {
54917 func = function () {
54918 return this[callback]();
54919 };
54920 }
54921
54922 if (token) {
54923 formatTokenFunctions[token] = func;
54924 }
54925
54926 if (padded) {
54927 formatTokenFunctions[padded[0]] = function () {
54928 return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
54929 };
54930 }
54931
54932 if (ordinal) {
54933 formatTokenFunctions[ordinal] = function () {
54934 return this.localeData().ordinal(func.apply(this, arguments), token);
54935 };
54936 }
54937 }
54938
54939 function removeFormattingTokens(input) {
54940 if (input.match(/\[[\s\S]/)) {
54941 return input.replace(/^\[|\]$/g, '');
54942 }
54943
54944 return input.replace(/\\/g, '');
54945 }
54946
54947 function makeFormatFunction(format) {
54948 var array = format.match(formattingTokens),
54949 i,
54950 length;
54951
54952 for (i = 0, length = array.length; i < length; i++) {
54953 if (formatTokenFunctions[array[i]]) {
54954 array[i] = formatTokenFunctions[array[i]];
54955 } else {
54956 array[i] = removeFormattingTokens(array[i]);
54957 }
54958 }
54959
54960 return function (mom) {
54961 var output = '',
54962 i;
54963
54964 for (i = 0; i < length; i++) {
54965 output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
54966 }
54967
54968 return output;
54969 };
54970 } // format date using native date object
54971
54972
54973 function formatMoment(m, format) {
54974 if (!m.isValid()) {
54975 return m.localeData().invalidDate();
54976 }
54977
54978 format = expandFormat(format, m.localeData());
54979 formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
54980 return formatFunctions[format](m);
54981 }
54982
54983 function expandFormat(format, locale) {
54984 var i = 5;
54985
54986 function replaceLongDateFormatTokens(input) {
54987 return locale.longDateFormat(input) || input;
54988 }
54989
54990 localFormattingTokens.lastIndex = 0;
54991
54992 while (i >= 0 && localFormattingTokens.test(format)) {
54993 format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
54994 localFormattingTokens.lastIndex = 0;
54995 i -= 1;
54996 }
54997
54998 return format;
54999 }
55000
55001 var match1 = /\d/; // 0 - 9
55002
55003 var match2 = /\d\d/; // 00 - 99
55004
55005 var match3 = /\d{3}/; // 000 - 999
55006
55007 var match4 = /\d{4}/; // 0000 - 9999
55008
55009 var match6 = /[+-]?\d{6}/; // -999999 - 999999
55010
55011 var match1to2 = /\d\d?/; // 0 - 99
55012
55013 var match3to4 = /\d\d\d\d?/; // 999 - 9999
55014
55015 var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
55016
55017 var match1to3 = /\d{1,3}/; // 0 - 999
55018
55019 var match1to4 = /\d{1,4}/; // 0 - 9999
55020
55021 var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
55022
55023 var matchUnsigned = /\d+/; // 0 - inf
55024
55025 var matchSigned = /[+-]?\d+/; // -inf - inf
55026
55027 var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
55028
55029 var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
55030
55031 var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
55032 // any word (or two) characters or numbers including two/three word month in arabic.
55033 // includes scottish gaelic two word and hyphenated months
55034
55035 var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;
55036 var regexes = {};
55037
55038 function addRegexToken(token, regex, strictRegex) {
55039 regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
55040 return isStrict && strictRegex ? strictRegex : regex;
55041 };
55042 }
55043
55044 function getParseRegexForToken(token, config) {
55045 if (!hasOwnProp(regexes, token)) {
55046 return new RegExp(unescapeFormat(token));
55047 }
55048
55049 return regexes[token](config._strict, config._locale);
55050 } // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
55051
55052
55053 function unescapeFormat(s) {
55054 return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
55055 return p1 || p2 || p3 || p4;
55056 }));
55057 }
55058
55059 function regexEscape(s) {
55060 return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
55061 }
55062
55063 var tokens = {};
55064
55065 function addParseToken(token, callback) {
55066 var i,
55067 func = callback;
55068
55069 if (typeof token === 'string') {
55070 token = [token];
55071 }
55072
55073 if (isNumber(callback)) {
55074 func = function (input, array) {
55075 array[callback] = toInt(input);
55076 };
55077 }
55078
55079 for (i = 0; i < token.length; i++) {
55080 tokens[token[i]] = func;
55081 }
55082 }
55083
55084 function addWeekParseToken(token, callback) {
55085 addParseToken(token, function (input, array, config, token) {
55086 config._w = config._w || {};
55087 callback(input, config._w, config, token);
55088 });
55089 }
55090
55091 function addTimeToArrayFromToken(token, input, config) {
55092 if (input != null && hasOwnProp(tokens, token)) {
55093 tokens[token](input, config._a, config, token);
55094 }
55095 }
55096
55097 var YEAR = 0;
55098 var MONTH = 1;
55099 var DATE = 2;
55100 var HOUR = 3;
55101 var MINUTE = 4;
55102 var SECOND = 5;
55103 var MILLISECOND = 6;
55104 var WEEK = 7;
55105 var WEEKDAY = 8; // FORMATTING
55106
55107 addFormatToken('Y', 0, 0, function () {
55108 var y = this.year();
55109 return y <= 9999 ? '' + y : '+' + y;
55110 });
55111 addFormatToken(0, ['YY', 2], 0, function () {
55112 return this.year() % 100;
55113 });
55114 addFormatToken(0, ['YYYY', 4], 0, 'year');
55115 addFormatToken(0, ['YYYYY', 5], 0, 'year');
55116 addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); // ALIASES
55117
55118 addUnitAlias('year', 'y'); // PRIORITIES
55119
55120 addUnitPriority('year', 1); // PARSING
55121
55122 addRegexToken('Y', matchSigned);
55123 addRegexToken('YY', match1to2, match2);
55124 addRegexToken('YYYY', match1to4, match4);
55125 addRegexToken('YYYYY', match1to6, match6);
55126 addRegexToken('YYYYYY', match1to6, match6);
55127 addParseToken(['YYYYY', 'YYYYYY'], YEAR);
55128 addParseToken('YYYY', function (input, array) {
55129 array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
55130 });
55131 addParseToken('YY', function (input, array) {
55132 array[YEAR] = hooks.parseTwoDigitYear(input);
55133 });
55134 addParseToken('Y', function (input, array) {
55135 array[YEAR] = parseInt(input, 10);
55136 }); // HELPERS
55137
55138 function daysInYear(year) {
55139 return isLeapYear(year) ? 366 : 365;
55140 }
55141
55142 function isLeapYear(year) {
55143 return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
55144 } // HOOKS
55145
55146
55147 hooks.parseTwoDigitYear = function (input) {
55148 return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
55149 }; // MOMENTS
55150
55151
55152 var getSetYear = makeGetSet('FullYear', true);
55153
55154 function getIsLeapYear() {
55155 return isLeapYear(this.year());
55156 }
55157
55158 function makeGetSet(unit, keepTime) {
55159 return function (value) {
55160 if (value != null) {
55161 set$1(this, unit, value);
55162 hooks.updateOffset(this, keepTime);
55163 return this;
55164 } else {
55165 return get(this, unit);
55166 }
55167 };
55168 }
55169
55170 function get(mom, unit) {
55171 return mom.isValid() ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
55172 }
55173
55174 function set$1(mom, unit, value) {
55175 if (mom.isValid() && !isNaN(value)) {
55176 if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
55177 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
55178 } else {
55179 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
55180 }
55181 }
55182 } // MOMENTS
55183
55184
55185 function stringGet(units) {
55186 units = normalizeUnits(units);
55187
55188 if (isFunction(this[units])) {
55189 return this[units]();
55190 }
55191
55192 return this;
55193 }
55194
55195 function stringSet(units, value) {
55196 if (typeof units === 'object') {
55197 units = normalizeObjectUnits(units);
55198 var prioritized = getPrioritizedUnits(units);
55199
55200 for (var i = 0; i < prioritized.length; i++) {
55201 this[prioritized[i].unit](units[prioritized[i].unit]);
55202 }
55203 } else {
55204 units = normalizeUnits(units);
55205
55206 if (isFunction(this[units])) {
55207 return this[units](value);
55208 }
55209 }
55210
55211 return this;
55212 }
55213
55214 function mod(n, x) {
55215 return (n % x + x) % x;
55216 }
55217
55218 var indexOf;
55219
55220 if (Array.prototype.indexOf) {
55221 indexOf = Array.prototype.indexOf;
55222 } else {
55223 indexOf = function (o) {
55224 // I know
55225 var i;
55226
55227 for (i = 0; i < this.length; ++i) {
55228 if (this[i] === o) {
55229 return i;
55230 }
55231 }
55232
55233 return -1;
55234 };
55235 }
55236
55237 function daysInMonth(year, month) {
55238 if (isNaN(year) || isNaN(month)) {
55239 return NaN;
55240 }
55241
55242 var modMonth = mod(month, 12);
55243 year += (month - modMonth) / 12;
55244 return modMonth === 1 ? isLeapYear(year) ? 29 : 28 : 31 - modMonth % 7 % 2;
55245 } // FORMATTING
55246
55247
55248 addFormatToken('M', ['MM', 2], 'Mo', function () {
55249 return this.month() + 1;
55250 });
55251 addFormatToken('MMM', 0, 0, function (format) {
55252 return this.localeData().monthsShort(this, format);
55253 });
55254 addFormatToken('MMMM', 0, 0, function (format) {
55255 return this.localeData().months(this, format);
55256 }); // ALIASES
55257
55258 addUnitAlias('month', 'M'); // PRIORITY
55259
55260 addUnitPriority('month', 8); // PARSING
55261
55262 addRegexToken('M', match1to2);
55263 addRegexToken('MM', match1to2, match2);
55264 addRegexToken('MMM', function (isStrict, locale) {
55265 return locale.monthsShortRegex(isStrict);
55266 });
55267 addRegexToken('MMMM', function (isStrict, locale) {
55268 return locale.monthsRegex(isStrict);
55269 });
55270 addParseToken(['M', 'MM'], function (input, array) {
55271 array[MONTH] = toInt(input) - 1;
55272 });
55273 addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
55274 var month = config._locale.monthsParse(input, token, config._strict); // if we didn't find a month name, mark the date as invalid.
55275
55276
55277 if (month != null) {
55278 array[MONTH] = month;
55279 } else {
55280 getParsingFlags(config).invalidMonth = input;
55281 }
55282 }); // LOCALES
55283
55284 var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
55285 var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
55286
55287 function localeMonths(m, format) {
55288 if (!m) {
55289 return isArray(this._months) ? this._months : this._months['standalone'];
55290 }
55291
55292 return isArray(this._months) ? this._months[m.month()] : this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
55293 }
55294
55295 var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
55296
55297 function localeMonthsShort(m, format) {
55298 if (!m) {
55299 return isArray(this._monthsShort) ? this._monthsShort : this._monthsShort['standalone'];
55300 }
55301
55302 return isArray(this._monthsShort) ? this._monthsShort[m.month()] : this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
55303 }
55304
55305 function handleStrictParse(monthName, format, strict) {
55306 var i,
55307 ii,
55308 mom,
55309 llc = monthName.toLocaleLowerCase();
55310
55311 if (!this._monthsParse) {
55312 // this is not used
55313 this._monthsParse = [];
55314 this._longMonthsParse = [];
55315 this._shortMonthsParse = [];
55316
55317 for (i = 0; i < 12; ++i) {
55318 mom = createUTC([2000, i]);
55319 this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
55320 this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
55321 }
55322 }
55323
55324 if (strict) {
55325 if (format === 'MMM') {
55326 ii = indexOf.call(this._shortMonthsParse, llc);
55327 return ii !== -1 ? ii : null;
55328 } else {
55329 ii = indexOf.call(this._longMonthsParse, llc);
55330 return ii !== -1 ? ii : null;
55331 }
55332 } else {
55333 if (format === 'MMM') {
55334 ii = indexOf.call(this._shortMonthsParse, llc);
55335
55336 if (ii !== -1) {
55337 return ii;
55338 }
55339
55340 ii = indexOf.call(this._longMonthsParse, llc);
55341 return ii !== -1 ? ii : null;
55342 } else {
55343 ii = indexOf.call(this._longMonthsParse, llc);
55344
55345 if (ii !== -1) {
55346 return ii;
55347 }
55348
55349 ii = indexOf.call(this._shortMonthsParse, llc);
55350 return ii !== -1 ? ii : null;
55351 }
55352 }
55353 }
55354
55355 function localeMonthsParse(monthName, format, strict) {
55356 var i, mom, regex;
55357
55358 if (this._monthsParseExact) {
55359 return handleStrictParse.call(this, monthName, format, strict);
55360 }
55361
55362 if (!this._monthsParse) {
55363 this._monthsParse = [];
55364 this._longMonthsParse = [];
55365 this._shortMonthsParse = [];
55366 } // TODO: add sorting
55367 // Sorting makes sure if one month (or abbr) is a prefix of another
55368 // see sorting in computeMonthsParse
55369
55370
55371 for (i = 0; i < 12; i++) {
55372 // make the regex if we don't have it already
55373 mom = createUTC([2000, i]);
55374
55375 if (strict && !this._longMonthsParse[i]) {
55376 this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
55377 this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
55378 }
55379
55380 if (!strict && !this._monthsParse[i]) {
55381 regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
55382 this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
55383 } // test the regex
55384
55385
55386 if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
55387 return i;
55388 } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
55389 return i;
55390 } else if (!strict && this._monthsParse[i].test(monthName)) {
55391 return i;
55392 }
55393 }
55394 } // MOMENTS
55395
55396
55397 function setMonth(mom, value) {
55398 var dayOfMonth;
55399
55400 if (!mom.isValid()) {
55401 // No op
55402 return mom;
55403 }
55404
55405 if (typeof value === 'string') {
55406 if (/^\d+$/.test(value)) {
55407 value = toInt(value);
55408 } else {
55409 value = mom.localeData().monthsParse(value); // TODO: Another silent failure?
55410
55411 if (!isNumber(value)) {
55412 return mom;
55413 }
55414 }
55415 }
55416
55417 dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
55418
55419 mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
55420
55421 return mom;
55422 }
55423
55424 function getSetMonth(value) {
55425 if (value != null) {
55426 setMonth(this, value);
55427 hooks.updateOffset(this, true);
55428 return this;
55429 } else {
55430 return get(this, 'Month');
55431 }
55432 }
55433
55434 function getDaysInMonth() {
55435 return daysInMonth(this.year(), this.month());
55436 }
55437
55438 var defaultMonthsShortRegex = matchWord;
55439
55440 function monthsShortRegex(isStrict) {
55441 if (this._monthsParseExact) {
55442 if (!hasOwnProp(this, '_monthsRegex')) {
55443 computeMonthsParse.call(this);
55444 }
55445
55446 if (isStrict) {
55447 return this._monthsShortStrictRegex;
55448 } else {
55449 return this._monthsShortRegex;
55450 }
55451 } else {
55452 if (!hasOwnProp(this, '_monthsShortRegex')) {
55453 this._monthsShortRegex = defaultMonthsShortRegex;
55454 }
55455
55456 return this._monthsShortStrictRegex && isStrict ? this._monthsShortStrictRegex : this._monthsShortRegex;
55457 }
55458 }
55459
55460 var defaultMonthsRegex = matchWord;
55461
55462 function monthsRegex(isStrict) {
55463 if (this._monthsParseExact) {
55464 if (!hasOwnProp(this, '_monthsRegex')) {
55465 computeMonthsParse.call(this);
55466 }
55467
55468 if (isStrict) {
55469 return this._monthsStrictRegex;
55470 } else {
55471 return this._monthsRegex;
55472 }
55473 } else {
55474 if (!hasOwnProp(this, '_monthsRegex')) {
55475 this._monthsRegex = defaultMonthsRegex;
55476 }
55477
55478 return this._monthsStrictRegex && isStrict ? this._monthsStrictRegex : this._monthsRegex;
55479 }
55480 }
55481
55482 function computeMonthsParse() {
55483 function cmpLenRev(a, b) {
55484 return b.length - a.length;
55485 }
55486
55487 var shortPieces = [],
55488 longPieces = [],
55489 mixedPieces = [],
55490 i,
55491 mom;
55492
55493 for (i = 0; i < 12; i++) {
55494 // make the regex if we don't have it already
55495 mom = createUTC([2000, i]);
55496 shortPieces.push(this.monthsShort(mom, ''));
55497 longPieces.push(this.months(mom, ''));
55498 mixedPieces.push(this.months(mom, ''));
55499 mixedPieces.push(this.monthsShort(mom, ''));
55500 } // Sorting makes sure if one month (or abbr) is a prefix of another it
55501 // will match the longer piece.
55502
55503
55504 shortPieces.sort(cmpLenRev);
55505 longPieces.sort(cmpLenRev);
55506 mixedPieces.sort(cmpLenRev);
55507
55508 for (i = 0; i < 12; i++) {
55509 shortPieces[i] = regexEscape(shortPieces[i]);
55510 longPieces[i] = regexEscape(longPieces[i]);
55511 }
55512
55513 for (i = 0; i < 24; i++) {
55514 mixedPieces[i] = regexEscape(mixedPieces[i]);
55515 }
55516
55517 this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
55518 this._monthsShortRegex = this._monthsRegex;
55519 this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
55520 this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
55521 }
55522
55523 function createDate(y, m, d, h, M, s, ms) {
55524 // can't just apply() to create a date:
55525 // https://stackoverflow.com/q/181348
55526 var date; // the date constructor remaps years 0-99 to 1900-1999
55527
55528 if (y < 100 && y >= 0) {
55529 // preserve leap years using a full 400 year cycle, then reset
55530 date = new Date(y + 400, m, d, h, M, s, ms);
55531
55532 if (isFinite(date.getFullYear())) {
55533 date.setFullYear(y);
55534 }
55535 } else {
55536 date = new Date(y, m, d, h, M, s, ms);
55537 }
55538
55539 return date;
55540 }
55541
55542 function createUTCDate(y) {
55543 var date; // the Date.UTC function remaps years 0-99 to 1900-1999
55544
55545 if (y < 100 && y >= 0) {
55546 var args = Array.prototype.slice.call(arguments); // preserve leap years using a full 400 year cycle, then reset
55547
55548 args[0] = y + 400;
55549 date = new Date(Date.UTC.apply(null, args));
55550
55551 if (isFinite(date.getUTCFullYear())) {
55552 date.setUTCFullYear(y);
55553 }
55554 } else {
55555 date = new Date(Date.UTC.apply(null, arguments));
55556 }
55557
55558 return date;
55559 } // start-of-first-week - start-of-year
55560
55561
55562 function firstWeekOffset(year, dow, doy) {
55563 var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
55564 fwd = 7 + dow - doy,
55565 // first-week day local weekday -- which local weekday is fwd
55566 fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
55567 return -fwdlw + fwd - 1;
55568 } // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
55569
55570
55571 function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
55572 var localWeekday = (7 + weekday - dow) % 7,
55573 weekOffset = firstWeekOffset(year, dow, doy),
55574 dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
55575 resYear,
55576 resDayOfYear;
55577
55578 if (dayOfYear <= 0) {
55579 resYear = year - 1;
55580 resDayOfYear = daysInYear(resYear) + dayOfYear;
55581 } else if (dayOfYear > daysInYear(year)) {
55582 resYear = year + 1;
55583 resDayOfYear = dayOfYear - daysInYear(year);
55584 } else {
55585 resYear = year;
55586 resDayOfYear = dayOfYear;
55587 }
55588
55589 return {
55590 year: resYear,
55591 dayOfYear: resDayOfYear
55592 };
55593 }
55594
55595 function weekOfYear(mom, dow, doy) {
55596 var weekOffset = firstWeekOffset(mom.year(), dow, doy),
55597 week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
55598 resWeek,
55599 resYear;
55600
55601 if (week < 1) {
55602 resYear = mom.year() - 1;
55603 resWeek = week + weeksInYear(resYear, dow, doy);
55604 } else if (week > weeksInYear(mom.year(), dow, doy)) {
55605 resWeek = week - weeksInYear(mom.year(), dow, doy);
55606 resYear = mom.year() + 1;
55607 } else {
55608 resYear = mom.year();
55609 resWeek = week;
55610 }
55611
55612 return {
55613 week: resWeek,
55614 year: resYear
55615 };
55616 }
55617
55618 function weeksInYear(year, dow, doy) {
55619 var weekOffset = firstWeekOffset(year, dow, doy),
55620 weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
55621 return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
55622 } // FORMATTING
55623
55624
55625 addFormatToken('w', ['ww', 2], 'wo', 'week');
55626 addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); // ALIASES
55627
55628 addUnitAlias('week', 'w');
55629 addUnitAlias('isoWeek', 'W'); // PRIORITIES
55630
55631 addUnitPriority('week', 5);
55632 addUnitPriority('isoWeek', 5); // PARSING
55633
55634 addRegexToken('w', match1to2);
55635 addRegexToken('ww', match1to2, match2);
55636 addRegexToken('W', match1to2);
55637 addRegexToken('WW', match1to2, match2);
55638 addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
55639 week[token.substr(0, 1)] = toInt(input);
55640 }); // HELPERS
55641 // LOCALES
55642
55643 function localeWeek(mom) {
55644 return weekOfYear(mom, this._week.dow, this._week.doy).week;
55645 }
55646
55647 var defaultLocaleWeek = {
55648 dow: 0,
55649 // Sunday is the first day of the week.
55650 doy: 6 // The week that contains Jan 6th is the first week of the year.
55651
55652 };
55653
55654 function localeFirstDayOfWeek() {
55655 return this._week.dow;
55656 }
55657
55658 function localeFirstDayOfYear() {
55659 return this._week.doy;
55660 } // MOMENTS
55661
55662
55663 function getSetWeek(input) {
55664 var week = this.localeData().week(this);
55665 return input == null ? week : this.add((input - week) * 7, 'd');
55666 }
55667
55668 function getSetISOWeek(input) {
55669 var week = weekOfYear(this, 1, 4).week;
55670 return input == null ? week : this.add((input - week) * 7, 'd');
55671 } // FORMATTING
55672
55673
55674 addFormatToken('d', 0, 'do', 'day');
55675 addFormatToken('dd', 0, 0, function (format) {
55676 return this.localeData().weekdaysMin(this, format);
55677 });
55678 addFormatToken('ddd', 0, 0, function (format) {
55679 return this.localeData().weekdaysShort(this, format);
55680 });
55681 addFormatToken('dddd', 0, 0, function (format) {
55682 return this.localeData().weekdays(this, format);
55683 });
55684 addFormatToken('e', 0, 0, 'weekday');
55685 addFormatToken('E', 0, 0, 'isoWeekday'); // ALIASES
55686
55687 addUnitAlias('day', 'd');
55688 addUnitAlias('weekday', 'e');
55689 addUnitAlias('isoWeekday', 'E'); // PRIORITY
55690
55691 addUnitPriority('day', 11);
55692 addUnitPriority('weekday', 11);
55693 addUnitPriority('isoWeekday', 11); // PARSING
55694
55695 addRegexToken('d', match1to2);
55696 addRegexToken('e', match1to2);
55697 addRegexToken('E', match1to2);
55698 addRegexToken('dd', function (isStrict, locale) {
55699 return locale.weekdaysMinRegex(isStrict);
55700 });
55701 addRegexToken('ddd', function (isStrict, locale) {
55702 return locale.weekdaysShortRegex(isStrict);
55703 });
55704 addRegexToken('dddd', function (isStrict, locale) {
55705 return locale.weekdaysRegex(isStrict);
55706 });
55707 addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
55708 var weekday = config._locale.weekdaysParse(input, token, config._strict); // if we didn't get a weekday name, mark the date as invalid
55709
55710
55711 if (weekday != null) {
55712 week.d = weekday;
55713 } else {
55714 getParsingFlags(config).invalidWeekday = input;
55715 }
55716 });
55717 addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
55718 week[token] = toInt(input);
55719 }); // HELPERS
55720
55721 function parseWeekday(input, locale) {
55722 if (typeof input !== 'string') {
55723 return input;
55724 }
55725
55726 if (!isNaN(input)) {
55727 return parseInt(input, 10);
55728 }
55729
55730 input = locale.weekdaysParse(input);
55731
55732 if (typeof input === 'number') {
55733 return input;
55734 }
55735
55736 return null;
55737 }
55738
55739 function parseIsoWeekday(input, locale) {
55740 if (typeof input === 'string') {
55741 return locale.weekdaysParse(input) % 7 || 7;
55742 }
55743
55744 return isNaN(input) ? null : input;
55745 } // LOCALES
55746
55747
55748 function shiftWeekdays(ws, n) {
55749 return ws.slice(n, 7).concat(ws.slice(0, n));
55750 }
55751
55752 var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
55753
55754 function localeWeekdays(m, format) {
55755 var weekdays = isArray(this._weekdays) ? this._weekdays : this._weekdays[m && m !== true && this._weekdays.isFormat.test(format) ? 'format' : 'standalone'];
55756 return m === true ? shiftWeekdays(weekdays, this._week.dow) : m ? weekdays[m.day()] : weekdays;
55757 }
55758
55759 var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
55760
55761 function localeWeekdaysShort(m) {
55762 return m === true ? shiftWeekdays(this._weekdaysShort, this._week.dow) : m ? this._weekdaysShort[m.day()] : this._weekdaysShort;
55763 }
55764
55765 var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
55766
55767 function localeWeekdaysMin(m) {
55768 return m === true ? shiftWeekdays(this._weekdaysMin, this._week.dow) : m ? this._weekdaysMin[m.day()] : this._weekdaysMin;
55769 }
55770
55771 function handleStrictParse$1(weekdayName, format, strict) {
55772 var i,
55773 ii,
55774 mom,
55775 llc = weekdayName.toLocaleLowerCase();
55776
55777 if (!this._weekdaysParse) {
55778 this._weekdaysParse = [];
55779 this._shortWeekdaysParse = [];
55780 this._minWeekdaysParse = [];
55781
55782 for (i = 0; i < 7; ++i) {
55783 mom = createUTC([2000, 1]).day(i);
55784 this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
55785 this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
55786 this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
55787 }
55788 }
55789
55790 if (strict) {
55791 if (format === 'dddd') {
55792 ii = indexOf.call(this._weekdaysParse, llc);
55793 return ii !== -1 ? ii : null;
55794 } else if (format === 'ddd') {
55795 ii = indexOf.call(this._shortWeekdaysParse, llc);
55796 return ii !== -1 ? ii : null;
55797 } else {
55798 ii = indexOf.call(this._minWeekdaysParse, llc);
55799 return ii !== -1 ? ii : null;
55800 }
55801 } else {
55802 if (format === 'dddd') {
55803 ii = indexOf.call(this._weekdaysParse, llc);
55804
55805 if (ii !== -1) {
55806 return ii;
55807 }
55808
55809 ii = indexOf.call(this._shortWeekdaysParse, llc);
55810
55811 if (ii !== -1) {
55812 return ii;
55813 }
55814
55815 ii = indexOf.call(this._minWeekdaysParse, llc);
55816 return ii !== -1 ? ii : null;
55817 } else if (format === 'ddd') {
55818 ii = indexOf.call(this._shortWeekdaysParse, llc);
55819
55820 if (ii !== -1) {
55821 return ii;
55822 }
55823
55824 ii = indexOf.call(this._weekdaysParse, llc);
55825
55826 if (ii !== -1) {
55827 return ii;
55828 }
55829
55830 ii = indexOf.call(this._minWeekdaysParse, llc);
55831 return ii !== -1 ? ii : null;
55832 } else {
55833 ii = indexOf.call(this._minWeekdaysParse, llc);
55834
55835 if (ii !== -1) {
55836 return ii;
55837 }
55838
55839 ii = indexOf.call(this._weekdaysParse, llc);
55840
55841 if (ii !== -1) {
55842 return ii;
55843 }
55844
55845 ii = indexOf.call(this._shortWeekdaysParse, llc);
55846 return ii !== -1 ? ii : null;
55847 }
55848 }
55849 }
55850
55851 function localeWeekdaysParse(weekdayName, format, strict) {
55852 var i, mom, regex;
55853
55854 if (this._weekdaysParseExact) {
55855 return handleStrictParse$1.call(this, weekdayName, format, strict);
55856 }
55857
55858 if (!this._weekdaysParse) {
55859 this._weekdaysParse = [];
55860 this._minWeekdaysParse = [];
55861 this._shortWeekdaysParse = [];
55862 this._fullWeekdaysParse = [];
55863 }
55864
55865 for (i = 0; i < 7; i++) {
55866 // make the regex if we don't have it already
55867 mom = createUTC([2000, 1]).day(i);
55868
55869 if (strict && !this._fullWeekdaysParse[i]) {
55870 this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', 'i');
55871 this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', 'i');
55872 this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', 'i');
55873 }
55874
55875 if (!this._weekdaysParse[i]) {
55876 regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
55877 this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
55878 } // test the regex
55879
55880
55881 if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
55882 return i;
55883 } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
55884 return i;
55885 } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
55886 return i;
55887 } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
55888 return i;
55889 }
55890 }
55891 } // MOMENTS
55892
55893
55894 function getSetDayOfWeek(input) {
55895 if (!this.isValid()) {
55896 return input != null ? this : NaN;
55897 }
55898
55899 var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
55900
55901 if (input != null) {
55902 input = parseWeekday(input, this.localeData());
55903 return this.add(input - day, 'd');
55904 } else {
55905 return day;
55906 }
55907 }
55908
55909 function getSetLocaleDayOfWeek(input) {
55910 if (!this.isValid()) {
55911 return input != null ? this : NaN;
55912 }
55913
55914 var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
55915 return input == null ? weekday : this.add(input - weekday, 'd');
55916 }
55917
55918 function getSetISODayOfWeek(input) {
55919 if (!this.isValid()) {
55920 return input != null ? this : NaN;
55921 } // behaves the same as moment#day except
55922 // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
55923 // as a setter, sunday should belong to the previous week.
55924
55925
55926 if (input != null) {
55927 var weekday = parseIsoWeekday(input, this.localeData());
55928 return this.day(this.day() % 7 ? weekday : weekday - 7);
55929 } else {
55930 return this.day() || 7;
55931 }
55932 }
55933
55934 var defaultWeekdaysRegex = matchWord;
55935
55936 function weekdaysRegex(isStrict) {
55937 if (this._weekdaysParseExact) {
55938 if (!hasOwnProp(this, '_weekdaysRegex')) {
55939 computeWeekdaysParse.call(this);
55940 }
55941
55942 if (isStrict) {
55943 return this._weekdaysStrictRegex;
55944 } else {
55945 return this._weekdaysRegex;
55946 }
55947 } else {
55948 if (!hasOwnProp(this, '_weekdaysRegex')) {
55949 this._weekdaysRegex = defaultWeekdaysRegex;
55950 }
55951
55952 return this._weekdaysStrictRegex && isStrict ? this._weekdaysStrictRegex : this._weekdaysRegex;
55953 }
55954 }
55955
55956 var defaultWeekdaysShortRegex = matchWord;
55957
55958 function weekdaysShortRegex(isStrict) {
55959 if (this._weekdaysParseExact) {
55960 if (!hasOwnProp(this, '_weekdaysRegex')) {
55961 computeWeekdaysParse.call(this);
55962 }
55963
55964 if (isStrict) {
55965 return this._weekdaysShortStrictRegex;
55966 } else {
55967 return this._weekdaysShortRegex;
55968 }
55969 } else {
55970 if (!hasOwnProp(this, '_weekdaysShortRegex')) {
55971 this._weekdaysShortRegex = defaultWeekdaysShortRegex;
55972 }
55973
55974 return this._weekdaysShortStrictRegex && isStrict ? this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
55975 }
55976 }
55977
55978 var defaultWeekdaysMinRegex = matchWord;
55979
55980 function weekdaysMinRegex(isStrict) {
55981 if (this._weekdaysParseExact) {
55982 if (!hasOwnProp(this, '_weekdaysRegex')) {
55983 computeWeekdaysParse.call(this);
55984 }
55985
55986 if (isStrict) {
55987 return this._weekdaysMinStrictRegex;
55988 } else {
55989 return this._weekdaysMinRegex;
55990 }
55991 } else {
55992 if (!hasOwnProp(this, '_weekdaysMinRegex')) {
55993 this._weekdaysMinRegex = defaultWeekdaysMinRegex;
55994 }
55995
55996 return this._weekdaysMinStrictRegex && isStrict ? this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
55997 }
55998 }
55999
56000 function computeWeekdaysParse() {
56001 function cmpLenRev(a, b) {
56002 return b.length - a.length;
56003 }
56004
56005 var minPieces = [],
56006 shortPieces = [],
56007 longPieces = [],
56008 mixedPieces = [],
56009 i,
56010 mom,
56011 minp,
56012 shortp,
56013 longp;
56014
56015 for (i = 0; i < 7; i++) {
56016 // make the regex if we don't have it already
56017 mom = createUTC([2000, 1]).day(i);
56018 minp = this.weekdaysMin(mom, '');
56019 shortp = this.weekdaysShort(mom, '');
56020 longp = this.weekdays(mom, '');
56021 minPieces.push(minp);
56022 shortPieces.push(shortp);
56023 longPieces.push(longp);
56024 mixedPieces.push(minp);
56025 mixedPieces.push(shortp);
56026 mixedPieces.push(longp);
56027 } // Sorting makes sure if one weekday (or abbr) is a prefix of another it
56028 // will match the longer piece.
56029
56030
56031 minPieces.sort(cmpLenRev);
56032 shortPieces.sort(cmpLenRev);
56033 longPieces.sort(cmpLenRev);
56034 mixedPieces.sort(cmpLenRev);
56035
56036 for (i = 0; i < 7; i++) {
56037 shortPieces[i] = regexEscape(shortPieces[i]);
56038 longPieces[i] = regexEscape(longPieces[i]);
56039 mixedPieces[i] = regexEscape(mixedPieces[i]);
56040 }
56041
56042 this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
56043 this._weekdaysShortRegex = this._weekdaysRegex;
56044 this._weekdaysMinRegex = this._weekdaysRegex;
56045 this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
56046 this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
56047 this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
56048 } // FORMATTING
56049
56050
56051 function hFormat() {
56052 return this.hours() % 12 || 12;
56053 }
56054
56055 function kFormat() {
56056 return this.hours() || 24;
56057 }
56058
56059 addFormatToken('H', ['HH', 2], 0, 'hour');
56060 addFormatToken('h', ['hh', 2], 0, hFormat);
56061 addFormatToken('k', ['kk', 2], 0, kFormat);
56062 addFormatToken('hmm', 0, 0, function () {
56063 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
56064 });
56065 addFormatToken('hmmss', 0, 0, function () {
56066 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
56067 });
56068 addFormatToken('Hmm', 0, 0, function () {
56069 return '' + this.hours() + zeroFill(this.minutes(), 2);
56070 });
56071 addFormatToken('Hmmss', 0, 0, function () {
56072 return '' + this.hours() + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
56073 });
56074
56075 function meridiem(token, lowercase) {
56076 addFormatToken(token, 0, 0, function () {
56077 return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
56078 });
56079 }
56080
56081 meridiem('a', true);
56082 meridiem('A', false); // ALIASES
56083
56084 addUnitAlias('hour', 'h'); // PRIORITY
56085
56086 addUnitPriority('hour', 13); // PARSING
56087
56088 function matchMeridiem(isStrict, locale) {
56089 return locale._meridiemParse;
56090 }
56091
56092 addRegexToken('a', matchMeridiem);
56093 addRegexToken('A', matchMeridiem);
56094 addRegexToken('H', match1to2);
56095 addRegexToken('h', match1to2);
56096 addRegexToken('k', match1to2);
56097 addRegexToken('HH', match1to2, match2);
56098 addRegexToken('hh', match1to2, match2);
56099 addRegexToken('kk', match1to2, match2);
56100 addRegexToken('hmm', match3to4);
56101 addRegexToken('hmmss', match5to6);
56102 addRegexToken('Hmm', match3to4);
56103 addRegexToken('Hmmss', match5to6);
56104 addParseToken(['H', 'HH'], HOUR);
56105 addParseToken(['k', 'kk'], function (input, array, config) {
56106 var kInput = toInt(input);
56107 array[HOUR] = kInput === 24 ? 0 : kInput;
56108 });
56109 addParseToken(['a', 'A'], function (input, array, config) {
56110 config._isPm = config._locale.isPM(input);
56111 config._meridiem = input;
56112 });
56113 addParseToken(['h', 'hh'], function (input, array, config) {
56114 array[HOUR] = toInt(input);
56115 getParsingFlags(config).bigHour = true;
56116 });
56117 addParseToken('hmm', function (input, array, config) {
56118 var pos = input.length - 2;
56119 array[HOUR] = toInt(input.substr(0, pos));
56120 array[MINUTE] = toInt(input.substr(pos));
56121 getParsingFlags(config).bigHour = true;
56122 });
56123 addParseToken('hmmss', function (input, array, config) {
56124 var pos1 = input.length - 4;
56125 var pos2 = input.length - 2;
56126 array[HOUR] = toInt(input.substr(0, pos1));
56127 array[MINUTE] = toInt(input.substr(pos1, 2));
56128 array[SECOND] = toInt(input.substr(pos2));
56129 getParsingFlags(config).bigHour = true;
56130 });
56131 addParseToken('Hmm', function (input, array, config) {
56132 var pos = input.length - 2;
56133 array[HOUR] = toInt(input.substr(0, pos));
56134 array[MINUTE] = toInt(input.substr(pos));
56135 });
56136 addParseToken('Hmmss', function (input, array, config) {
56137 var pos1 = input.length - 4;
56138 var pos2 = input.length - 2;
56139 array[HOUR] = toInt(input.substr(0, pos1));
56140 array[MINUTE] = toInt(input.substr(pos1, 2));
56141 array[SECOND] = toInt(input.substr(pos2));
56142 }); // LOCALES
56143
56144 function localeIsPM(input) {
56145 // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
56146 // Using charAt should be more compatible.
56147 return (input + '').toLowerCase().charAt(0) === 'p';
56148 }
56149
56150 var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
56151
56152 function localeMeridiem(hours, minutes, isLower) {
56153 if (hours > 11) {
56154 return isLower ? 'pm' : 'PM';
56155 } else {
56156 return isLower ? 'am' : 'AM';
56157 }
56158 } // MOMENTS
56159 // Setting the hour should keep the time, because the user explicitly
56160 // specified which hour they want. So trying to maintain the same hour (in
56161 // a new timezone) makes sense. Adding/subtracting hours does not follow
56162 // this rule.
56163
56164
56165 var getSetHour = makeGetSet('Hours', true);
56166 var baseConfig = {
56167 calendar: defaultCalendar,
56168 longDateFormat: defaultLongDateFormat,
56169 invalidDate: defaultInvalidDate,
56170 ordinal: defaultOrdinal,
56171 dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
56172 relativeTime: defaultRelativeTime,
56173 months: defaultLocaleMonths,
56174 monthsShort: defaultLocaleMonthsShort,
56175 week: defaultLocaleWeek,
56176 weekdays: defaultLocaleWeekdays,
56177 weekdaysMin: defaultLocaleWeekdaysMin,
56178 weekdaysShort: defaultLocaleWeekdaysShort,
56179 meridiemParse: defaultLocaleMeridiemParse
56180 }; // internal storage for locale config files
56181
56182 var locales = {};
56183 var localeFamilies = {};
56184 var globalLocale;
56185
56186 function normalizeLocale(key) {
56187 return key ? key.toLowerCase().replace('_', '-') : key;
56188 } // pick the locale from the array
56189 // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
56190 // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
56191
56192
56193 function chooseLocale(names) {
56194 var i = 0,
56195 j,
56196 next,
56197 locale,
56198 split;
56199
56200 while (i < names.length) {
56201 split = normalizeLocale(names[i]).split('-');
56202 j = split.length;
56203 next = normalizeLocale(names[i + 1]);
56204 next = next ? next.split('-') : null;
56205
56206 while (j > 0) {
56207 locale = loadLocale(split.slice(0, j).join('-'));
56208
56209 if (locale) {
56210 return locale;
56211 }
56212
56213 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
56214 //the next array item is better than a shallower substring of this one
56215 break;
56216 }
56217
56218 j--;
56219 }
56220
56221 i++;
56222 }
56223
56224 return globalLocale;
56225 }
56226
56227 function loadLocale(name) {
56228 var oldLocale = null; // TODO: Find a better way to register and load all the locales in Node
56229
56230 if (!locales[name] && 'object' !== 'undefined' && module && module.exports) {
56231 try {
56232 oldLocale = globalLocale._abbr;
56233 var aliasedRequire = commonjsRequire;
56234 aliasedRequire('./locale/' + name);
56235 getSetGlobalLocale(oldLocale);
56236 } catch (e) {}
56237 }
56238
56239 return locales[name];
56240 } // This function will load locale and then set the global locale. If
56241 // no arguments are passed in, it will simply return the current global
56242 // locale key.
56243
56244
56245 function getSetGlobalLocale(key, values) {
56246 var data;
56247
56248 if (key) {
56249 if (isUndefined(values)) {
56250 data = getLocale(key);
56251 } else {
56252 data = defineLocale(key, values);
56253 }
56254
56255 if (data) {
56256 // moment.duration._locale = moment._locale = data;
56257 globalLocale = data;
56258 } else {
56259 if (typeof console !== 'undefined' && console.warn) {
56260 //warn user if arguments are passed but the locale could not be set
56261 console.warn('Locale ' + key + ' not found. Did you forget to load it?');
56262 }
56263 }
56264 }
56265
56266 return globalLocale._abbr;
56267 }
56268
56269 function defineLocale(name, config) {
56270 if (config !== null) {
56271 var locale,
56272 parentConfig = baseConfig;
56273 config.abbr = name;
56274
56275 if (locales[name] != null) {
56276 deprecateSimple('defineLocaleOverride', 'use moment.updateLocale(localeName, config) to change ' + 'an existing locale. moment.defineLocale(localeName, ' + 'config) should only be used for creating a new locale ' + 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
56277 parentConfig = locales[name]._config;
56278 } else if (config.parentLocale != null) {
56279 if (locales[config.parentLocale] != null) {
56280 parentConfig = locales[config.parentLocale]._config;
56281 } else {
56282 locale = loadLocale(config.parentLocale);
56283
56284 if (locale != null) {
56285 parentConfig = locale._config;
56286 } else {
56287 if (!localeFamilies[config.parentLocale]) {
56288 localeFamilies[config.parentLocale] = [];
56289 }
56290
56291 localeFamilies[config.parentLocale].push({
56292 name: name,
56293 config: config
56294 });
56295 return null;
56296 }
56297 }
56298 }
56299
56300 locales[name] = new Locale(mergeConfigs(parentConfig, config));
56301
56302 if (localeFamilies[name]) {
56303 localeFamilies[name].forEach(function (x) {
56304 defineLocale(x.name, x.config);
56305 });
56306 } // backwards compat for now: also set the locale
56307 // make sure we set the locale AFTER all child locales have been
56308 // created, so we won't end up with the child locale set.
56309
56310
56311 getSetGlobalLocale(name);
56312 return locales[name];
56313 } else {
56314 // useful for testing
56315 delete locales[name];
56316 return null;
56317 }
56318 }
56319
56320 function updateLocale(name, config) {
56321 if (config != null) {
56322 var locale,
56323 tmpLocale,
56324 parentConfig = baseConfig; // MERGE
56325
56326 tmpLocale = loadLocale(name);
56327
56328 if (tmpLocale != null) {
56329 parentConfig = tmpLocale._config;
56330 }
56331
56332 config = mergeConfigs(parentConfig, config);
56333 locale = new Locale(config);
56334 locale.parentLocale = locales[name];
56335 locales[name] = locale; // backwards compat for now: also set the locale
56336
56337 getSetGlobalLocale(name);
56338 } else {
56339 // pass null for config to unupdate, useful for tests
56340 if (locales[name] != null) {
56341 if (locales[name].parentLocale != null) {
56342 locales[name] = locales[name].parentLocale;
56343 } else if (locales[name] != null) {
56344 delete locales[name];
56345 }
56346 }
56347 }
56348
56349 return locales[name];
56350 } // returns locale data
56351
56352
56353 function getLocale(key) {
56354 var locale;
56355
56356 if (key && key._locale && key._locale._abbr) {
56357 key = key._locale._abbr;
56358 }
56359
56360 if (!key) {
56361 return globalLocale;
56362 }
56363
56364 if (!isArray(key)) {
56365 //short-circuit everything else
56366 locale = loadLocale(key);
56367
56368 if (locale) {
56369 return locale;
56370 }
56371
56372 key = [key];
56373 }
56374
56375 return chooseLocale(key);
56376 }
56377
56378 function listLocales() {
56379 return keys(locales);
56380 }
56381
56382 function checkOverflow(m) {
56383 var overflow;
56384 var a = m._a;
56385
56386 if (a && getParsingFlags(m).overflow === -2) {
56387 overflow = a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE : a[HOUR] < 0 || a[HOUR] > 24 || a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0) ? HOUR : a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE : a[SECOND] < 0 || a[SECOND] > 59 ? SECOND : a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND : -1;
56388
56389 if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
56390 overflow = DATE;
56391 }
56392
56393 if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
56394 overflow = WEEK;
56395 }
56396
56397 if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
56398 overflow = WEEKDAY;
56399 }
56400
56401 getParsingFlags(m).overflow = overflow;
56402 }
56403
56404 return m;
56405 } // Pick the first defined of two or three arguments.
56406
56407
56408 function defaults(a, b, c) {
56409 if (a != null) {
56410 return a;
56411 }
56412
56413 if (b != null) {
56414 return b;
56415 }
56416
56417 return c;
56418 }
56419
56420 function currentDateArray(config) {
56421 // hooks is actually the exported moment object
56422 var nowValue = new Date(hooks.now());
56423
56424 if (config._useUTC) {
56425 return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
56426 }
56427
56428 return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
56429 } // convert an array to a date.
56430 // the array should mirror the parameters below
56431 // note: all values past the year are optional and will default to the lowest possible value.
56432 // [year, month, day , hour, minute, second, millisecond]
56433
56434
56435 function configFromArray(config) {
56436 var i,
56437 date,
56438 input = [],
56439 currentDate,
56440 expectedWeekday,
56441 yearToUse;
56442
56443 if (config._d) {
56444 return;
56445 }
56446
56447 currentDate = currentDateArray(config); //compute day of the year from weeks and weekdays
56448
56449 if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
56450 dayOfYearFromWeekInfo(config);
56451 } //if the day of the year is set, figure out what it is
56452
56453
56454 if (config._dayOfYear != null) {
56455 yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
56456
56457 if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
56458 getParsingFlags(config)._overflowDayOfYear = true;
56459 }
56460
56461 date = createUTCDate(yearToUse, 0, config._dayOfYear);
56462 config._a[MONTH] = date.getUTCMonth();
56463 config._a[DATE] = date.getUTCDate();
56464 } // Default to current date.
56465 // * if no year, month, day of month are given, default to today
56466 // * if day of month is given, default month and year
56467 // * if month is given, default only year
56468 // * if year is given, don't default anything
56469
56470
56471 for (i = 0; i < 3 && config._a[i] == null; ++i) {
56472 config._a[i] = input[i] = currentDate[i];
56473 } // Zero out whatever was not defaulted, including time
56474
56475
56476 for (; i < 7; i++) {
56477 config._a[i] = input[i] = config._a[i] == null ? i === 2 ? 1 : 0 : config._a[i];
56478 } // Check for 24:00:00.000
56479
56480
56481 if (config._a[HOUR] === 24 && config._a[MINUTE] === 0 && config._a[SECOND] === 0 && config._a[MILLISECOND] === 0) {
56482 config._nextDay = true;
56483 config._a[HOUR] = 0;
56484 }
56485
56486 config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
56487 expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay(); // Apply timezone offset from input. The actual utcOffset can be changed
56488 // with parseZone.
56489
56490 if (config._tzm != null) {
56491 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
56492 }
56493
56494 if (config._nextDay) {
56495 config._a[HOUR] = 24;
56496 } // check for mismatching day of week
56497
56498
56499 if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
56500 getParsingFlags(config).weekdayMismatch = true;
56501 }
56502 }
56503
56504 function dayOfYearFromWeekInfo(config) {
56505 var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
56506 w = config._w;
56507
56508 if (w.GG != null || w.W != null || w.E != null) {
56509 dow = 1;
56510 doy = 4; // TODO: We need to take the current isoWeekYear, but that depends on
56511 // how we interpret now (local, utc, fixed offset). So create
56512 // a now version of current config (take local/utc/offset flags, and
56513 // create now).
56514
56515 weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
56516 week = defaults(w.W, 1);
56517 weekday = defaults(w.E, 1);
56518
56519 if (weekday < 1 || weekday > 7) {
56520 weekdayOverflow = true;
56521 }
56522 } else {
56523 dow = config._locale._week.dow;
56524 doy = config._locale._week.doy;
56525 var curWeek = weekOfYear(createLocal(), dow, doy);
56526 weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); // Default to current week.
56527
56528 week = defaults(w.w, curWeek.week);
56529
56530 if (w.d != null) {
56531 // weekday -- low day numbers are considered next week
56532 weekday = w.d;
56533
56534 if (weekday < 0 || weekday > 6) {
56535 weekdayOverflow = true;
56536 }
56537 } else if (w.e != null) {
56538 // local weekday -- counting starts from beginning of week
56539 weekday = w.e + dow;
56540
56541 if (w.e < 0 || w.e > 6) {
56542 weekdayOverflow = true;
56543 }
56544 } else {
56545 // default to beginning of week
56546 weekday = dow;
56547 }
56548 }
56549
56550 if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
56551 getParsingFlags(config)._overflowWeeks = true;
56552 } else if (weekdayOverflow != null) {
56553 getParsingFlags(config)._overflowWeekday = true;
56554 } else {
56555 temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
56556 config._a[YEAR] = temp.year;
56557 config._dayOfYear = temp.dayOfYear;
56558 }
56559 } // iso 8601 regex
56560 // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
56561
56562
56563 var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
56564 var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
56565 var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
56566 var isoDates = [['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], ['GGGG-[W]WW', /\d{4}-W\d\d/, false], ['YYYY-DDD', /\d{4}-\d{3}/], ['YYYY-MM', /\d{4}-\d\d/, false], ['YYYYYYMMDD', /[+-]\d{10}/], ['YYYYMMDD', /\d{8}/], // YYYYMM is NOT allowed by the standard
56567 ['GGGG[W]WWE', /\d{4}W\d{3}/], ['GGGG[W]WW', /\d{4}W\d{2}/, false], ['YYYYDDD', /\d{7}/]]; // iso time formats and regexes
56568
56569 var isoTimes = [['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], ['HH:mm:ss', /\d\d:\d\d:\d\d/], ['HH:mm', /\d\d:\d\d/], ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], ['HHmmss', /\d\d\d\d\d\d/], ['HHmm', /\d\d\d\d/], ['HH', /\d\d/]];
56570 var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; // date from iso format
56571
56572 function configFromISO(config) {
56573 var i,
56574 l,
56575 string = config._i,
56576 match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
56577 allowTime,
56578 dateFormat,
56579 timeFormat,
56580 tzFormat;
56581
56582 if (match) {
56583 getParsingFlags(config).iso = true;
56584
56585 for (i = 0, l = isoDates.length; i < l; i++) {
56586 if (isoDates[i][1].exec(match[1])) {
56587 dateFormat = isoDates[i][0];
56588 allowTime = isoDates[i][2] !== false;
56589 break;
56590 }
56591 }
56592
56593 if (dateFormat == null) {
56594 config._isValid = false;
56595 return;
56596 }
56597
56598 if (match[3]) {
56599 for (i = 0, l = isoTimes.length; i < l; i++) {
56600 if (isoTimes[i][1].exec(match[3])) {
56601 // match[2] should be 'T' or space
56602 timeFormat = (match[2] || ' ') + isoTimes[i][0];
56603 break;
56604 }
56605 }
56606
56607 if (timeFormat == null) {
56608 config._isValid = false;
56609 return;
56610 }
56611 }
56612
56613 if (!allowTime && timeFormat != null) {
56614 config._isValid = false;
56615 return;
56616 }
56617
56618 if (match[4]) {
56619 if (tzRegex.exec(match[4])) {
56620 tzFormat = 'Z';
56621 } else {
56622 config._isValid = false;
56623 return;
56624 }
56625 }
56626
56627 config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
56628 configFromStringAndFormat(config);
56629 } else {
56630 config._isValid = false;
56631 }
56632 } // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
56633
56634
56635 var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
56636
56637 function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
56638 var result = [untruncateYear(yearStr), defaultLocaleMonthsShort.indexOf(monthStr), parseInt(dayStr, 10), parseInt(hourStr, 10), parseInt(minuteStr, 10)];
56639
56640 if (secondStr) {
56641 result.push(parseInt(secondStr, 10));
56642 }
56643
56644 return result;
56645 }
56646
56647 function untruncateYear(yearStr) {
56648 var year = parseInt(yearStr, 10);
56649
56650 if (year <= 49) {
56651 return 2000 + year;
56652 } else if (year <= 999) {
56653 return 1900 + year;
56654 }
56655
56656 return year;
56657 }
56658
56659 function preprocessRFC2822(s) {
56660 // Remove comments and folding whitespace and replace multiple-spaces with a single space
56661 return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
56662 }
56663
56664 function checkWeekday(weekdayStr, parsedInput, config) {
56665 if (weekdayStr) {
56666 // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
56667 var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
56668 weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
56669
56670 if (weekdayProvided !== weekdayActual) {
56671 getParsingFlags(config).weekdayMismatch = true;
56672 config._isValid = false;
56673 return false;
56674 }
56675 }
56676
56677 return true;
56678 }
56679
56680 var obsOffsets = {
56681 UT: 0,
56682 GMT: 0,
56683 EDT: -4 * 60,
56684 EST: -5 * 60,
56685 CDT: -5 * 60,
56686 CST: -6 * 60,
56687 MDT: -6 * 60,
56688 MST: -7 * 60,
56689 PDT: -7 * 60,
56690 PST: -8 * 60
56691 };
56692
56693 function calculateOffset(obsOffset, militaryOffset, numOffset) {
56694 if (obsOffset) {
56695 return obsOffsets[obsOffset];
56696 } else if (militaryOffset) {
56697 // the only allowed military tz is Z
56698 return 0;
56699 } else {
56700 var hm = parseInt(numOffset, 10);
56701 var m = hm % 100,
56702 h = (hm - m) / 100;
56703 return h * 60 + m;
56704 }
56705 } // date and time from ref 2822 format
56706
56707
56708 function configFromRFC2822(config) {
56709 var match = rfc2822.exec(preprocessRFC2822(config._i));
56710
56711 if (match) {
56712 var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
56713
56714 if (!checkWeekday(match[1], parsedArray, config)) {
56715 return;
56716 }
56717
56718 config._a = parsedArray;
56719 config._tzm = calculateOffset(match[8], match[9], match[10]);
56720 config._d = createUTCDate.apply(null, config._a);
56721
56722 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
56723
56724 getParsingFlags(config).rfc2822 = true;
56725 } else {
56726 config._isValid = false;
56727 }
56728 } // date from iso format or fallback
56729
56730
56731 function configFromString(config) {
56732 var matched = aspNetJsonRegex.exec(config._i);
56733
56734 if (matched !== null) {
56735 config._d = new Date(+matched[1]);
56736 return;
56737 }
56738
56739 configFromISO(config);
56740
56741 if (config._isValid === false) {
56742 delete config._isValid;
56743 } else {
56744 return;
56745 }
56746
56747 configFromRFC2822(config);
56748
56749 if (config._isValid === false) {
56750 delete config._isValid;
56751 } else {
56752 return;
56753 } // Final attempt, use Input Fallback
56754
56755
56756 hooks.createFromInputFallback(config);
56757 }
56758
56759 hooks.createFromInputFallback = deprecate('value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + 'discouraged and will be removed in an upcoming major release. Please refer to ' + 'http://momentjs.com/guides/#/warnings/js-date/ for more info.', function (config) {
56760 config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
56761 }); // constant that refers to the ISO standard
56762
56763 hooks.ISO_8601 = function () {}; // constant that refers to the RFC 2822 form
56764
56765
56766 hooks.RFC_2822 = function () {}; // date from string and format string
56767
56768
56769 function configFromStringAndFormat(config) {
56770 // TODO: Move this to another part of the creation flow to prevent circular deps
56771 if (config._f === hooks.ISO_8601) {
56772 configFromISO(config);
56773 return;
56774 }
56775
56776 if (config._f === hooks.RFC_2822) {
56777 configFromRFC2822(config);
56778 return;
56779 }
56780
56781 config._a = [];
56782 getParsingFlags(config).empty = true; // This array is used to make a Date, either with `new Date` or `Date.UTC`
56783
56784 var string = '' + config._i,
56785 i,
56786 parsedInput,
56787 tokens,
56788 token,
56789 skipped,
56790 stringLength = string.length,
56791 totalParsedInputLength = 0;
56792 tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
56793
56794 for (i = 0; i < tokens.length; i++) {
56795 token = tokens[i];
56796 parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; // console.log('token', token, 'parsedInput', parsedInput,
56797 // 'regex', getParseRegexForToken(token, config));
56798
56799 if (parsedInput) {
56800 skipped = string.substr(0, string.indexOf(parsedInput));
56801
56802 if (skipped.length > 0) {
56803 getParsingFlags(config).unusedInput.push(skipped);
56804 }
56805
56806 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
56807 totalParsedInputLength += parsedInput.length;
56808 } // don't parse if it's not a known token
56809
56810
56811 if (formatTokenFunctions[token]) {
56812 if (parsedInput) {
56813 getParsingFlags(config).empty = false;
56814 } else {
56815 getParsingFlags(config).unusedTokens.push(token);
56816 }
56817
56818 addTimeToArrayFromToken(token, parsedInput, config);
56819 } else if (config._strict && !parsedInput) {
56820 getParsingFlags(config).unusedTokens.push(token);
56821 }
56822 } // add remaining unparsed input length to the string
56823
56824
56825 getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
56826
56827 if (string.length > 0) {
56828 getParsingFlags(config).unusedInput.push(string);
56829 } // clear _12h flag if hour is <= 12
56830
56831
56832 if (config._a[HOUR] <= 12 && getParsingFlags(config).bigHour === true && config._a[HOUR] > 0) {
56833 getParsingFlags(config).bigHour = undefined;
56834 }
56835
56836 getParsingFlags(config).parsedDateParts = config._a.slice(0);
56837 getParsingFlags(config).meridiem = config._meridiem; // handle meridiem
56838
56839 config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
56840 configFromArray(config);
56841 checkOverflow(config);
56842 }
56843
56844 function meridiemFixWrap(locale, hour, meridiem) {
56845 var isPm;
56846
56847 if (meridiem == null) {
56848 // nothing to do
56849 return hour;
56850 }
56851
56852 if (locale.meridiemHour != null) {
56853 return locale.meridiemHour(hour, meridiem);
56854 } else if (locale.isPM != null) {
56855 // Fallback
56856 isPm = locale.isPM(meridiem);
56857
56858 if (isPm && hour < 12) {
56859 hour += 12;
56860 }
56861
56862 if (!isPm && hour === 12) {
56863 hour = 0;
56864 }
56865
56866 return hour;
56867 } else {
56868 // this is not supposed to happen
56869 return hour;
56870 }
56871 } // date from string and array of format strings
56872
56873
56874 function configFromStringAndArray(config) {
56875 var tempConfig, bestMoment, scoreToBeat, i, currentScore;
56876
56877 if (config._f.length === 0) {
56878 getParsingFlags(config).invalidFormat = true;
56879 config._d = new Date(NaN);
56880 return;
56881 }
56882
56883 for (i = 0; i < config._f.length; i++) {
56884 currentScore = 0;
56885 tempConfig = copyConfig({}, config);
56886
56887 if (config._useUTC != null) {
56888 tempConfig._useUTC = config._useUTC;
56889 }
56890
56891 tempConfig._f = config._f[i];
56892 configFromStringAndFormat(tempConfig);
56893
56894 if (!isValid(tempConfig)) {
56895 continue;
56896 } // if there is any input that was not parsed add a penalty for that format
56897
56898
56899 currentScore += getParsingFlags(tempConfig).charsLeftOver; //or tokens
56900
56901 currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
56902 getParsingFlags(tempConfig).score = currentScore;
56903
56904 if (scoreToBeat == null || currentScore < scoreToBeat) {
56905 scoreToBeat = currentScore;
56906 bestMoment = tempConfig;
56907 }
56908 }
56909
56910 extend(config, bestMoment || tempConfig);
56911 }
56912
56913 function configFromObject(config) {
56914 if (config._d) {
56915 return;
56916 }
56917
56918 var i = normalizeObjectUnits(config._i);
56919 config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
56920 return obj && parseInt(obj, 10);
56921 });
56922 configFromArray(config);
56923 }
56924
56925 function createFromConfig(config) {
56926 var res = new Moment(checkOverflow(prepareConfig(config)));
56927
56928 if (res._nextDay) {
56929 // Adding is smart enough around DST
56930 res.add(1, 'd');
56931 res._nextDay = undefined;
56932 }
56933
56934 return res;
56935 }
56936
56937 function prepareConfig(config) {
56938 var input = config._i,
56939 format = config._f;
56940 config._locale = config._locale || getLocale(config._l);
56941
56942 if (input === null || format === undefined && input === '') {
56943 return createInvalid({
56944 nullInput: true
56945 });
56946 }
56947
56948 if (typeof input === 'string') {
56949 config._i = input = config._locale.preparse(input);
56950 }
56951
56952 if (isMoment(input)) {
56953 return new Moment(checkOverflow(input));
56954 } else if (isDate(input)) {
56955 config._d = input;
56956 } else if (isArray(format)) {
56957 configFromStringAndArray(config);
56958 } else if (format) {
56959 configFromStringAndFormat(config);
56960 } else {
56961 configFromInput(config);
56962 }
56963
56964 if (!isValid(config)) {
56965 config._d = null;
56966 }
56967
56968 return config;
56969 }
56970
56971 function configFromInput(config) {
56972 var input = config._i;
56973
56974 if (isUndefined(input)) {
56975 config._d = new Date(hooks.now());
56976 } else if (isDate(input)) {
56977 config._d = new Date(input.valueOf());
56978 } else if (typeof input === 'string') {
56979 configFromString(config);
56980 } else if (isArray(input)) {
56981 config._a = map(input.slice(0), function (obj) {
56982 return parseInt(obj, 10);
56983 });
56984 configFromArray(config);
56985 } else if (isObject(input)) {
56986 configFromObject(config);
56987 } else if (isNumber(input)) {
56988 // from milliseconds
56989 config._d = new Date(input);
56990 } else {
56991 hooks.createFromInputFallback(config);
56992 }
56993 }
56994
56995 function createLocalOrUTC(input, format, locale, strict, isUTC) {
56996 var c = {};
56997
56998 if (locale === true || locale === false) {
56999 strict = locale;
57000 locale = undefined;
57001 }
57002
57003 if (isObject(input) && isObjectEmpty(input) || isArray(input) && input.length === 0) {
57004 input = undefined;
57005 } // object construction must be done this way.
57006 // https://github.com/moment/moment/issues/1423
57007
57008
57009 c._isAMomentObject = true;
57010 c._useUTC = c._isUTC = isUTC;
57011 c._l = locale;
57012 c._i = input;
57013 c._f = format;
57014 c._strict = strict;
57015 return createFromConfig(c);
57016 }
57017
57018 function createLocal(input, format, locale, strict) {
57019 return createLocalOrUTC(input, format, locale, strict, false);
57020 }
57021
57022 var prototypeMin = deprecate('moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
57023 var other = createLocal.apply(null, arguments);
57024
57025 if (this.isValid() && other.isValid()) {
57026 return other < this ? this : other;
57027 } else {
57028 return createInvalid();
57029 }
57030 });
57031 var prototypeMax = deprecate('moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
57032 var other = createLocal.apply(null, arguments);
57033
57034 if (this.isValid() && other.isValid()) {
57035 return other > this ? this : other;
57036 } else {
57037 return createInvalid();
57038 }
57039 }); // Pick a moment m from moments so that m[fn](other) is true for all
57040 // other. This relies on the function fn to be transitive.
57041 //
57042 // moments should either be an array of moment objects or an array, whose
57043 // first element is an array of moment objects.
57044
57045 function pickBy(fn, moments) {
57046 var res, i;
57047
57048 if (moments.length === 1 && isArray(moments[0])) {
57049 moments = moments[0];
57050 }
57051
57052 if (!moments.length) {
57053 return createLocal();
57054 }
57055
57056 res = moments[0];
57057
57058 for (i = 1; i < moments.length; ++i) {
57059 if (!moments[i].isValid() || moments[i][fn](res)) {
57060 res = moments[i];
57061 }
57062 }
57063
57064 return res;
57065 } // TODO: Use [].sort instead?
57066
57067
57068 function min() {
57069 var args = [].slice.call(arguments, 0);
57070 return pickBy('isBefore', args);
57071 }
57072
57073 function max() {
57074 var args = [].slice.call(arguments, 0);
57075 return pickBy('isAfter', args);
57076 }
57077
57078 var now = function () {
57079 return Date.now ? Date.now() : +new Date();
57080 };
57081
57082 var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
57083
57084 function isDurationValid(m) {
57085 for (var key in m) {
57086 if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
57087 return false;
57088 }
57089 }
57090
57091 var unitHasDecimal = false;
57092
57093 for (var i = 0; i < ordering.length; ++i) {
57094 if (m[ordering[i]]) {
57095 if (unitHasDecimal) {
57096 return false; // only allow non-integers for smallest unit
57097 }
57098
57099 if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
57100 unitHasDecimal = true;
57101 }
57102 }
57103 }
57104
57105 return true;
57106 }
57107
57108 function isValid$1() {
57109 return this._isValid;
57110 }
57111
57112 function createInvalid$1() {
57113 return createDuration(NaN);
57114 }
57115
57116 function Duration(duration) {
57117 var normalizedInput = normalizeObjectUnits(duration),
57118 years = normalizedInput.year || 0,
57119 quarters = normalizedInput.quarter || 0,
57120 months = normalizedInput.month || 0,
57121 weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
57122 days = normalizedInput.day || 0,
57123 hours = normalizedInput.hour || 0,
57124 minutes = normalizedInput.minute || 0,
57125 seconds = normalizedInput.second || 0,
57126 milliseconds = normalizedInput.millisecond || 0;
57127 this._isValid = isDurationValid(normalizedInput); // representation for dateAddRemove
57128
57129 this._milliseconds = +milliseconds + seconds * 1e3 + // 1000
57130 minutes * 6e4 + // 1000 * 60
57131 hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
57132 // Because of dateAddRemove treats 24 hours as different from a
57133 // day when working around DST, we need to store them separately
57134
57135 this._days = +days + weeks * 7; // It is impossible to translate months into days without knowing
57136 // which months you are are talking about, so we have to store
57137 // it separately.
57138
57139 this._months = +months + quarters * 3 + years * 12;
57140 this._data = {};
57141 this._locale = getLocale();
57142
57143 this._bubble();
57144 }
57145
57146 function isDuration(obj) {
57147 return obj instanceof Duration;
57148 }
57149
57150 function absRound(number) {
57151 if (number < 0) {
57152 return Math.round(-1 * number) * -1;
57153 } else {
57154 return Math.round(number);
57155 }
57156 } // FORMATTING
57157
57158
57159 function offset(token, separator) {
57160 addFormatToken(token, 0, 0, function () {
57161 var offset = this.utcOffset();
57162 var sign = '+';
57163
57164 if (offset < 0) {
57165 offset = -offset;
57166 sign = '-';
57167 }
57168
57169 return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~offset % 60, 2);
57170 });
57171 }
57172
57173 offset('Z', ':');
57174 offset('ZZ', ''); // PARSING
57175
57176 addRegexToken('Z', matchShortOffset);
57177 addRegexToken('ZZ', matchShortOffset);
57178 addParseToken(['Z', 'ZZ'], function (input, array, config) {
57179 config._useUTC = true;
57180 config._tzm = offsetFromString(matchShortOffset, input);
57181 }); // HELPERS
57182 // timezone chunker
57183 // '+10:00' > ['10', '00']
57184 // '-1530' > ['-15', '30']
57185
57186 var chunkOffset = /([\+\-]|\d\d)/gi;
57187
57188 function offsetFromString(matcher, string) {
57189 var matches = (string || '').match(matcher);
57190
57191 if (matches === null) {
57192 return null;
57193 }
57194
57195 var chunk = matches[matches.length - 1] || [];
57196 var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
57197 var minutes = +(parts[1] * 60) + toInt(parts[2]);
57198 return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
57199 } // Return a moment from input, that is local/utc/zone equivalent to model.
57200
57201
57202 function cloneWithOffset(input, model) {
57203 var res, diff;
57204
57205 if (model._isUTC) {
57206 res = model.clone();
57207 diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf(); // Use low-level api, because this fn is low-level api.
57208
57209 res._d.setTime(res._d.valueOf() + diff);
57210
57211 hooks.updateOffset(res, false);
57212 return res;
57213 } else {
57214 return createLocal(input).local();
57215 }
57216 }
57217
57218 function getDateOffset(m) {
57219 // On Firefox.24 Date#getTimezoneOffset returns a floating point.
57220 // https://github.com/moment/moment/pull/1871
57221 return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
57222 } // HOOKS
57223 // This function will be called whenever a moment is mutated.
57224 // It is intended to keep the offset in sync with the timezone.
57225
57226
57227 hooks.updateOffset = function () {}; // MOMENTS
57228 // keepLocalTime = true means only change the timezone, without
57229 // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
57230 // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
57231 // +0200, so we adjust the time as needed, to be valid.
57232 //
57233 // Keeping the time actually adds/subtracts (one hour)
57234 // from the actual represented time. That is why we call updateOffset
57235 // a second time. In case it wants us to change the offset again
57236 // _changeInProgress == true case, then we have to adjust, because
57237 // there is no such time in the given timezone.
57238
57239
57240 function getSetOffset(input, keepLocalTime, keepMinutes) {
57241 var offset = this._offset || 0,
57242 localAdjust;
57243
57244 if (!this.isValid()) {
57245 return input != null ? this : NaN;
57246 }
57247
57248 if (input != null) {
57249 if (typeof input === 'string') {
57250 input = offsetFromString(matchShortOffset, input);
57251
57252 if (input === null) {
57253 return this;
57254 }
57255 } else if (Math.abs(input) < 16 && !keepMinutes) {
57256 input = input * 60;
57257 }
57258
57259 if (!this._isUTC && keepLocalTime) {
57260 localAdjust = getDateOffset(this);
57261 }
57262
57263 this._offset = input;
57264 this._isUTC = true;
57265
57266 if (localAdjust != null) {
57267 this.add(localAdjust, 'm');
57268 }
57269
57270 if (offset !== input) {
57271 if (!keepLocalTime || this._changeInProgress) {
57272 addSubtract(this, createDuration(input - offset, 'm'), 1, false);
57273 } else if (!this._changeInProgress) {
57274 this._changeInProgress = true;
57275 hooks.updateOffset(this, true);
57276 this._changeInProgress = null;
57277 }
57278 }
57279
57280 return this;
57281 } else {
57282 return this._isUTC ? offset : getDateOffset(this);
57283 }
57284 }
57285
57286 function getSetZone(input, keepLocalTime) {
57287 if (input != null) {
57288 if (typeof input !== 'string') {
57289 input = -input;
57290 }
57291
57292 this.utcOffset(input, keepLocalTime);
57293 return this;
57294 } else {
57295 return -this.utcOffset();
57296 }
57297 }
57298
57299 function setOffsetToUTC(keepLocalTime) {
57300 return this.utcOffset(0, keepLocalTime);
57301 }
57302
57303 function setOffsetToLocal(keepLocalTime) {
57304 if (this._isUTC) {
57305 this.utcOffset(0, keepLocalTime);
57306 this._isUTC = false;
57307
57308 if (keepLocalTime) {
57309 this.subtract(getDateOffset(this), 'm');
57310 }
57311 }
57312
57313 return this;
57314 }
57315
57316 function setOffsetToParsedOffset() {
57317 if (this._tzm != null) {
57318 this.utcOffset(this._tzm, false, true);
57319 } else if (typeof this._i === 'string') {
57320 var tZone = offsetFromString(matchOffset, this._i);
57321
57322 if (tZone != null) {
57323 this.utcOffset(tZone);
57324 } else {
57325 this.utcOffset(0, true);
57326 }
57327 }
57328
57329 return this;
57330 }
57331
57332 function hasAlignedHourOffset(input) {
57333 if (!this.isValid()) {
57334 return false;
57335 }
57336
57337 input = input ? createLocal(input).utcOffset() : 0;
57338 return (this.utcOffset() - input) % 60 === 0;
57339 }
57340
57341 function isDaylightSavingTime() {
57342 return this.utcOffset() > this.clone().month(0).utcOffset() || this.utcOffset() > this.clone().month(5).utcOffset();
57343 }
57344
57345 function isDaylightSavingTimeShifted() {
57346 if (!isUndefined(this._isDSTShifted)) {
57347 return this._isDSTShifted;
57348 }
57349
57350 var c = {};
57351 copyConfig(c, this);
57352 c = prepareConfig(c);
57353
57354 if (c._a) {
57355 var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
57356 this._isDSTShifted = this.isValid() && compareArrays(c._a, other.toArray()) > 0;
57357 } else {
57358 this._isDSTShifted = false;
57359 }
57360
57361 return this._isDSTShifted;
57362 }
57363
57364 function isLocal() {
57365 return this.isValid() ? !this._isUTC : false;
57366 }
57367
57368 function isUtcOffset() {
57369 return this.isValid() ? this._isUTC : false;
57370 }
57371
57372 function isUtc() {
57373 return this.isValid() ? this._isUTC && this._offset === 0 : false;
57374 } // ASP.NET json date format regex
57375
57376
57377 var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/; // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
57378 // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
57379 // and further modified to allow for strings containing both week and day
57380
57381 var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
57382
57383 function createDuration(input, key) {
57384 var duration = input,
57385 // matching against regexp is expensive, do it on demand
57386 match = null,
57387 sign,
57388 ret,
57389 diffRes;
57390
57391 if (isDuration(input)) {
57392 duration = {
57393 ms: input._milliseconds,
57394 d: input._days,
57395 M: input._months
57396 };
57397 } else if (isNumber(input)) {
57398 duration = {};
57399
57400 if (key) {
57401 duration[key] = input;
57402 } else {
57403 duration.milliseconds = input;
57404 }
57405 } else if (!!(match = aspNetRegex.exec(input))) {
57406 sign = match[1] === '-' ? -1 : 1;
57407 duration = {
57408 y: 0,
57409 d: toInt(match[DATE]) * sign,
57410 h: toInt(match[HOUR]) * sign,
57411 m: toInt(match[MINUTE]) * sign,
57412 s: toInt(match[SECOND]) * sign,
57413 ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
57414
57415 };
57416 } else if (!!(match = isoRegex.exec(input))) {
57417 sign = match[1] === '-' ? -1 : 1;
57418 duration = {
57419 y: parseIso(match[2], sign),
57420 M: parseIso(match[3], sign),
57421 w: parseIso(match[4], sign),
57422 d: parseIso(match[5], sign),
57423 h: parseIso(match[6], sign),
57424 m: parseIso(match[7], sign),
57425 s: parseIso(match[8], sign)
57426 };
57427 } else if (duration == null) {
57428 // checks for null or undefined
57429 duration = {};
57430 } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
57431 diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
57432 duration = {};
57433 duration.ms = diffRes.milliseconds;
57434 duration.M = diffRes.months;
57435 }
57436
57437 ret = new Duration(duration);
57438
57439 if (isDuration(input) && hasOwnProp(input, '_locale')) {
57440 ret._locale = input._locale;
57441 }
57442
57443 return ret;
57444 }
57445
57446 createDuration.fn = Duration.prototype;
57447 createDuration.invalid = createInvalid$1;
57448
57449 function parseIso(inp, sign) {
57450 // We'd normally use ~~inp for this, but unfortunately it also
57451 // converts floats to ints.
57452 // inp may be undefined, so careful calling replace on it.
57453 var res = inp && parseFloat(inp.replace(',', '.')); // apply sign while we're at it
57454
57455 return (isNaN(res) ? 0 : res) * sign;
57456 }
57457
57458 function positiveMomentsDifference(base, other) {
57459 var res = {};
57460 res.months = other.month() - base.month() + (other.year() - base.year()) * 12;
57461
57462 if (base.clone().add(res.months, 'M').isAfter(other)) {
57463 --res.months;
57464 }
57465
57466 res.milliseconds = +other - +base.clone().add(res.months, 'M');
57467 return res;
57468 }
57469
57470 function momentsDifference(base, other) {
57471 var res;
57472
57473 if (!(base.isValid() && other.isValid())) {
57474 return {
57475 milliseconds: 0,
57476 months: 0
57477 };
57478 }
57479
57480 other = cloneWithOffset(other, base);
57481
57482 if (base.isBefore(other)) {
57483 res = positiveMomentsDifference(base, other);
57484 } else {
57485 res = positiveMomentsDifference(other, base);
57486 res.milliseconds = -res.milliseconds;
57487 res.months = -res.months;
57488 }
57489
57490 return res;
57491 } // TODO: remove 'name' arg after deprecation is removed
57492
57493
57494 function createAdder(direction, name) {
57495 return function (val, period) {
57496 var dur, tmp; //invert the arguments, but complain about it
57497
57498 if (period !== null && !isNaN(+period)) {
57499 deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' + 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
57500 tmp = val;
57501 val = period;
57502 period = tmp;
57503 }
57504
57505 val = typeof val === 'string' ? +val : val;
57506 dur = createDuration(val, period);
57507 addSubtract(this, dur, direction);
57508 return this;
57509 };
57510 }
57511
57512 function addSubtract(mom, duration, isAdding, updateOffset) {
57513 var milliseconds = duration._milliseconds,
57514 days = absRound(duration._days),
57515 months = absRound(duration._months);
57516
57517 if (!mom.isValid()) {
57518 // No op
57519 return;
57520 }
57521
57522 updateOffset = updateOffset == null ? true : updateOffset;
57523
57524 if (months) {
57525 setMonth(mom, get(mom, 'Month') + months * isAdding);
57526 }
57527
57528 if (days) {
57529 set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
57530 }
57531
57532 if (milliseconds) {
57533 mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
57534 }
57535
57536 if (updateOffset) {
57537 hooks.updateOffset(mom, days || months);
57538 }
57539 }
57540
57541 var add = createAdder(1, 'add');
57542 var subtract = createAdder(-1, 'subtract');
57543
57544 function getCalendarFormat(myMoment, now) {
57545 var diff = myMoment.diff(now, 'days', true);
57546 return diff < -6 ? 'sameElse' : diff < -1 ? 'lastWeek' : diff < 0 ? 'lastDay' : diff < 1 ? 'sameDay' : diff < 2 ? 'nextDay' : diff < 7 ? 'nextWeek' : 'sameElse';
57547 }
57548
57549 function calendar$1(time, formats) {
57550 // We want to compare the start of today, vs this.
57551 // Getting start-of-today depends on whether we're local/utc/offset or not.
57552 var now = time || createLocal(),
57553 sod = cloneWithOffset(now, this).startOf('day'),
57554 format = hooks.calendarFormat(this, sod) || 'sameElse';
57555 var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
57556 return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
57557 }
57558
57559 function clone() {
57560 return new Moment(this);
57561 }
57562
57563 function isAfter(input, units) {
57564 var localInput = isMoment(input) ? input : createLocal(input);
57565
57566 if (!(this.isValid() && localInput.isValid())) {
57567 return false;
57568 }
57569
57570 units = normalizeUnits(units) || 'millisecond';
57571
57572 if (units === 'millisecond') {
57573 return this.valueOf() > localInput.valueOf();
57574 } else {
57575 return localInput.valueOf() < this.clone().startOf(units).valueOf();
57576 }
57577 }
57578
57579 function isBefore(input, units) {
57580 var localInput = isMoment(input) ? input : createLocal(input);
57581
57582 if (!(this.isValid() && localInput.isValid())) {
57583 return false;
57584 }
57585
57586 units = normalizeUnits(units) || 'millisecond';
57587
57588 if (units === 'millisecond') {
57589 return this.valueOf() < localInput.valueOf();
57590 } else {
57591 return this.clone().endOf(units).valueOf() < localInput.valueOf();
57592 }
57593 }
57594
57595 function isBetween(from, to, units, inclusivity) {
57596 var localFrom = isMoment(from) ? from : createLocal(from),
57597 localTo = isMoment(to) ? to : createLocal(to);
57598
57599 if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
57600 return false;
57601 }
57602
57603 inclusivity = inclusivity || '()';
57604 return (inclusivity[0] === '(' ? this.isAfter(localFrom, units) : !this.isBefore(localFrom, units)) && (inclusivity[1] === ')' ? this.isBefore(localTo, units) : !this.isAfter(localTo, units));
57605 }
57606
57607 function isSame(input, units) {
57608 var localInput = isMoment(input) ? input : createLocal(input),
57609 inputMs;
57610
57611 if (!(this.isValid() && localInput.isValid())) {
57612 return false;
57613 }
57614
57615 units = normalizeUnits(units) || 'millisecond';
57616
57617 if (units === 'millisecond') {
57618 return this.valueOf() === localInput.valueOf();
57619 } else {
57620 inputMs = localInput.valueOf();
57621 return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
57622 }
57623 }
57624
57625 function isSameOrAfter(input, units) {
57626 return this.isSame(input, units) || this.isAfter(input, units);
57627 }
57628
57629 function isSameOrBefore(input, units) {
57630 return this.isSame(input, units) || this.isBefore(input, units);
57631 }
57632
57633 function diff(input, units, asFloat) {
57634 var that, zoneDelta, output;
57635
57636 if (!this.isValid()) {
57637 return NaN;
57638 }
57639
57640 that = cloneWithOffset(input, this);
57641
57642 if (!that.isValid()) {
57643 return NaN;
57644 }
57645
57646 zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
57647 units = normalizeUnits(units);
57648
57649 switch (units) {
57650 case 'year':
57651 output = monthDiff(this, that) / 12;
57652 break;
57653
57654 case 'month':
57655 output = monthDiff(this, that);
57656 break;
57657
57658 case 'quarter':
57659 output = monthDiff(this, that) / 3;
57660 break;
57661
57662 case 'second':
57663 output = (this - that) / 1e3;
57664 break;
57665 // 1000
57666
57667 case 'minute':
57668 output = (this - that) / 6e4;
57669 break;
57670 // 1000 * 60
57671
57672 case 'hour':
57673 output = (this - that) / 36e5;
57674 break;
57675 // 1000 * 60 * 60
57676
57677 case 'day':
57678 output = (this - that - zoneDelta) / 864e5;
57679 break;
57680 // 1000 * 60 * 60 * 24, negate dst
57681
57682 case 'week':
57683 output = (this - that - zoneDelta) / 6048e5;
57684 break;
57685 // 1000 * 60 * 60 * 24 * 7, negate dst
57686
57687 default:
57688 output = this - that;
57689 }
57690
57691 return asFloat ? output : absFloor(output);
57692 }
57693
57694 function monthDiff(a, b) {
57695 // difference in months
57696 var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()),
57697 // b is in (anchor - 1 month, anchor + 1 month)
57698 anchor = a.clone().add(wholeMonthDiff, 'months'),
57699 anchor2,
57700 adjust;
57701
57702 if (b - anchor < 0) {
57703 anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); // linear across the month
57704
57705 adjust = (b - anchor) / (anchor - anchor2);
57706 } else {
57707 anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); // linear across the month
57708
57709 adjust = (b - anchor) / (anchor2 - anchor);
57710 } //check for negative zero, return zero if negative zero
57711
57712
57713 return -(wholeMonthDiff + adjust) || 0;
57714 }
57715
57716 hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
57717 hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
57718
57719 function toString() {
57720 return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
57721 }
57722
57723 function toISOString(keepOffset) {
57724 if (!this.isValid()) {
57725 return null;
57726 }
57727
57728 var utc = keepOffset !== true;
57729 var m = utc ? this.clone().utc() : this;
57730
57731 if (m.year() < 0 || m.year() > 9999) {
57732 return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
57733 }
57734
57735 if (isFunction(Date.prototype.toISOString)) {
57736 // native implementation is ~50x faster, use it when we can
57737 if (utc) {
57738 return this.toDate().toISOString();
57739 } else {
57740 return new Date(this.valueOf() + this.utcOffset() * 60 * 1000).toISOString().replace('Z', formatMoment(m, 'Z'));
57741 }
57742 }
57743
57744 return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
57745 }
57746 /**
57747 * Return a human readable representation of a moment that can
57748 * also be evaluated to get a new moment which is the same
57749 *
57750 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
57751 */
57752
57753
57754 function inspect() {
57755 if (!this.isValid()) {
57756 return 'moment.invalid(/* ' + this._i + ' */)';
57757 }
57758
57759 var func = 'moment';
57760 var zone = '';
57761
57762 if (!this.isLocal()) {
57763 func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
57764 zone = 'Z';
57765 }
57766
57767 var prefix = '[' + func + '("]';
57768 var year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
57769 var datetime = '-MM-DD[T]HH:mm:ss.SSS';
57770 var suffix = zone + '[")]';
57771 return this.format(prefix + year + datetime + suffix);
57772 }
57773
57774 function format(inputString) {
57775 if (!inputString) {
57776 inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
57777 }
57778
57779 var output = formatMoment(this, inputString);
57780 return this.localeData().postformat(output);
57781 }
57782
57783 function from(time, withoutSuffix) {
57784 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
57785 return createDuration({
57786 to: this,
57787 from: time
57788 }).locale(this.locale()).humanize(!withoutSuffix);
57789 } else {
57790 return this.localeData().invalidDate();
57791 }
57792 }
57793
57794 function fromNow(withoutSuffix) {
57795 return this.from(createLocal(), withoutSuffix);
57796 }
57797
57798 function to(time, withoutSuffix) {
57799 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
57800 return createDuration({
57801 from: this,
57802 to: time
57803 }).locale(this.locale()).humanize(!withoutSuffix);
57804 } else {
57805 return this.localeData().invalidDate();
57806 }
57807 }
57808
57809 function toNow(withoutSuffix) {
57810 return this.to(createLocal(), withoutSuffix);
57811 } // If passed a locale key, it will set the locale for this
57812 // instance. Otherwise, it will return the locale configuration
57813 // variables for this instance.
57814
57815
57816 function locale(key) {
57817 var newLocaleData;
57818
57819 if (key === undefined) {
57820 return this._locale._abbr;
57821 } else {
57822 newLocaleData = getLocale(key);
57823
57824 if (newLocaleData != null) {
57825 this._locale = newLocaleData;
57826 }
57827
57828 return this;
57829 }
57830 }
57831
57832 var lang = deprecate('moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', function (key) {
57833 if (key === undefined) {
57834 return this.localeData();
57835 } else {
57836 return this.locale(key);
57837 }
57838 });
57839
57840 function localeData() {
57841 return this._locale;
57842 }
57843
57844 var MS_PER_SECOND = 1000;
57845 var MS_PER_MINUTE = 60 * MS_PER_SECOND;
57846 var MS_PER_HOUR = 60 * MS_PER_MINUTE;
57847 var MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; // actual modulo - handles negative numbers (for dates before 1970):
57848
57849 function mod$1(dividend, divisor) {
57850 return (dividend % divisor + divisor) % divisor;
57851 }
57852
57853 function localStartOfDate(y, m, d) {
57854 // the date constructor remaps years 0-99 to 1900-1999
57855 if (y < 100 && y >= 0) {
57856 // preserve leap years using a full 400 year cycle, then reset
57857 return new Date(y + 400, m, d) - MS_PER_400_YEARS;
57858 } else {
57859 return new Date(y, m, d).valueOf();
57860 }
57861 }
57862
57863 function utcStartOfDate(y, m, d) {
57864 // Date.UTC remaps years 0-99 to 1900-1999
57865 if (y < 100 && y >= 0) {
57866 // preserve leap years using a full 400 year cycle, then reset
57867 return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
57868 } else {
57869 return Date.UTC(y, m, d);
57870 }
57871 }
57872
57873 function startOf(units) {
57874 var time;
57875 units = normalizeUnits(units);
57876
57877 if (units === undefined || units === 'millisecond' || !this.isValid()) {
57878 return this;
57879 }
57880
57881 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
57882
57883 switch (units) {
57884 case 'year':
57885 time = startOfDate(this.year(), 0, 1);
57886 break;
57887
57888 case 'quarter':
57889 time = startOfDate(this.year(), this.month() - this.month() % 3, 1);
57890 break;
57891
57892 case 'month':
57893 time = startOfDate(this.year(), this.month(), 1);
57894 break;
57895
57896 case 'week':
57897 time = startOfDate(this.year(), this.month(), this.date() - this.weekday());
57898 break;
57899
57900 case 'isoWeek':
57901 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1));
57902 break;
57903
57904 case 'day':
57905 case 'date':
57906 time = startOfDate(this.year(), this.month(), this.date());
57907 break;
57908
57909 case 'hour':
57910 time = this._d.valueOf();
57911 time -= mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR);
57912 break;
57913
57914 case 'minute':
57915 time = this._d.valueOf();
57916 time -= mod$1(time, MS_PER_MINUTE);
57917 break;
57918
57919 case 'second':
57920 time = this._d.valueOf();
57921 time -= mod$1(time, MS_PER_SECOND);
57922 break;
57923 }
57924
57925 this._d.setTime(time);
57926
57927 hooks.updateOffset(this, true);
57928 return this;
57929 }
57930
57931 function endOf(units) {
57932 var time;
57933 units = normalizeUnits(units);
57934
57935 if (units === undefined || units === 'millisecond' || !this.isValid()) {
57936 return this;
57937 }
57938
57939 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
57940
57941 switch (units) {
57942 case 'year':
57943 time = startOfDate(this.year() + 1, 0, 1) - 1;
57944 break;
57945
57946 case 'quarter':
57947 time = startOfDate(this.year(), this.month() - this.month() % 3 + 3, 1) - 1;
57948 break;
57949
57950 case 'month':
57951 time = startOfDate(this.year(), this.month() + 1, 1) - 1;
57952 break;
57953
57954 case 'week':
57955 time = startOfDate(this.year(), this.month(), this.date() - this.weekday() + 7) - 1;
57956 break;
57957
57958 case 'isoWeek':
57959 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1) + 7) - 1;
57960 break;
57961
57962 case 'day':
57963 case 'date':
57964 time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
57965 break;
57966
57967 case 'hour':
57968 time = this._d.valueOf();
57969 time += MS_PER_HOUR - mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR) - 1;
57970 break;
57971
57972 case 'minute':
57973 time = this._d.valueOf();
57974 time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
57975 break;
57976
57977 case 'second':
57978 time = this._d.valueOf();
57979 time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
57980 break;
57981 }
57982
57983 this._d.setTime(time);
57984
57985 hooks.updateOffset(this, true);
57986 return this;
57987 }
57988
57989 function valueOf() {
57990 return this._d.valueOf() - (this._offset || 0) * 60000;
57991 }
57992
57993 function unix() {
57994 return Math.floor(this.valueOf() / 1000);
57995 }
57996
57997 function toDate() {
57998 return new Date(this.valueOf());
57999 }
58000
58001 function toArray() {
58002 var m = this;
58003 return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
58004 }
58005
58006 function toObject() {
58007 var m = this;
58008 return {
58009 years: m.year(),
58010 months: m.month(),
58011 date: m.date(),
58012 hours: m.hours(),
58013 minutes: m.minutes(),
58014 seconds: m.seconds(),
58015 milliseconds: m.milliseconds()
58016 };
58017 }
58018
58019 function toJSON() {
58020 // new Date(NaN).toJSON() === null
58021 return this.isValid() ? this.toISOString() : null;
58022 }
58023
58024 function isValid$2() {
58025 return isValid(this);
58026 }
58027
58028 function parsingFlags() {
58029 return extend({}, getParsingFlags(this));
58030 }
58031
58032 function invalidAt() {
58033 return getParsingFlags(this).overflow;
58034 }
58035
58036 function creationData() {
58037 return {
58038 input: this._i,
58039 format: this._f,
58040 locale: this._locale,
58041 isUTC: this._isUTC,
58042 strict: this._strict
58043 };
58044 } // FORMATTING
58045
58046
58047 addFormatToken(0, ['gg', 2], 0, function () {
58048 return this.weekYear() % 100;
58049 });
58050 addFormatToken(0, ['GG', 2], 0, function () {
58051 return this.isoWeekYear() % 100;
58052 });
58053
58054 function addWeekYearFormatToken(token, getter) {
58055 addFormatToken(0, [token, token.length], 0, getter);
58056 }
58057
58058 addWeekYearFormatToken('gggg', 'weekYear');
58059 addWeekYearFormatToken('ggggg', 'weekYear');
58060 addWeekYearFormatToken('GGGG', 'isoWeekYear');
58061 addWeekYearFormatToken('GGGGG', 'isoWeekYear'); // ALIASES
58062
58063 addUnitAlias('weekYear', 'gg');
58064 addUnitAlias('isoWeekYear', 'GG'); // PRIORITY
58065
58066 addUnitPriority('weekYear', 1);
58067 addUnitPriority('isoWeekYear', 1); // PARSING
58068
58069 addRegexToken('G', matchSigned);
58070 addRegexToken('g', matchSigned);
58071 addRegexToken('GG', match1to2, match2);
58072 addRegexToken('gg', match1to2, match2);
58073 addRegexToken('GGGG', match1to4, match4);
58074 addRegexToken('gggg', match1to4, match4);
58075 addRegexToken('GGGGG', match1to6, match6);
58076 addRegexToken('ggggg', match1to6, match6);
58077 addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
58078 week[token.substr(0, 2)] = toInt(input);
58079 });
58080 addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
58081 week[token] = hooks.parseTwoDigitYear(input);
58082 }); // MOMENTS
58083
58084 function getSetWeekYear(input) {
58085 return getSetWeekYearHelper.call(this, input, this.week(), this.weekday(), this.localeData()._week.dow, this.localeData()._week.doy);
58086 }
58087
58088 function getSetISOWeekYear(input) {
58089 return getSetWeekYearHelper.call(this, input, this.isoWeek(), this.isoWeekday(), 1, 4);
58090 }
58091
58092 function getISOWeeksInYear() {
58093 return weeksInYear(this.year(), 1, 4);
58094 }
58095
58096 function getWeeksInYear() {
58097 var weekInfo = this.localeData()._week;
58098
58099 return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
58100 }
58101
58102 function getSetWeekYearHelper(input, week, weekday, dow, doy) {
58103 var weeksTarget;
58104
58105 if (input == null) {
58106 return weekOfYear(this, dow, doy).year;
58107 } else {
58108 weeksTarget = weeksInYear(input, dow, doy);
58109
58110 if (week > weeksTarget) {
58111 week = weeksTarget;
58112 }
58113
58114 return setWeekAll.call(this, input, week, weekday, dow, doy);
58115 }
58116 }
58117
58118 function setWeekAll(weekYear, week, weekday, dow, doy) {
58119 var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
58120 date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
58121 this.year(date.getUTCFullYear());
58122 this.month(date.getUTCMonth());
58123 this.date(date.getUTCDate());
58124 return this;
58125 } // FORMATTING
58126
58127
58128 addFormatToken('Q', 0, 'Qo', 'quarter'); // ALIASES
58129
58130 addUnitAlias('quarter', 'Q'); // PRIORITY
58131
58132 addUnitPriority('quarter', 7); // PARSING
58133
58134 addRegexToken('Q', match1);
58135 addParseToken('Q', function (input, array) {
58136 array[MONTH] = (toInt(input) - 1) * 3;
58137 }); // MOMENTS
58138
58139 function getSetQuarter(input) {
58140 return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
58141 } // FORMATTING
58142
58143
58144 addFormatToken('D', ['DD', 2], 'Do', 'date'); // ALIASES
58145
58146 addUnitAlias('date', 'D'); // PRIORITY
58147
58148 addUnitPriority('date', 9); // PARSING
58149
58150 addRegexToken('D', match1to2);
58151 addRegexToken('DD', match1to2, match2);
58152 addRegexToken('Do', function (isStrict, locale) {
58153 // TODO: Remove "ordinalParse" fallback in next major release.
58154 return isStrict ? locale._dayOfMonthOrdinalParse || locale._ordinalParse : locale._dayOfMonthOrdinalParseLenient;
58155 });
58156 addParseToken(['D', 'DD'], DATE);
58157 addParseToken('Do', function (input, array) {
58158 array[DATE] = toInt(input.match(match1to2)[0]);
58159 }); // MOMENTS
58160
58161 var getSetDayOfMonth = makeGetSet('Date', true); // FORMATTING
58162
58163 addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); // ALIASES
58164
58165 addUnitAlias('dayOfYear', 'DDD'); // PRIORITY
58166
58167 addUnitPriority('dayOfYear', 4); // PARSING
58168
58169 addRegexToken('DDD', match1to3);
58170 addRegexToken('DDDD', match3);
58171 addParseToken(['DDD', 'DDDD'], function (input, array, config) {
58172 config._dayOfYear = toInt(input);
58173 }); // HELPERS
58174 // MOMENTS
58175
58176 function getSetDayOfYear(input) {
58177 var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
58178 return input == null ? dayOfYear : this.add(input - dayOfYear, 'd');
58179 } // FORMATTING
58180
58181
58182 addFormatToken('m', ['mm', 2], 0, 'minute'); // ALIASES
58183
58184 addUnitAlias('minute', 'm'); // PRIORITY
58185
58186 addUnitPriority('minute', 14); // PARSING
58187
58188 addRegexToken('m', match1to2);
58189 addRegexToken('mm', match1to2, match2);
58190 addParseToken(['m', 'mm'], MINUTE); // MOMENTS
58191
58192 var getSetMinute = makeGetSet('Minutes', false); // FORMATTING
58193
58194 addFormatToken('s', ['ss', 2], 0, 'second'); // ALIASES
58195
58196 addUnitAlias('second', 's'); // PRIORITY
58197
58198 addUnitPriority('second', 15); // PARSING
58199
58200 addRegexToken('s', match1to2);
58201 addRegexToken('ss', match1to2, match2);
58202 addParseToken(['s', 'ss'], SECOND); // MOMENTS
58203
58204 var getSetSecond = makeGetSet('Seconds', false); // FORMATTING
58205
58206 addFormatToken('S', 0, 0, function () {
58207 return ~~(this.millisecond() / 100);
58208 });
58209 addFormatToken(0, ['SS', 2], 0, function () {
58210 return ~~(this.millisecond() / 10);
58211 });
58212 addFormatToken(0, ['SSS', 3], 0, 'millisecond');
58213 addFormatToken(0, ['SSSS', 4], 0, function () {
58214 return this.millisecond() * 10;
58215 });
58216 addFormatToken(0, ['SSSSS', 5], 0, function () {
58217 return this.millisecond() * 100;
58218 });
58219 addFormatToken(0, ['SSSSSS', 6], 0, function () {
58220 return this.millisecond() * 1000;
58221 });
58222 addFormatToken(0, ['SSSSSSS', 7], 0, function () {
58223 return this.millisecond() * 10000;
58224 });
58225 addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
58226 return this.millisecond() * 100000;
58227 });
58228 addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
58229 return this.millisecond() * 1000000;
58230 }); // ALIASES
58231
58232 addUnitAlias('millisecond', 'ms'); // PRIORITY
58233
58234 addUnitPriority('millisecond', 16); // PARSING
58235
58236 addRegexToken('S', match1to3, match1);
58237 addRegexToken('SS', match1to3, match2);
58238 addRegexToken('SSS', match1to3, match3);
58239 var token;
58240
58241 for (token = 'SSSS'; token.length <= 9; token += 'S') {
58242 addRegexToken(token, matchUnsigned);
58243 }
58244
58245 function parseMs(input, array) {
58246 array[MILLISECOND] = toInt(('0.' + input) * 1000);
58247 }
58248
58249 for (token = 'S'; token.length <= 9; token += 'S') {
58250 addParseToken(token, parseMs);
58251 } // MOMENTS
58252
58253
58254 var getSetMillisecond = makeGetSet('Milliseconds', false); // FORMATTING
58255
58256 addFormatToken('z', 0, 0, 'zoneAbbr');
58257 addFormatToken('zz', 0, 0, 'zoneName'); // MOMENTS
58258
58259 function getZoneAbbr() {
58260 return this._isUTC ? 'UTC' : '';
58261 }
58262
58263 function getZoneName() {
58264 return this._isUTC ? 'Coordinated Universal Time' : '';
58265 }
58266
58267 var proto = Moment.prototype;
58268 proto.add = add;
58269 proto.calendar = calendar$1;
58270 proto.clone = clone;
58271 proto.diff = diff;
58272 proto.endOf = endOf;
58273 proto.format = format;
58274 proto.from = from;
58275 proto.fromNow = fromNow;
58276 proto.to = to;
58277 proto.toNow = toNow;
58278 proto.get = stringGet;
58279 proto.invalidAt = invalidAt;
58280 proto.isAfter = isAfter;
58281 proto.isBefore = isBefore;
58282 proto.isBetween = isBetween;
58283 proto.isSame = isSame;
58284 proto.isSameOrAfter = isSameOrAfter;
58285 proto.isSameOrBefore = isSameOrBefore;
58286 proto.isValid = isValid$2;
58287 proto.lang = lang;
58288 proto.locale = locale;
58289 proto.localeData = localeData;
58290 proto.max = prototypeMax;
58291 proto.min = prototypeMin;
58292 proto.parsingFlags = parsingFlags;
58293 proto.set = stringSet;
58294 proto.startOf = startOf;
58295 proto.subtract = subtract;
58296 proto.toArray = toArray;
58297 proto.toObject = toObject;
58298 proto.toDate = toDate;
58299 proto.toISOString = toISOString;
58300 proto.inspect = inspect;
58301 proto.toJSON = toJSON;
58302 proto.toString = toString;
58303 proto.unix = unix;
58304 proto.valueOf = valueOf;
58305 proto.creationData = creationData;
58306 proto.year = getSetYear;
58307 proto.isLeapYear = getIsLeapYear;
58308 proto.weekYear = getSetWeekYear;
58309 proto.isoWeekYear = getSetISOWeekYear;
58310 proto.quarter = proto.quarters = getSetQuarter;
58311 proto.month = getSetMonth;
58312 proto.daysInMonth = getDaysInMonth;
58313 proto.week = proto.weeks = getSetWeek;
58314 proto.isoWeek = proto.isoWeeks = getSetISOWeek;
58315 proto.weeksInYear = getWeeksInYear;
58316 proto.isoWeeksInYear = getISOWeeksInYear;
58317 proto.date = getSetDayOfMonth;
58318 proto.day = proto.days = getSetDayOfWeek;
58319 proto.weekday = getSetLocaleDayOfWeek;
58320 proto.isoWeekday = getSetISODayOfWeek;
58321 proto.dayOfYear = getSetDayOfYear;
58322 proto.hour = proto.hours = getSetHour;
58323 proto.minute = proto.minutes = getSetMinute;
58324 proto.second = proto.seconds = getSetSecond;
58325 proto.millisecond = proto.milliseconds = getSetMillisecond;
58326 proto.utcOffset = getSetOffset;
58327 proto.utc = setOffsetToUTC;
58328 proto.local = setOffsetToLocal;
58329 proto.parseZone = setOffsetToParsedOffset;
58330 proto.hasAlignedHourOffset = hasAlignedHourOffset;
58331 proto.isDST = isDaylightSavingTime;
58332 proto.isLocal = isLocal;
58333 proto.isUtcOffset = isUtcOffset;
58334 proto.isUtc = isUtc;
58335 proto.isUTC = isUtc;
58336 proto.zoneAbbr = getZoneAbbr;
58337 proto.zoneName = getZoneName;
58338 proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
58339 proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
58340 proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
58341 proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
58342 proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
58343
58344 function createUnix(input) {
58345 return createLocal(input * 1000);
58346 }
58347
58348 function createInZone() {
58349 return createLocal.apply(null, arguments).parseZone();
58350 }
58351
58352 function preParsePostFormat(string) {
58353 return string;
58354 }
58355
58356 var proto$1 = Locale.prototype;
58357 proto$1.calendar = calendar;
58358 proto$1.longDateFormat = longDateFormat;
58359 proto$1.invalidDate = invalidDate;
58360 proto$1.ordinal = ordinal;
58361 proto$1.preparse = preParsePostFormat;
58362 proto$1.postformat = preParsePostFormat;
58363 proto$1.relativeTime = relativeTime;
58364 proto$1.pastFuture = pastFuture;
58365 proto$1.set = set;
58366 proto$1.months = localeMonths;
58367 proto$1.monthsShort = localeMonthsShort;
58368 proto$1.monthsParse = localeMonthsParse;
58369 proto$1.monthsRegex = monthsRegex;
58370 proto$1.monthsShortRegex = monthsShortRegex;
58371 proto$1.week = localeWeek;
58372 proto$1.firstDayOfYear = localeFirstDayOfYear;
58373 proto$1.firstDayOfWeek = localeFirstDayOfWeek;
58374 proto$1.weekdays = localeWeekdays;
58375 proto$1.weekdaysMin = localeWeekdaysMin;
58376 proto$1.weekdaysShort = localeWeekdaysShort;
58377 proto$1.weekdaysParse = localeWeekdaysParse;
58378 proto$1.weekdaysRegex = weekdaysRegex;
58379 proto$1.weekdaysShortRegex = weekdaysShortRegex;
58380 proto$1.weekdaysMinRegex = weekdaysMinRegex;
58381 proto$1.isPM = localeIsPM;
58382 proto$1.meridiem = localeMeridiem;
58383
58384 function get$1(format, index, field, setter) {
58385 var locale = getLocale();
58386 var utc = createUTC().set(setter, index);
58387 return locale[field](utc, format);
58388 }
58389
58390 function listMonthsImpl(format, index, field) {
58391 if (isNumber(format)) {
58392 index = format;
58393 format = undefined;
58394 }
58395
58396 format = format || '';
58397
58398 if (index != null) {
58399 return get$1(format, index, field, 'month');
58400 }
58401
58402 var i;
58403 var out = [];
58404
58405 for (i = 0; i < 12; i++) {
58406 out[i] = get$1(format, i, field, 'month');
58407 }
58408
58409 return out;
58410 } // ()
58411 // (5)
58412 // (fmt, 5)
58413 // (fmt)
58414 // (true)
58415 // (true, 5)
58416 // (true, fmt, 5)
58417 // (true, fmt)
58418
58419
58420 function listWeekdaysImpl(localeSorted, format, index, field) {
58421 if (typeof localeSorted === 'boolean') {
58422 if (isNumber(format)) {
58423 index = format;
58424 format = undefined;
58425 }
58426
58427 format = format || '';
58428 } else {
58429 format = localeSorted;
58430 index = format;
58431 localeSorted = false;
58432
58433 if (isNumber(format)) {
58434 index = format;
58435 format = undefined;
58436 }
58437
58438 format = format || '';
58439 }
58440
58441 var locale = getLocale(),
58442 shift = localeSorted ? locale._week.dow : 0;
58443
58444 if (index != null) {
58445 return get$1(format, (index + shift) % 7, field, 'day');
58446 }
58447
58448 var i;
58449 var out = [];
58450
58451 for (i = 0; i < 7; i++) {
58452 out[i] = get$1(format, (i + shift) % 7, field, 'day');
58453 }
58454
58455 return out;
58456 }
58457
58458 function listMonths(format, index) {
58459 return listMonthsImpl(format, index, 'months');
58460 }
58461
58462 function listMonthsShort(format, index) {
58463 return listMonthsImpl(format, index, 'monthsShort');
58464 }
58465
58466 function listWeekdays(localeSorted, format, index) {
58467 return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
58468 }
58469
58470 function listWeekdaysShort(localeSorted, format, index) {
58471 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
58472 }
58473
58474 function listWeekdaysMin(localeSorted, format, index) {
58475 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
58476 }
58477
58478 getSetGlobalLocale('en', {
58479 dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
58480 ordinal: function (number) {
58481 var b = number % 10,
58482 output = toInt(number % 100 / 10) === 1 ? 'th' : b === 1 ? 'st' : b === 2 ? 'nd' : b === 3 ? 'rd' : 'th';
58483 return number + output;
58484 }
58485 }); // Side effect imports
58486
58487 hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
58488 hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
58489 var mathAbs = Math.abs;
58490
58491 function abs() {
58492 var data = this._data;
58493 this._milliseconds = mathAbs(this._milliseconds);
58494 this._days = mathAbs(this._days);
58495 this._months = mathAbs(this._months);
58496 data.milliseconds = mathAbs(data.milliseconds);
58497 data.seconds = mathAbs(data.seconds);
58498 data.minutes = mathAbs(data.minutes);
58499 data.hours = mathAbs(data.hours);
58500 data.months = mathAbs(data.months);
58501 data.years = mathAbs(data.years);
58502 return this;
58503 }
58504
58505 function addSubtract$1(duration, input, value, direction) {
58506 var other = createDuration(input, value);
58507 duration._milliseconds += direction * other._milliseconds;
58508 duration._days += direction * other._days;
58509 duration._months += direction * other._months;
58510 return duration._bubble();
58511 } // supports only 2.0-style add(1, 's') or add(duration)
58512
58513
58514 function add$1(input, value) {
58515 return addSubtract$1(this, input, value, 1);
58516 } // supports only 2.0-style subtract(1, 's') or subtract(duration)
58517
58518
58519 function subtract$1(input, value) {
58520 return addSubtract$1(this, input, value, -1);
58521 }
58522
58523 function absCeil(number) {
58524 if (number < 0) {
58525 return Math.floor(number);
58526 } else {
58527 return Math.ceil(number);
58528 }
58529 }
58530
58531 function bubble() {
58532 var milliseconds = this._milliseconds;
58533 var days = this._days;
58534 var months = this._months;
58535 var data = this._data;
58536 var seconds, minutes, hours, years, monthsFromDays; // if we have a mix of positive and negative values, bubble down first
58537 // check: https://github.com/moment/moment/issues/2166
58538
58539 if (!(milliseconds >= 0 && days >= 0 && months >= 0 || milliseconds <= 0 && days <= 0 && months <= 0)) {
58540 milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
58541 days = 0;
58542 months = 0;
58543 } // The following code bubbles up values, see the tests for
58544 // examples of what that means.
58545
58546
58547 data.milliseconds = milliseconds % 1000;
58548 seconds = absFloor(milliseconds / 1000);
58549 data.seconds = seconds % 60;
58550 minutes = absFloor(seconds / 60);
58551 data.minutes = minutes % 60;
58552 hours = absFloor(minutes / 60);
58553 data.hours = hours % 24;
58554 days += absFloor(hours / 24); // convert days to months
58555
58556 monthsFromDays = absFloor(daysToMonths(days));
58557 months += monthsFromDays;
58558 days -= absCeil(monthsToDays(monthsFromDays)); // 12 months -> 1 year
58559
58560 years = absFloor(months / 12);
58561 months %= 12;
58562 data.days = days;
58563 data.months = months;
58564 data.years = years;
58565 return this;
58566 }
58567
58568 function daysToMonths(days) {
58569 // 400 years have 146097 days (taking into account leap year rules)
58570 // 400 years have 12 months === 4800
58571 return days * 4800 / 146097;
58572 }
58573
58574 function monthsToDays(months) {
58575 // the reverse of daysToMonths
58576 return months * 146097 / 4800;
58577 }
58578
58579 function as(units) {
58580 if (!this.isValid()) {
58581 return NaN;
58582 }
58583
58584 var days;
58585 var months;
58586 var milliseconds = this._milliseconds;
58587 units = normalizeUnits(units);
58588
58589 if (units === 'month' || units === 'quarter' || units === 'year') {
58590 days = this._days + milliseconds / 864e5;
58591 months = this._months + daysToMonths(days);
58592
58593 switch (units) {
58594 case 'month':
58595 return months;
58596
58597 case 'quarter':
58598 return months / 3;
58599
58600 case 'year':
58601 return months / 12;
58602 }
58603 } else {
58604 // handle milliseconds separately because of floating point math errors (issue #1867)
58605 days = this._days + Math.round(monthsToDays(this._months));
58606
58607 switch (units) {
58608 case 'week':
58609 return days / 7 + milliseconds / 6048e5;
58610
58611 case 'day':
58612 return days + milliseconds / 864e5;
58613
58614 case 'hour':
58615 return days * 24 + milliseconds / 36e5;
58616
58617 case 'minute':
58618 return days * 1440 + milliseconds / 6e4;
58619
58620 case 'second':
58621 return days * 86400 + milliseconds / 1000;
58622 // Math.floor prevents floating point math errors here
58623
58624 case 'millisecond':
58625 return Math.floor(days * 864e5) + milliseconds;
58626
58627 default:
58628 throw new Error('Unknown unit ' + units);
58629 }
58630 }
58631 } // TODO: Use this.as('ms')?
58632
58633
58634 function valueOf$1() {
58635 if (!this.isValid()) {
58636 return NaN;
58637 }
58638
58639 return this._milliseconds + this._days * 864e5 + this._months % 12 * 2592e6 + toInt(this._months / 12) * 31536e6;
58640 }
58641
58642 function makeAs(alias) {
58643 return function () {
58644 return this.as(alias);
58645 };
58646 }
58647
58648 var asMilliseconds = makeAs('ms');
58649 var asSeconds = makeAs('s');
58650 var asMinutes = makeAs('m');
58651 var asHours = makeAs('h');
58652 var asDays = makeAs('d');
58653 var asWeeks = makeAs('w');
58654 var asMonths = makeAs('M');
58655 var asQuarters = makeAs('Q');
58656 var asYears = makeAs('y');
58657
58658 function clone$1() {
58659 return createDuration(this);
58660 }
58661
58662 function get$2(units) {
58663 units = normalizeUnits(units);
58664 return this.isValid() ? this[units + 's']() : NaN;
58665 }
58666
58667 function makeGetter(name) {
58668 return function () {
58669 return this.isValid() ? this._data[name] : NaN;
58670 };
58671 }
58672
58673 var milliseconds = makeGetter('milliseconds');
58674 var seconds = makeGetter('seconds');
58675 var minutes = makeGetter('minutes');
58676 var hours = makeGetter('hours');
58677 var days = makeGetter('days');
58678 var months = makeGetter('months');
58679 var years = makeGetter('years');
58680
58681 function weeks() {
58682 return absFloor(this.days() / 7);
58683 }
58684
58685 var round = Math.round;
58686 var thresholds = {
58687 ss: 44,
58688 // a few seconds to seconds
58689 s: 45,
58690 // seconds to minute
58691 m: 45,
58692 // minutes to hour
58693 h: 22,
58694 // hours to day
58695 d: 26,
58696 // days to month
58697 M: 11 // months to year
58698
58699 }; // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
58700
58701 function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
58702 return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
58703 }
58704
58705 function relativeTime$1(posNegDuration, withoutSuffix, locale) {
58706 var duration = createDuration(posNegDuration).abs();
58707 var seconds = round(duration.as('s'));
58708 var minutes = round(duration.as('m'));
58709 var hours = round(duration.as('h'));
58710 var days = round(duration.as('d'));
58711 var months = round(duration.as('M'));
58712 var years = round(duration.as('y'));
58713 var a = seconds <= thresholds.ss && ['s', seconds] || seconds < thresholds.s && ['ss', seconds] || minutes <= 1 && ['m'] || minutes < thresholds.m && ['mm', minutes] || hours <= 1 && ['h'] || hours < thresholds.h && ['hh', hours] || days <= 1 && ['d'] || days < thresholds.d && ['dd', days] || months <= 1 && ['M'] || months < thresholds.M && ['MM', months] || years <= 1 && ['y'] || ['yy', years];
58714 a[2] = withoutSuffix;
58715 a[3] = +posNegDuration > 0;
58716 a[4] = locale;
58717 return substituteTimeAgo.apply(null, a);
58718 } // This function allows you to set the rounding function for relative time strings
58719
58720
58721 function getSetRelativeTimeRounding(roundingFunction) {
58722 if (roundingFunction === undefined) {
58723 return round;
58724 }
58725
58726 if (typeof roundingFunction === 'function') {
58727 round = roundingFunction;
58728 return true;
58729 }
58730
58731 return false;
58732 } // This function allows you to set a threshold for relative time strings
58733
58734
58735 function getSetRelativeTimeThreshold(threshold, limit) {
58736 if (thresholds[threshold] === undefined) {
58737 return false;
58738 }
58739
58740 if (limit === undefined) {
58741 return thresholds[threshold];
58742 }
58743
58744 thresholds[threshold] = limit;
58745
58746 if (threshold === 's') {
58747 thresholds.ss = limit - 1;
58748 }
58749
58750 return true;
58751 }
58752
58753 function humanize(withSuffix) {
58754 if (!this.isValid()) {
58755 return this.localeData().invalidDate();
58756 }
58757
58758 var locale = this.localeData();
58759 var output = relativeTime$1(this, !withSuffix, locale);
58760
58761 if (withSuffix) {
58762 output = locale.pastFuture(+this, output);
58763 }
58764
58765 return locale.postformat(output);
58766 }
58767
58768 var abs$1 = Math.abs;
58769
58770 function sign(x) {
58771 return (x > 0) - (x < 0) || +x;
58772 }
58773
58774 function toISOString$1() {
58775 // for ISO strings we do not use the normal bubbling rules:
58776 // * milliseconds bubble up until they become hours
58777 // * days do not bubble at all
58778 // * months bubble up until they become years
58779 // This is because there is no context-free conversion between hours and days
58780 // (think of clock changes)
58781 // and also not between days and months (28-31 days per month)
58782 if (!this.isValid()) {
58783 return this.localeData().invalidDate();
58784 }
58785
58786 var seconds = abs$1(this._milliseconds) / 1000;
58787 var days = abs$1(this._days);
58788 var months = abs$1(this._months);
58789 var minutes, hours, years; // 3600 seconds -> 60 minutes -> 1 hour
58790
58791 minutes = absFloor(seconds / 60);
58792 hours = absFloor(minutes / 60);
58793 seconds %= 60;
58794 minutes %= 60; // 12 months -> 1 year
58795
58796 years = absFloor(months / 12);
58797 months %= 12; // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
58798
58799 var Y = years;
58800 var M = months;
58801 var D = days;
58802 var h = hours;
58803 var m = minutes;
58804 var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
58805 var total = this.asSeconds();
58806
58807 if (!total) {
58808 // this is the same as C#'s (Noda) and python (isodate)...
58809 // but not other JS (goog.date)
58810 return 'P0D';
58811 }
58812
58813 var totalSign = total < 0 ? '-' : '';
58814 var ymSign = sign(this._months) !== sign(total) ? '-' : '';
58815 var daysSign = sign(this._days) !== sign(total) ? '-' : '';
58816 var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
58817 return totalSign + 'P' + (Y ? ymSign + Y + 'Y' : '') + (M ? ymSign + M + 'M' : '') + (D ? daysSign + D + 'D' : '') + (h || m || s ? 'T' : '') + (h ? hmsSign + h + 'H' : '') + (m ? hmsSign + m + 'M' : '') + (s ? hmsSign + s + 'S' : '');
58818 }
58819
58820 var proto$2 = Duration.prototype;
58821 proto$2.isValid = isValid$1;
58822 proto$2.abs = abs;
58823 proto$2.add = add$1;
58824 proto$2.subtract = subtract$1;
58825 proto$2.as = as;
58826 proto$2.asMilliseconds = asMilliseconds;
58827 proto$2.asSeconds = asSeconds;
58828 proto$2.asMinutes = asMinutes;
58829 proto$2.asHours = asHours;
58830 proto$2.asDays = asDays;
58831 proto$2.asWeeks = asWeeks;
58832 proto$2.asMonths = asMonths;
58833 proto$2.asQuarters = asQuarters;
58834 proto$2.asYears = asYears;
58835 proto$2.valueOf = valueOf$1;
58836 proto$2._bubble = bubble;
58837 proto$2.clone = clone$1;
58838 proto$2.get = get$2;
58839 proto$2.milliseconds = milliseconds;
58840 proto$2.seconds = seconds;
58841 proto$2.minutes = minutes;
58842 proto$2.hours = hours;
58843 proto$2.days = days;
58844 proto$2.weeks = weeks;
58845 proto$2.months = months;
58846 proto$2.years = years;
58847 proto$2.humanize = humanize;
58848 proto$2.toISOString = toISOString$1;
58849 proto$2.toString = toISOString$1;
58850 proto$2.toJSON = toISOString$1;
58851 proto$2.locale = locale;
58852 proto$2.localeData = localeData;
58853 proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
58854 proto$2.lang = lang; // Side effect imports
58855 // FORMATTING
58856
58857 addFormatToken('X', 0, 0, 'unix');
58858 addFormatToken('x', 0, 0, 'valueOf'); // PARSING
58859
58860 addRegexToken('x', matchSigned);
58861 addRegexToken('X', matchTimestamp);
58862 addParseToken('X', function (input, array, config) {
58863 config._d = new Date(parseFloat(input, 10) * 1000);
58864 });
58865 addParseToken('x', function (input, array, config) {
58866 config._d = new Date(toInt(input));
58867 }); // Side effect imports
58868
58869 hooks.version = '2.24.0';
58870 setHookCallback(createLocal);
58871 hooks.fn = proto;
58872 hooks.min = min;
58873 hooks.max = max;
58874 hooks.now = now;
58875 hooks.utc = createUTC;
58876 hooks.unix = createUnix;
58877 hooks.months = listMonths;
58878 hooks.isDate = isDate;
58879 hooks.locale = getSetGlobalLocale;
58880 hooks.invalid = createInvalid;
58881 hooks.duration = createDuration;
58882 hooks.isMoment = isMoment;
58883 hooks.weekdays = listWeekdays;
58884 hooks.parseZone = createInZone;
58885 hooks.localeData = getLocale;
58886 hooks.isDuration = isDuration;
58887 hooks.monthsShort = listMonthsShort;
58888 hooks.weekdaysMin = listWeekdaysMin;
58889 hooks.defineLocale = defineLocale;
58890 hooks.updateLocale = updateLocale;
58891 hooks.locales = listLocales;
58892 hooks.weekdaysShort = listWeekdaysShort;
58893 hooks.normalizeUnits = normalizeUnits;
58894 hooks.relativeTimeRounding = getSetRelativeTimeRounding;
58895 hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
58896 hooks.calendarFormat = getCalendarFormat;
58897 hooks.prototype = proto; // currently HTML5 input type only supports 24-hour formats
58898
58899 hooks.HTML5_FMT = {
58900 DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',
58901 // <input type="datetime-local" />
58902 DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',
58903 // <input type="datetime-local" step="1" />
58904 DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',
58905 // <input type="datetime-local" step="0.001" />
58906 DATE: 'YYYY-MM-DD',
58907 // <input type="date" />
58908 TIME: 'HH:mm',
58909 // <input type="time" />
58910 TIME_SECONDS: 'HH:mm:ss',
58911 // <input type="time" step="1" />
58912 TIME_MS: 'HH:mm:ss.SSS',
58913 // <input type="time" step="0.001" />
58914 WEEK: 'GGGG-[W]WW',
58915 // <input type="week" />
58916 MONTH: 'YYYY-MM' // <input type="month" />
58917
58918 };
58919 return hooks;
58920 });
58921 });
58922
58923 // use this instance. Else, load via commonjs.
58924
58925 var moment$3 = typeof window !== 'undefined' && window['moment'] || moment$2;
58926
58927 var moment$4 = /*#__PURE__*/Object.freeze({
58928 __proto__: null,
58929 'default': moment$3,
58930 __moduleExports: moment$3
58931 });
58932
58933 var network = {
58934 Images: Images,
58935 dotparser: dotparser$1,
58936 gephiParser: gephiParser,
58937 allOptions: allOptions$2,
58938 convertDot: DOTToGraph_1,
58939 convertGephi: parseGephi
58940 }; // utils
58941
58942 var indexLegacy = /*#__PURE__*/Object.freeze({
58943 __proto__: null,
58944 network: network,
58945 DOMutil: DOMutil$1,
58946 util: esm,
58947 data: esm$1,
58948 moment: moment$4,
58949 Hammer: hammer$1,
58950 keycharm: keycharm$1,
58951 DataSet: DataSet,
58952 DataView: DataView$2,
58953 Queue: Queue,
58954 Network: Network
58955 });
58956
58957 exports.DOMutil = DOMutil$1;
58958 exports.DataSet = DataSet;
58959 exports.DataView = DataView$2;
58960 exports.Hammer = hammer$1;
58961 exports.Network = Network;
58962 exports.Queue = Queue;
58963 exports.data = esm$1;
58964 exports.default = indexLegacy;
58965 exports.keycharm = keycharm$1;
58966 exports.moment = moment$4;
58967 exports.network = network;
58968 exports.util = esm;
58969
58970 Object.defineProperty(exports, '__esModule', { value: true });
58971
58972})));
58973//# sourceMappingURL=vis-network.js.map